2014-03-14 116 views
0

我正在尝试将多行图形合并到一个关于城市和温度的Bostock示例中。D3多系列折线图从tsv文件中获取我的国家数据

例子就在这里http://bl.ocks.org/mbostock/3884955

现在,我有来自世界数据库信息定制一个TSV文件。格式如下

Country Name Year GDP Population GDP per Capita Exports Industry 
Brazil 2004 663760341880.342 184010283 3607.1915713555 16.4250921582 30.1135838508 
Brazil 2005 882185702547.247 186142403 4739.3054367481 15.1283508131 29.27296088 
Brazil 2006 1088916819852.94 188134315 5787.9755740091 14.3684508393 28.7527649158 
Brazil 2007 1366853244424.28 189996976 7194.0789437843 13.3643803148 27.8112224671 
Brazil 2008 1653538618144.8 191765567 8622.7086750397 13.6631968034 27.901606309 
Brazil 2009 1620165226993.77 193490922 8373.3397424907 10.9789949015 26.8288327492 
Brazil 2010 2143035333258.24 195210154 10978.093553772 10.8715851234 28.0694513261 
Brazil 2011 2476652189879.72 196935134 12575.9794079188 11.8891676714 27.5330208705 
Brazil 2012 2252664120777.39 198656019 11339.5211084814 12.557350455 26.2886840461 

我在哪里有多个国家不同年份的投入。格式是一个答案从另一个问题后这里

D3 Getting values from keys using array of objects

这TSV文件中的建议是为了绘制GDP,人口等因素对不同的SVG图形;为了方便起见,我把它放在一个tsv文件中。现在,我的下一步是从我的数据中提取这些国家并将它们绘制成线。该示例在标题行中具有城市作为关键字,由d3.keys调用进行解析。如上所示,我的国家在一个名为国名的关键字中。我如何解析我的数据,以便为每个国家/地区获得一行?

这里就是我在编码

//Define Margin Object with properties from the four sides Clockwise 
var margin = {top: 20, right: 80, bottom: 30, left: 50}; 
var dataset; 

//Width and Height as inner dimensions of chart area 
var width = 960 - margin.left - margin.right; 
var height = 500 - margin.top - margin.bottom; 

//Define svg 
var svg = d3.select("#chart").append("svg") 
    .attr("width", width + margin.left + margin.right) 
    .attr("height", height + margin.top + margin.bottom) 
    .append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

var x = d3.scale.linear() 
    .range([0, width]); 

var y = d3.scale.linear() 
    .range([0, height]); 

var color = d3.scale.category10(); 

var xAxis = d3.svg.axis() 
    .scale(x) 
    .orient("bottom"); 

var yAxis = d3.svg.axis() 
    .scale(y) 
    .orient("left"); 

var line = d3.svg.line() 
    .interpolate("basis") 
    .x(function(d) {return x(d.year);}) 
    .y(function(d) {return y(d.GDP);}); 

d3.tsv("OlympicsData.tsv", function(error, data) { 
    x.domain(d3.extent(data, function(d) {return d["Year"];})); 
    y.domain(d3.extent(data, function(d) {return d["GDP"];})); 

    console.log(d3.min(data, function(d) {return d["Year"];}) + " " + d3.max(data, function(d) {return d["Year"];})); 

    svg.append("g") 
    .attr("class", "x axis") 
    .call(xAxis); 

    svg.append("g") 
    .attr("class", "y axis") 
    .call(yAxis); 
}); 
+0

你可以用硬编码数据在[jsFiddle](http://jsfiddle.net)上对此进行演示吗? –

+0

我可悲的不能,因为我专注于尝试读取这些数据。令人困惑的是我需要使用jsFiddle进行操作? – kthieu

+0

所以基本上你的问题只是格式化数据,就像你在上面引用的Bostock例子那样?在他的例子中,每一行都是单列,而在每个国家都有多行记录。对? –

回答

1

要创建与D3多线图方面目前我在,你需要

  1. 创建一个顶级的数据阵列,每个数据系列(即图表上的每一行)都有一个条目;和
  2. 对于每个数据系列,以标准格式创建一个包含该系列数据的(x,y)点数组。

当您的数据为表格格式时,如果您可以硬编码表示要用作数据序列的列的列名称数组,那么每个系列都位于单独的列中。

var seriesNames = ["GDP", "Population", "GDP per Capita", "Exports", "Industry"]; 

如果你不希望在所有的系列名称硬编码,你将至少需要知道将用于x值和任何其他列的列的名称不包括。然后,您可以从d3.keys(data[0])获取所有列的名称,并使用数组筛选器来摆脱“Year”和“Country Name”值。您链接到迈克·博斯托克例如这是否设置色阶的域时,然后抓起从color.domain()以备将来使用数组:

color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; })); 

我觉得还不清楚,而将节省的名字在一个阵列可变第一,然后用它来设置颜色规模的域:

var seriesNames = d3.keys(data[0]).filter(function(key) { 
            return key !== "date"; 
            //you would have to change the name(s) to exclude 
           }); 
color.domain(seriesNames); 

无论你硬编码或动态创建它,那么你可以使用你的系列名称的数组创建数组的数组:

var series = seriesNames.map(function(name) { 
    return { 
     name: name, 
     values: data.map(function(d) { 
     return {x: d.year, 
       y: +d[name] }; 
     }) 
    }; 
}); 

数组map函数创建一个新数组,其中每个条目都是将相应条目从起始数组传递到映射函数的结果。此代码使用两级映射:外部函数接受您的系列名称并返回一个数据对象,内部函数接受原始数据数组并仅提取与此系列相关的值,并使用标准化名称,然后您可以使用在你的其他代码中。

这应该让你开始,但是你的数据中有一个复杂因素不在你正在使用的例子中:你的数据系列都代表完全不同的数字类型,具有完全不同的尺度。我不确定你是如何计划处理在同一张图表上绘制所有这些值的图表,但一种选择是从开始年份开始绘制百分比变化图。你可以在你的数据映射函数中做这样的计算:

var series = seriesNames.map(function(name) { 
    var initialValue = +data[0][name]; 
    return { 
     name: name, 
     values: data.map(function(d) { 
     return {year: d.year, 
       percentChange: (+d[name]/initialValue) }; 
     }) 
    }; 
});