D3多系列线形图从tsv文件获得我的国家数据

D3 Multi Series Line Graph getting my countries data from tsv file

本文关键字:文件 我的 数据 国家 tsv 系列 D3      更新时间:2023-09-26

我正在尝试将多个线形图合并为如下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使用对象数组从键获取值

这个TSV文件是为了在单独的svg图形上绘制GDP,人口等;为了方便,我把它放在一个tsv文件中。现在,我的下一步是从我的数据中提取国家,并将它们绘制成直线。该示例在标题行中将城市作为键,由d3解析。键调用。然而,如上所示,我的国家在一个名为"国家名称"的键中。我该如何解析我的数据,以便得到每个国家的一行?

这是我目前在编码方面的地方

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

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

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

当您的数据是表格式时,每个序列都在单独的列中,如果您可以硬编码一个列名数组,表示您想用作数据序列的列,这将变得容易得多。

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

如果您不想硬编码所有的系列名称,您至少需要知道将用于x值的列的名称以及不包含的任何其他列的名称。然后,您可以从d3.keys(data[0])中获得所有列的名称,并使用数组筛选器去除"Year"answers"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] };
      })
    };
});

array 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) };
      })
    };
});