Click here to Skip to main content
15,881,967 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm trying to replicate this line chart according to my data, but the line chart produces many lines instead of just one line.

here is the link of line chart that I tried to replicate:
Filter group in d3.js line chart[^]

here is the link to the output of my line chart as your reference: line-chart — imgbb.com[^]

thank you in advance!

What I have tried:

below is my html code:
HTML
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Initialize a select button -->
<select id="selectButton"></select>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

<!-- Color Scale -->
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>

<script>

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

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
  .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 + ")");

//Read the data
d3.csv("https://raw.githubusercontent.com/syakirah98/data_vis/master/suicide_rate.csv", function(data) {

    // List of groups (here I have one group per column)
    var allGroup = d3.map(data, function(d){return(d.sex)}).keys()

    // add the options to the button
    d3.select("#selectButton")
      .selectAll('myOptions')
     	.data(allGroup)
      .enter()
    	.append('option')
      .text(function (d) { return d; }) // text showed in the menu
      .attr("value", function (d) { return d; }) // corresponding value returned by the button

    // A color scale: one color for each group
    var myColor = d3.scaleOrdinal()
      .domain(allGroup)
      .range(d3.schemeSet2);

    // Add X axis --> it is a date format
    var x = d3.scaleLinear()
      .domain(d3.extent(data, function(d) { return d.year; }))
      .range([ 0, width ]);
    svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x).ticks(31));

    // Add Y axis
    var y = d3.scaleLinear()
      .domain([0, d3.max(data, function(d) { return +d.suicides_rate; })])
      .range([ height, 0 ]);
    svg.append("g")
      .call(d3.axisLeft(y));

    // Initialize line with first group of the list
    var line = svg
      .append('g')
      .append("path")
        .datum(data.filter(function(d){return d.sex==allGroup[0]}))
        .attr("d", d3.line()
          .x(function(d) { return x(d.year) })
          .y(function(d) { return y(+d.suicides_rate) })
        )
        .attr("stroke", function(d){ return myColor("valueA") })
        .style("stroke-width", 4)
        .style("fill", "none")

    // A function that update the chart
    function update(selectedGroup) {

      // Create new data with the selection?
      var dataFilter = data.filter(function(d){return d.sex==selectedGroup})

      // Give these new data to update line
      line
          .datum(dataFilter)
          .transition()
          .duration(1000)
          .attr("d", d3.line()
            .x(function(d) { return x(d.year) })
            .y(function(d) { return y(+d.suicides_rate) })
          )
          .attr("stroke", function(d){ return myColor(selectedGroup) })
    }

    // When the button is changed, run the updateChart function
    d3.select("#selectButton").on("change", function(d) {
        // recover the option that has been chosen
        var selectedOption = d3.select(this).property("value")
        // run the updateChart function with this selected option
        update(selectedOption)
    })

})
</script>

below is the sample of my data:
csv
country,year,sex,age,suicides_no,population,suicides_rate,country-year,HDI for year, gdp_for_year ($) ,gdp_per_capita ($),generation
Albania,1987,male,15-24 years,21,312900,6.71,Albania1987,,"2,156,624,900",796,Generation X
Albania,1987,male,35-54 years,16,308000,5.19,Albania1987,,"2,156,624,900",796,Silent
Albania,1987,female,15-24 years,14,289700,4.83,Albania1987,,"2,156,624,900",796,Generation X
Albania,1987,male,75+ years,1,21800,4.59,Albania1987,,"2,156,624,900",796,G.I. Generation
Albania,1987,male,25-34 years,9,274300,3.28,Albania1987,,"2,156,624,900",796,Boomers
Albania,1987,female,75+ years,1,35600,2.81,Albania1987,,"2,156,624,900",796,G.I. Generation
Albania,1987,female,35-54 years,6,278800,2.15,Albania1987,,"2,156,624,900",796,Silent
Albania,1987,female,25-34 years,4,257200,1.56,Albania1987,,"2,156,624,900",796,Boomers
Albania,1987,male,55-74 years,1,137500,0.73,Albania1987,,"2,156,624,900",796,G.I. Generation
Albania,1987,female,5-14 years,0,311000,0,Albania1987,,"2,156,624,900",796,Generation X
Albania,1987,female,55-74 years,0,144600,0,Albania1987,,"2,156,624,900",796,G.I. Generation
Albania,1987,male,5-14 years,0,338200,0,Albania1987,,"2,156,624,900",796,Generation X
Albania,1988,female,75+ years,2,36400,5.49,Albania1988,,"2,126,000,000",769,G.I. Generation
Albania,1988,male,15-24 years,17,319200,5.33,Albania1988,,"2,126,000,000",769,Generation X
Albania,1988,male,75+ years,1,22300,4.48,Albania1988,,"2,126,000,000",769,G.I. Generation
Albania,1988,male,35-54 years,14,314100,4.46,Albania1988,,"2,126,000,000",769,Silent
Albania,1988,male,55-74 years,4,140200,2.85,Albania1988,,"2,126,000,000",769,G.I. Generation
Albania,1988,female,15-24 years,8,295600,2.71,Albania1988,,"2,126,000,000",769,Generation X
Albania,1988,female,55-74 years,3,147500,2.03,Albania1988,,"2,126,000,000",769,G.I. Generation
Albania,1988,female,25-34 years,5,262400,1.91,Albania1988,,"2,126,000,000",769,Boomers
Albania,1988,male,25-34 years,5,279900,1.79,Albania1988,,"2,126,000,000",769,Boomers
Albania,1988,female,35-54 years,4,284500,1.41,Albania1988,,"2,126,000,000",769,Silent
Albania,1988,female,5-14 years,0,317200,0,Albania1988,,"2,126,000,000",769,Generation X
Albania,1988,male,5-14 years,0,345000,0,Albania1988,,"2,126,000,000",769,Generation X
Albania,1989,male,75+ years,2,22500,8.89,Albania1989,,"2,335,124,988",833,G.I. Generation
Albania,1989,male,25-34 years,18,283600,6.35,Albania1989,,"2,335,124,988",833,Boomers
Albania,1989,male,35-54 years,15,318400,4.71,Albania1989,,"2,335,124,988",833,Silent
Albania,1989,male,55-74 years,6,142100,4.22,Albania1989,,"2,335,124,988",833,G.I. Generation
Albania,1989,male,15-24 years,12,323500,3.71,Albania1989,,"2,335,124,988",833,Generation X
Albania,1989,female,35-54 years,7,288600,2.43,Albania1989,,"2,335,124,988",833,Silent
Demo - JSFiddle[^]
Posted
Updated 28-Jan-20 23:19pm
v2

1 solution

The problem is that the sample is filtering by name. In the filtered data, there is only one entry per year.

In your sample data, you are filtering by sex. The filtered data has multiple entries for each year.

You need to sum up the filtered data by year, using the nest[^] function. You will also need to modify the range of your y-axis to account for the total values, which will be much higher than the individual entries.
JavaScript
var dataGrouper = d3.nest()
    .key(function(d) { return d.year; }).sortKeys(d3.ascending)
    .rollup(function(g) { return d3.sum(g, function(d) { return +d.suicides_rate; }) });

...

var y = d3.scaleLinear()
    .domain([0, d3.max(dataGrouper.entries(data), function(d) { return d.value; })])
    .range([height, 0]);

...

var filteredData = data.filter(function(d) { return d.sex == allGroup[0]; });
var groupedData = dataGrouper.entries(filteredData);

var line = svg
    .append('g')
    .append("path")
    .datum(groupedData)
    .attr("d", d3.line()
        .x(function(d) { return x(d.key); })
        .y(function(d) { return y(d.value); })
    )
    .attr("stroke", function(d) {
        return myColor("valueA")
    })
    .style("stroke-width", 4)
    .style("fill", "none");

...

function update(selectedGroup) {
    // Create new data with the selection
    var filteredData = data.filter(function(d) { return d.sex == selectedGroup; });
    var groupedData = dataGrouper.entries(filteredData);

    // Give these new data to update line
    line
        .datum(groupedData)
        .transition()
        .duration(1000)
        .attr("d", d3.line()
            .x(function(d) { return x(d.key); })
            .y(function(d) { return y(d.value); })
        )
        .attr("stroke", function(d) {
            return myColor(selectedGroup)
        });
}
Demo - JSFiddle[^]
 
Share this answer
 
Comments
Member 13620781 29-Jan-20 7:06am    
Thank you!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900