简体   繁体   中英

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

I posted a previous question with perhaps too much specificity. I'm trying to create a multi-line chart in d3 with a dropdown, similar to this .

I've switched out the obvious changes needed for v7 but am still running into trouble, I believe in the if/else statement right after var initialGraph but I'm not 100% sure. It may also be because my d3.groups isn't set up / referenced correctly.

The current error I receive is:

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

My dataset has four values: year, state, wvalues, and lvalues. state and lvalues are strings, year and wvalues are numeric. Here's my code so far:

  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')
})

I did more digging and found the answer here .

I had to replace the initial path attribute .attr("d", valueLine(([, values]) => values)) with .attr('d', (d) => valueLine(Array.from(d.values())[1])) . I also had to replace the code further down within the updateGraph function under selectLegisGroups .attr for it to update properly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM