1

I am trying to figure out the best method for accessing nested json data in d3.

So my data looks something like this:

{
    "Florida":{"New York": "yellow",
                "New Jersey": "blue",
                "Pennsylvania": "green",
etc..

And my d3.select function looks something like:

    .selectAll("path")
.style('fill', function(d){
                                    return jsondata.state[d.properties.NAME];

of course, var state here is a variable, which should be referring to "Florida", but doesn't.

The way I see it, there are two ways:

  1. Use some of the parsing methods outlined in this post. Namely, the .get() method

  2. Use d3.nest() in some capacity and rolling up my data into an accessible object ahead of the .style function.

What is the best method?

Community
  • 1
  • 1
Union find
  • 7,759
  • 13
  • 60
  • 111
  • 1
    It's unclear to me what you're trying to do. How are you passing that data to D3, and what does it determine? – Lars Kotthoff Jul 22 '14 at 16:49
  • @LarsKotthoff This is for a chloropleth. So this data is being passed to pattern match against the ID of the geodata.The selectAll is referencing an object with data already populated from another function. Now we're accessing this separate dataset to match id's and find colors. – Union find Jul 22 '14 at 16:49
  • 1
    Ok, and why is the data nested? Wouldn't a simple mapping from sate to colour be enough? – Lars Kotthoff Jul 22 '14 at 16:55
  • @LarsKotthoff If only I could do that. This map will show different chloropleths depending on an external selector. So I need a way to access different datasets dependent on the selected state (e.g., Florida). – Union find Jul 22 '14 at 16:56
  • @LarsKotthoff It occurs to me that it's possible to de-nest the array by creating a lot more objects. For example, this dataset: http://www.datagraaf.nl/lib/D3/global_malaria.json used for this map: http://www.datagraaf.nl/lib/D3/malariapleth.html It's less semantic, though. – Union find Jul 22 '14 at 17:18
  • 1
    See my answer below, but by the way... if `state` is a variable you should use bracket notation. `jsondata[state][d.properties.NAME]` – jshanley Jul 22 '14 at 17:30
  • @jshanley As I say, state is a variable. Your notation saved me from having to write an unholy amount of code. Thank you! – Union find Jul 22 '14 at 18:19

1 Answers1

1

You can use an ordinal scale, and change its domain and range based on whatever state is selected, and its data.

Create a scale without a domain or range:

var color = d3.scale.ordinal();

Then when a state is selected, get its name, and get the d3.entries for its corresponding object:

var entries = d3.entries(yourData[selectedState]);

Then set the domain and range of the scale to be the keys and values respectively:

color.domain(entries.map(function(d) {return d.key;}));
color.range(entries.map(function(d) {return d.value;}));

Finally, select all of your state paths and use the scale to set the fill:

.selectAll('path').attr('fill', function(d) {return color(d.properties.NAME)})
jshanley
  • 9,048
  • 2
  • 37
  • 44
  • I'm a bit confused by this. How do domain/range compute the values for a chloropleth fill? Bostock uses, which varies i: var quantize = d3.scale.quantize() .domain([0, .15]) .range(d3.range(9).map(function(i) { return "q" + i + "-9"; })); – Union find Jul 22 '14 at 18:53
  • 1
    The scale in Bostock's example is used to set the class of an element, and then colors are applied using css selectors for those classes. The scale in my example above is a mapping of state names to color names. `color.domain` is an array of state names like `['New York','California','Texas',...]` and `color.range` is an array of color names like `['red','green','blue', ...]`. When `color()` is called and passed a state name as its argument, it returns the color associated with that state by matching the index of the state name in the domain to the index of the color name in the range. – jshanley Jul 22 '14 at 21:08
  • 1
    For instance, `color('Texas')` would return `'blue'` therefore, when you set `.attr('fill', function(d) {return color(d.properties.NAME);})` you are setting the `fill` attribute to be the color that is associated with the name of the state that is passed in as `d.properties.NAME` – jshanley Jul 22 '14 at 21:11