如何使用从csv文件中过滤的数据创建多系列折线图? [英] How to create a multiseries line chart using data filtered from a csv file?

查看:254
本文介绍了如何使用从csv文件中过滤的数据创建多系列折线图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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个圆圈,其代码分别为 AB AC AD AE )和3个单选按钮(第一第二第三). /p>

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

因此,我有一个数组codes,其中包含所选圆的代码,一个modalitySelected变量,其中包含所选的单选按钮.

我想做的是一个折线图,该折线图表示基于用户所做选择的数据.

示例:

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

在此示例中,缺少一些数据,而虚线仅此. (目前,这并不重要).

这是我的代码.最初,管理圆的选择,并创建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();
}

完整代码为 此处 .

此代码中存在两个问题:

  1. 更改单选按钮选择时,图形会被覆盖(尽管存在state.exit().remove();)
  2. 如您所见,
  3. 该代码仅适用于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

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


解决方案

按照此示例,我能够解决问题.

此处 代码.

现在,我只有一个很小的(我希望是)图形问题. 在这张照片中,我们可以清楚地看到问题出在哪里.

线在轴之前开始.为什么?

解决方案

问题是createAxis()中的"transform", "translate("将轴移到了一侧.

所以我添加了

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

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

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

createAxis()

这里是链接: 柱塞

I have a data.csv file done this way:

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

I created an index.html file composed of some user selectable elements (in the example, for simplicity, I chose 4 circles with codes AB, AC, AD or AE) and 3 radio buttons (first, second and third).

The user can select one or more circles and also select a radio button.

So I have an array codes that contains the codes of the selected circles and a modalitySelected variable that contains the radio button chosen.

What I would like to do is a line chart that represents the data based on the selection made by the user.

Example:

There is a line for each chosen code and the values are those corresponding to the selected radio button.

In this example there are some missing data, and the dotted line just this. (For now this is not important to represent).

This is my code. Initially the selection of the circles is managed and the codes array is created which contains the codes of the selected elements. Then the line chart is created.

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

Complete code is HERE.

In this code there are two problems:

  1. when changing radio button selection, the graph is overwritten (despite the presence of state.exit().remove();)
  2. as you can see, the code works only for the first element in codes. I don't know how to handle the case where codes is composed of several elements and show more lines.

I can consider the idea of modifying the structure of data.csv keeping the same content. For example, I could edit the file like this:

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

Would anyone know how to help me? Thanks!


SOLUTION

Following this example, I was able to solve the problem.

HERE the code.

Now I have only a small (I hope) graphic problem. In this picture we can clearly see what the problem is.

The lines start before the axes. Why?

解决方案

The problem was that the "transform", "translate(" in your createAxis() moved your axis to the side.

So I added

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

To your original svg variable so that it aligns with the axis and removed the

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

From the createAxis()

Here's the link: Plunker

这篇关于如何使用从csv文件中过滤的数据创建多系列折线图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆