javascript - 如何使用从 csv 文件过滤的数据创建多系列折线图?

标签 javascript d3.js data-visualization linechart

我有一个 data.csv 文件是这样完成的:

CODE,YEAR,MODALITY,VALUE
AB,2000,first,15
AB,2000,second,
AB,2000,third,33
AB,2001,first,20
AB,2001,second,25
AB,2001,third,87
AB,2002,first,6
AB,2002,second,
AB,2002,third,16
AB,2003,first,50
AB,2003,second,50
AB,2003,third,10
AB,2004,first,20
AB,2004,second,55
AB,2004,third,8
AC,2000,first,
AC,2000,second,97
AC,2000,third,77
AC,2001,first,42
AC,2001,second,5
AC,2001,third,81
AC,2002,first,
AC,2002,second,63
AC,2002,third,14
AC,2003,first,5
AC,2003,second,7
AC,2003,third,0
AC,2004,first,5
AC,2004,second,7
AC,2004,third,0
AD,2000,first,11
AD,2000,second,2
AD,2000,third,36
AD,2001,first,95
AD,2001,second,78
AD,2001,third,88
AD,2002,first,89
AD,2002,second,32
AD,2002,third,79
AD,2003,first,5
AD,2003,second,32
AD,2003,third,9
AD,2004,first,7
AD,2004,second,32
AD,2004,third,91
AE,2000,first,15
AE,2000,second,78
AE,2000,third,1
AE,2001,first,5
AE,2001,second,2
AE,2001,third,64
AE,2002,first,44
AE,2002,second,51
AE,2002,third,
AE,2003,first,40
AE,2003,second,52
AE,2003,third,85
AE,2004,first,45
AE,2004,second,50
AE,2004,third,80

我创建了一个由一些用户可选元素组成的 index.html 文件(在示例中,为简单起见,我选择了 4 个圆圈,代码为 ABAC ADAE)和 3 个单选按钮(firstsecondthird )。

用户可以选择一个或多个圆圈,也可以选择一个单选按钮。

所以我有一个包含所选圆圈代码的数组 codes 和一个包含所选单选按钮的 modalitySelected 变量。

我想要做的是根据用户所做的选择来表示数据的折线图。

例子: enter image description here

每个选择的代码都有一行,值是与所选单选按钮对应的值。

在这个例子中有一些缺失的数据,虚线就是这个。 (目前这并不重要)。

这是我的代码。最初对圆的选择进行管理,并创建 codes 数组,其中包含所选元素的代码。 然后创建折线图。

index.html:

<body>
   <div id="circles">
      <svg>
         <circle id="AB" cx="10" cy="10" r="10" fill="purple" />
         <circle id="AC" cx="60" cy="60" r="5" fill="red" />
         <circle id="AD" cx="110" cy="110" r="15" fill="orange" />
         <circle id="AE" cx="90" cy="50" r="7" fill="yellow" />
      </svg>
   </div>
   <button type="button" id="finalSelection">Finish</button>

   <span style="display:block;margin-top: 10px;">Selected codes: <span class="values"></span></span><br>

   <div id="modality-selector-container">
      <form id="modality-selector">
         <input type="radio" name="modality-selector" id="rb-first" value="first" checked />
         <label for="rb-first">First</label>
         <input type="radio" name="modality-selector" id="rb-second" value="second" />
         <label for="rb-second">Second</label>
         <input type="radio" name="modality-selector" id="rb-third" value="third" />
         <label for="rb-third">Third</label>
      </form>
   </div>

   <div id="line-chart-container"></div>
   <script src="./script.js"></script>
</body>

script.js:

var codes = [];
modalitySelected = document.querySelector('input[name=modality-selector]:checked').value; 
var filtered_data = null;

// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 30, left: 50};
var width = 600 - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;

// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]); 

// parse the date/time
var parseTime = d3.timeParse("%Y"); 

var svg = null;
var valueline = null;

d3.selectAll('#circles svg circle').on('click', function() {
   var id = d3.select(this).attr('id');

   if(d3.select(this).classed('clicked')) { 
      d3.select(this).classed('clicked', false).style('stroke', null);
      codes.splice(codes.indexOf(id), 1); 
   } 
   else { 
      if(codes.length) { 
         if(d3.event.ctrlKey) { 
            d3.select(this).classed('clicked', true).style('stroke', 'blue');
            codes.push(id); 
         }
         else { 
            d3.selectAll(".clicked").classed('clicked', false).style('stroke', null);
            codes = [];
            d3.select(this).classed('clicked', true).style('stroke', 'blue');
            codes.push(id); 
         }
      } 
      else {
         d3.select(this).classed('clicked', true).style('stroke', 'blue');
         codes.push(id);
      }
   }

   $('span.values').html(codes.join(', '));
});

$('button#finalSelection').click(function() {
   $('span.values').html(codes.join(', '));
   console.log("compare: " + codes);
   compareCodes();
});

function compareCodes() {
   // define the line
   valueline = d3.line()
      .x(function(d) {
         return x(d.YEAR); 
      })
      .y(function(d) {
         return y(d.VALUE);  
      });  

   // append the svg obgect to the body of the page
   // appends a 'group' element to 'svg'
   // moves the 'group' element to the top left margin
   svg = d3.select("#line-chart-container").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 + ")");

   getData(); 
}

function getData() {
   d3.queue()
      .defer(d3.csv, './data.csv') 
      .await(makeLineChart); 
}

function makeLineChart(error, data) {
   if(error) {
      console.log(error);
   }

   // radio button change
   d3.selectAll("input[name='modality-selector']")
      .on("change", function(){
         console.log(this.value);
         modalitySelected = this.value;

         // filter data
         filtered_data = data.filter(function(d) {
            return d.MODALITY == modalitySelected && d.CODE == codes[0];
         });

         // format the data
         filtered_data.forEach(function(d) {
            d.YEAR = parseTime(d.YEAR);
            d.VALUE = +d.VALUE;
         });

         updateGraph(filtered_data);
      }); // end radio on change

   // generate initial line chart - filter data
   filtered_data = data.filter(function(d) {
      return d.MODALITY == modalitySelected && d.CODE == codes[0];
   });
   updateGraph(filtered_data);
}

function updateGraph(data) {
   var numTickXaxis = data.length;

   // scale the range of the data
   x.domain(d3.extent(filtered_data, function(d) { 
      return d.YEAR; 
   }));
   y.domain([0, d3.max(filtered_data, function(d) { 
      return d.VALUE; 
   })]);

   // add the valueline path
   svg.append("path")
      .data([filtered_data])
      .attr("class", "line")
      .attr("d", valueline);

   // add the X Axis
   svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x)
         .tickFormat(d3.timeFormat("%Y"))
         .ticks(numTickXaxis))
      .selectAll("text")   
         .style("text-anchor", "end")
         .attr("dx", "-.8em")
         .attr("dy", ".15em")
         .attr("transform", "rotate(-65)");

   // add the Y Axis
   svg.append("g")
      .attr("class", "axis")
      .call(d3.axisLeft(y)); 

   var state = svg.selectAll(".line");
   state.exit().remove();
}

完整代码为HERE .

这段代码有两个问题:

  1. 当更改单选按钮选择时,图表会被覆盖(尽管存在 state.exit().remove();)
  2. 如您所见,该代码仅适用于 codes 中的第一个元素。我不知道如何处理 codes 由多个元素组成并显示更多行的情况。

我可以考虑修改 data.csv 的结构以保持相同的内容。 例如,我可以这样编辑文件:

CODE,YEAR,FIRST,SECOND,THIRD
AB,2000,15,50,33
AB,2001,20,25,87
AB,2002,6,,16
AB,2003,50,50,10
AB,2004,20,55,8
AC,2000,,97,77
AC,2001,42,5,81
AC,2002,,63,14
AC,2003,5,7,0
AC,2004,5,7,0
AD,2000,11,2,36
AD,2001,95,78,88
AD,2002,89,32,79
AD,2003,5,32,9
AD,2004,7,32,91
AE,2000,15,78,1
AE,2001,5,2,64
AE,2002,44,51,
AE,2003,40,52,85
AE,2004,45,50,80

有人知道如何帮助我吗?谢谢!


解决方案

正在关注 this example ,我能够解决问题。

HERE代码。

现在我只有一个小的(我希望)图形问题。 从这张图中我们可以清楚的看出问题所在。

enter image description here

线条在轴之前开始。为什么?

最佳答案

问题是 createAxis() 中的 “transform”、“translate(” 将轴移到了一边。

所以我加了

.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

到您原来的 svg 变量,使其与轴对齐并删除

  .attr("transform", "translate(" + 0 + "," + 0 + ")");

来自 createAxis()

这是链接:Plunker

关于javascript - 如何使用从 csv 文件过滤的数据创建多系列折线图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48264567/

相关文章:

javascript - ProtractorJS 规范未运行,浏览器获取数据;仅有的

java - 如何在 JAVA 中创建 JSON 输出

javascript - D3 条形图到堆积条形图

r - 如何将效果大小添加到 t 检验的 ggplot 条形图? (例如 Cohen 的 d 或 Hedges 的 g)

image - 如何自动选择n种不同的颜色来绘制n个不同的对象?

python - 词向量列表上的 T-SNE 可视化

javascript - 如何显示城市的 Google map ?

javascript - 在nodejs中编写 "blocking"代码

D3.JS:多系列折线图,显示日期所有线条的工具提示?

d3.js - D3js:什么时候使用.datum()和.data()?