0

我正在尝试按照博斯托克关于城市和温度的示例将多条折线图制作成一个。

示例就在这里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使用对象数组从键中获取值

此 TSV 文件用于在单独的 svg 图表上绘制 GDP、人口等;为方便起见,我将其放入一个 tsv 文件中。现在,我的下一步是从我的数据中提取国家并将它们绘制成线条。该示例将城市作为标题行中的键,由 d3.keys 调用解析。但是,我的国家/地区位于一个名为 Country Name 的键中,如上所示。我将如何解析我的数据,以便为每个国家/地区获得一条线?

这是我目前在编码方面的情况

//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);
});
4

1 回答 1

1

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

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

当您的数据采用表格格式时,每个系列都位于单独的列中,如果您可以硬编码表示要用作数据系列的列的列名数组,这将变得更加容易。

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

如果您不想在所有系列名称中硬编码,您至少需要知道将用于 x 值的列的名称以及不包含的任何其他列的名称。然后您可以从中获取所有列的名称d3.keys(data[0]),并使用数组过滤器去除“年份”和“国家名称”值。您链接到的 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) };
      })
    };
});
于 2014-03-14T21:59:51.947 回答