D3 Multi Series Line Graph从tsv文件获取我的国家/地区数据

时间:2014-03-14 07:17:28

标签: javascript svg d3.js linegraph

我正试图在Bostock关于城市和温度的例子中做多个线图。

示例就在这里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文件用于在单独的svg图上绘制GDP,人口等图表;为方便起见,我把它放在一个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);
});

1 个答案:

答案 0 :(得分:1)

要使用d3创建多线图,您需要

  1. 创建一个顶级数据数组,每个数据系列有一个条目(即图表中的每一行);和
  2. 对于每个数据系列,创建一个(x,y)点数组,其中包含标准格式的系列数据。
  3. 当您的数据采用表格格式时,每个系列都在单独的列中,如果您可以对表示要用作数据系列的列的列名称进行硬编码,这将变得更加容易。

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

    如果您不想在所有系列名称中进行硬编码,则至少需要知道将用于x值的列的名称以及不包括的任何其他列。然后,您可以从d3.keys(data[0])获取所有列的名称,并使用数组过滤器来删除“Year”和“Country Name”值。您链接到的Mike Bostock示例在设置色标的域时执行此操作,然后从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) };
          })
        };
    });