如何使用下拉菜单在 d3 中创建多折线图?

How do I create a multi-line chart in d3 with a dropdown menu?

我之前发布的问题可能过于具体。我正在尝试在 d3 中创建一个带有下拉菜单的多折线图,类似于 this.

我已经关闭了 v7 所需的明显更改,但仍然 运行 遇到麻烦,我相信 var initialGraph 之后的 if/else 声明,但我不是 100 % 当然。也可能是因为我的 d3.groups 没有正确设置/引用。

我收到的当前错误是:

Uncaught (in promise) TypeError: Cannot read property 'year' of undefined
    at <anonymous>:23:33
    at a (d3.v7.min.js:2)
    at initialGraph (<anonymous>:83:18)
    at <anonymous>:89:3

我的数据集有四个值:year、state、wvalues 和 lvalues。 state 和 lvalues 是字符串,year 和 wvalues 是数字。到目前为止,这是我的代码:

  var margin = { top: 50, right: 50, bottom: 50, left: 50 }
  var h = 500 - margin.top - margin.bottom
  var w = 700 - margin.left - margin.right
  var formatDecimal = d3.format('.2')

d3.csv('15/data.csv').then(function (data) {

// Scales
var x = d3.scaleLinear()
  .range([0,w])
var y = d3.scaleLinear()
  .range([h,0])

  y.domain([
    d3.min([0,d3.min(data,function (d) { return d.wvalue })]),
    d3.max([0,d3.max(data,function (d) { return d.wvalue })])
    ]);
  x.domain([1968, 2016])
  
// Define the line
var valueLine = d3.line()
    .x(function(d) { return x(d.year); })
    .y(function(d) { return y(d.wvalue); })

// Create the svg canvas in the "d3block" div
var svg = d3.select("#d3block")
        .append("svg")
        .style("width", w + margin.left + margin.right + "px")
        .style("height", h + margin.top + margin.bottom + "px")
        .attr("width", w + margin.left + margin.right)
        .attr("height", h + margin.top + margin.bottom)
        .append("g")
        .attr("transform","translate(" + margin.left + "," + margin.top + ")")
        .attr("class", "svg");

//nest variable
var nest = d3.groups(data, 
  d => d.state, d => d.lvalue)

  // X-axis
  var xAxis = d3.axisBottom()
    .scale(x)
    .tickFormat(formatDecimal)
    .ticks(7)
  // Y-axis
  var yAxis = d3.axisLeft()
    .scale(y)
    .tickFormat(formatDecimal)
    .ticks(5)
    // Create a dropdown
    var legisMenu = d3.select("#legisDropdown")

    legisMenu
    .append("select")
    .selectAll("option")
        .data(nest)
        .enter()
        .append("option")
        .attr("value", ([key, ]) => key)
        .text(([key, ]) => key)

  // Function to create the initial graph
  var initialGraph = function(legis){

    // Filter the data to include only state of interest
    var selectLegis = nest.filter(([key, ]) => key == legis)

      var selectLegisGroups = svg.selectAll(".legisGroups")
        .data(selectLegis, function(d){
          return d ? d.key : this.key;
        })
        .enter()
        .append("g")
        .attr("class", "legisGroups")

    var initialPath = selectLegisGroups.selectAll(".line")
      .data(([, values]) => values)
      .enter()
      .append("path")

    initialPath
      .attr("d", valueLine(([, values]) => values))
      .attr("class", "line")

  }

  // Create initial graph
  initialGraph("Alabama")


  // Update the data
  var updateGraph = function(legis){

    // Filter the data to include only state of interest
    var selectLegis = nest.filter(([key, ]) => key == legis)

    // Select all of the grouped elements and update the data
      var selectLegisGroups = svg.selectAll(".legisGroups")
        .data(selectLegis)

        // Select all the lines and transition to new positions
            selectLegisGroups.selectAll("path.line")
               .data(([, values]) => values)
                .transition()
                  .duration(1000)
                  .attr("d", valueLine(([, values ]) => values))
  }

  // Run update function when dropdown selection changes
  legisMenu.on('change', function(){

    // Find which state was selected from the dropdown
    var selectedLegis = d3.select(this)
            .select("select")
            .property("value")

        // Run update function with the selected state
        updateGraph(selectedLegis)

    });
      
  // X-axis
  svg.append('g')
      .attr('class','axis')
      .attr('id','xAxis')
      .attr('transform', 'translate(0,' + h + ')')
      .call(xAxis)
    .append('text') // X-axis Label
      .attr('id','xAxisLabel')
      .attr('fill','black')
      .attr('y',-10)
      .attr('x',w)
      .attr('dy','.71em')
      .style('text-anchor','end')
      .text('')
  // Y-axis
  svg.append('g')
      .attr('class','axis')
      .attr('id','yAxis')
      .call(yAxis)
    .append('text') // y-axis Label
      .attr('id', 'yAxisLabel')
      .attr('fill', 'black')
      .attr('transform','rotate(-90)')
      .attr('x',0)
      .attr('y',5)
      .attr('dy','.71em')
      .style('text-anchor','end')
      .text('wvalue')
})

我进行了更多挖掘并找到了答案

我不得不将初始路径属性 .attr("d", valueLine(([, values]) => values)) 替换为 .attr('d', (d) => valueLine(Array.from(d.values())[1]))。我还必须在 selectLegisGroups .attr 下的 updateGraph 函数中进一步替换代码,以使其正确更新。