简体   繁体   中英

Line with nested json attributes

I have a problem accessing attributes in a json file to generate a line graph. The json is structured like this:

    [{
    "id" : "AustraliaNewZealand" ,
    "year" : [1990,1992,1994,1993,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010],
    "values":[477790,485825,487296,488885,502585,511718,526594,538967,550556,563572,577171,579126,591635,599216,604267,608954,615853,623685,618961,614920]
}, 
{
    "id":"CentralEurope",
    "year":[1990,1992,1994,1993,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010],
    "values":[1548736,1334452,1313088,1283248,1314709,1360546,1343907,1285511,1237278,1251872,1244069,1233778,1284639,1297510,1317861,1359787,1396681,1361445,1278731,1343044]
}, 
{
    "id":"EasternEurope",
    "year":[1990,1992,1994,1993,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010],
    "values":[4418516,3530464,3287987,2925644,2775181,2672238,2540975,2495036,2513372,2515375,2540796,2544848,2598148,2637682,2622241,2709974,2714204,2740248,2565213,2680226]
}, 
{
    "id":"NorthAmerica",
    "year":[1990,1992,1994,1993,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010],
    "values":[6750754,6821412,6948829,7059001,7166869,7386971,7460485,7509719,7573562,7790060,7675762,7710685,7769154,7896824,7918461,7841686,7966277,7751508,7277713,7493948]
}, 
{
    "id":"WesternEurope",
    "year":[1990,1992,1994,1993,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010],
    "values":[4365949,4290345,4222425,4221029,4264725,4353056,4290057,4310736,4251628,4260565,4306230,4278128,4333237,4337031,4305560,4267515,4209481,4125479,3841580,3924831
]
}]

And what I'd like to do is to generate a line path for each id, with the values of x being the years and y being the values. Other than asking for the code I tried to develop (below), I'd like to ask if this is the optimal layout for the data, I usually worked with simple csv and tsv and am not that good at managing .json. I assembled this dataset myself so if there's a more reasonable way to organize it I'm all ears. But back to the code, what I tried to do is the following in the line generator:

var line = d3   .svg.line()
                .interpolate("linear")
                .x(function (d, i) { for (var i = 0; i >= dataset.length; i++) {
                                        return dataset[(i)].year }})        
                .y(function (d, i) { for (var i = 0; i >= dataset.length; i++) {
                    return dataset[(i)].values; }});

and then in the path I tried the following:

var path = svg  
                .append("path")
                .attr("class", "line")
                .attr("d", line(dataset))   
                .attr("fill", "none")
                .attr("stroke", "#E37222")
                .attr("stroke-width", 0.5 + "px");

but in the console i get that there were problem parsing the coordinates of the path. Since I'm kinda new to the whole .json thing, I watched some tutorials and read some guides, but can't manage to solve this by myself. Any explaination on how to solve this would be really appreciated, thanks!

The idea behind the line generator is that you pass it a list of values and it generates a point for each of them. As such, it expects its input to be a list of elements rather than a single one as in your case. You should probably also use the usual .data() pattern if you're using D3.

So what this boils down to is that you would define your line as follows.

var line = d3.svg.line().x(function(d,i) { return xscale(data[0].year[i]); })
                        .y(function(d) { return yscale(d); });

Then you can create the path elements like this.

svg.selectAll("line").data(data).enter()
   .append("path").attr("d", function(d) { return line(d.values); });

This is a bit hacky because you're getting the year through the index, but with your current data format this is just the way it is.

Complete jsfiddle here . You can make this a lot prettier and easier by having a list that has an element for each data point on the graph. That is, instead of having one element per line as you do currently, one point (for several lines) is one element. The format would be something like this.

[{year: 1990, valueAustralia: 1000, valueEurope: 2000}, {year: 1991, ...}]

Then you can simply define different line generators for the different lines as follows.

var line1 = d3.svg.line().x(function(d) { return xscale(d.year); })
                         .y(function(d) { return yscale(d.valueAustralia); }),
    line2 = d3.svg.line().x(function(d) { return xscale(d.year); })
                         .y(function(d) { return yscale(d.valueEurope); });

And the code to draw the lines would be as follows.

d3.selectAll("path.australia").data(data).enter()
  .append("path").attr("class", "australia").attr("d", line1);
// etc

You could of course have a completely data-driven design with nested elements (ie each data point in the list contains a list of values for the different regions) which would eliminate the need for several line generators and would make your code a lot more flexible. I do suggest that you start with the simpler solution of having multiple generators however.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM