Click here to Skip to main content
15,880,392 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I tried to create a multiline chart with a dropdown menu. The chart should change according to the data for the selected value in the dropdown menu. Currently, the dot at the line chart can change according to the value in the dropdown menu, but the previous line is not removed after changing the dropdown value. When I change the selection, the lines will be overlapped. Besides that, I don't know why some of the dots are missing at certain year even though there is data for that particular year after I change the selection. I'm very new to d3. Hope someone can help me fix these problems. Thank you in advance.

Here is the link to my data: https://raw.githubusercontent.com/syakirah98/data_vis/master/sex_country.csv[^]

Here is the link to my chart: line-chart — ImgBB[^]

What I have tried:

Below is my html code:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

    /* set the CSS */
    
    .line {
        fill: none;
        /*stroke: #aaa;
        stroke: #43484c;
        stroke: #405275;
        stroke: rgba(40, 53, 79, .95);
        stroke: #161719;
        stroke: #f99e1a;*/
        stroke: #f89e35;
        stroke-width: 2px;
    }
    
    .line2 {
        fill: none;
        stroke: #aaa;
        stroke-width: 2px;
    }
    
    .line3 {
        fill: none;
        stroke: #405275;
        stroke-width: 2px;
    }
    
    .line3-text {
        fill: #405275;
        stroke: #405275;
    }
    
    .line2-text {
        fill: #aaa;
        stroke: #aaa;
    }
    
    .line-text {
        fill: #f89e35;
        stroke: #f89e35;
    }
    
    div.tooltip {
        position: absolute;
        text-align: center;
        padding: 5px;
        font-size: 12px;
        font-weight: bold;
        background: #f99e1a;
        border: 0px;
        border-radius: 8px;
    }
    
    .tooltip p {
        margin: 0;
        padding: 0;
    }
    
    circle {
        fill: rgba(40, 53, 79, .95);
    }
    
    .chart-title {
        margin-bottom: 0;
    }

</style>

<body>
    <h4 class="chart-title">Suicide Rate by Gender</h4>
    <select id="contBtn"></select>
    <div class="sex"></div>
    <!-- load the d3.js library -->
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script>
        // set the dimensions and margins of the graph
        var margin = {
                top: 50,
                right: 20,
                bottom: 30,
                left: 80
            },
            width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom;

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

        // define the line  
        function basicy() {
            var ret = d3.line()
                .x(function (d) {
                    return x(d.year);
                })
            return ret;
        }
        var valueline = basicy()
            .y(function (d) {
                return y(d.female);
            });
        var valueline2 = basicy()
            .y(function (d) {
                return y(d.male);
            });
        var div = d3.select(".sex").append("div")
            .attr("class", "tooltip")
            .style("opacity", 0);

        // 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
        var svg = d3.select(".sex").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 + ")");

        // Get the data
        var datalist = [];
        d3.csv("https://raw.githubusercontent.com/syakirah98/data_vis/master/sex_country.csv", function (error, data) {
            if (error) throw error;
                    
              var dataGrouper = d3.nest().key(function(d) { return d.country; })
                //.entries(data);
              
              var datas = dataGrouper.entries(data);
                
              datas.forEach(function(d) {
                d.values.forEach(function(d) {
                    d.female = +d.female;
                    d.male = +d.male;
                });
              });
            
            var countriess = d3.map(data, function(d){return(d.country)}).keys()
    
            // add the options to the button
            d3.select("#contBtn")
              .selectAll('myOptions')
                .data(countriess)
              .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

            // scale the range of the data
            x.domain(d3.extent(data, function (d) {
                return d.year;
            }));
            y.domain([0, d3.max(data, function (d) {
                return Math.max(d.female, d.male);
            })]);

            // add the valueline path.
            var dataArray = [{
                "name": "Female",
                "x": 100,
                "y": 50,
                "class": "line-text",
                "class2": "line",
                "dataline": valueline
            }, {
                "name": "male",
                "x": 100,
                "y": 90,
                "class": "line2-text",
                "class2": "line2",
                "dataline": valueline2
            }]
            var filteredData = data.filter(function(d) {
                return d.country == countriess[0];
            });

            var groupedData = dataGrouper.entries(filteredData);

            for (var i = 0; i < dataArray.length; i++) {
                svg.append("text").text(dataArray[i].name)
                    .attr("x", dataArray[i].x)
                    .attr("y", dataArray[i].y);
                svg.append("rect")
                    .attr("x", dataArray[i].x - 70)
                    .attr("y", dataArray[i].y - 11)
                    .attr("width", 50)
                    .attr('height', 10)
                    .attr('class', dataArray[i].class)
                svg.append("path")
                    .data([groupedData[0].values])
                    .attr("class", dataArray[i].class2)
                    .attr("d", dataArray[i].dataline) 
            }

            // add the dots with tooltips
            var fixeddot = svg.selectAll("dot")
                .data(groupedData[0].values)
                .enter().append("circle")
                .attr("r", 5)
            var fixeddot2 = svg.selectAll("dot")
                .data(groupedData[0].values)
                .enter().append("circle")
                .attr("r", 5)
            

            fixeddot.attr("cx", function (d) {
                    return x(d.year);
                })
                .attr("cy", function (d) {
                    return y(d.female);
                })
                .on("mouseover", function (d) {
                    div.transition()
                        .duration(100)
                        .style("opacity", .9);
                    div.html("<p>Year:" + d.year + "</p> <p>Suicide rate:" + d.female + "</p>")
                        .style("left", (d3.event.pageX) + "px")
                        .style("top", (d3.event.pageY - 28) + "px");
                });

            fixeddot2.attr("cx", function (d) {
                    return x(d.year);
                })
                .attr("cy", function (d) {
                    return y(d.male);
                })
                .on("mouseover", function (d) {
                    div.transition()
                        .duration(100)
                        .style("opacity", .9);
                    div.html("<p>Year:" + d.year + "</p> <p>Suicide rate:" + d.male + "</p>")
                        .style("left", (d3.event.pageX) + "px")
                        .style("top", (d3.event.pageY - 28) + "px");
                });

            // add the X Axis
            svg.append("g")
                .attr("transform", "translate(0," + height + ")")
                .call(d3.axisBottom(x));

            // add the Y Axis
            svg.append("g")
                .call(d3.axisLeft(y));
                
            svg.append("g")
              .attr("class", "y axis")
              .call(y)
              .append('text')
              .attr("y", -50)
              .attr("x", -250)
              .attr("transform", "rotate(-90)")
              .attr("fill", "#000")
              .text("Suicides Rate (/100K)");   

            svg.append("text")
                .attr("class", "x axis")
                .attr("text-anchor", "end")
                .attr("x", 450)
                .attr("y", height + 30)
                .text("Year");
                
            function update(selectedGroup) {

              // Create new data with the selection?
              var filteredData = data.filter(function(d) {
                return d.country == selectedGroup;
              });
                    
              var groupedData = dataGrouper.entries(filteredData);
              
              for (var i = 0; i < dataArray.length; i++) {
                svg.append("text").text(dataArray[i].name)
                    .attr("x", dataArray[i].x)
                    .attr("y", dataArray[i].y);
                svg.append("rect")
                    .attr("x", dataArray[i].x - 70)
                    .attr("y", dataArray[i].y - 11)
                    .attr("width", 50)
                    .attr('height', 10)
                    .attr('class', dataArray[i].class)
                svg.append("path")
                    .data([groupedData[0].values]).transition().duration(1000)
                    .attr("class", dataArray[i].class2)
                    .attr("d", dataArray[i].dataline) 
            }

            // add the dots with tooltips
            fixeddot.data(groupedData[0].values).transition().duration(1000)
                .attr("r", 5)
            fixeddot2.data(groupedData[0].values).transition().duration(1000)
                .attr("r", 5)
            

            fixeddot.attr("cx", function (d) {
                    return x(d.year);
                })
                .attr("cy", function (d) {
                    return y(d.female);
                })
                .on("mouseover", function (d) {
                    div.transition()
                        .duration(200)
                        .style("opacity", .9);
                    div.html("<p>Year:" + d.year + "</p> <p>Suicide rate:" + d.female + "</p>")
                        .style("left", (d3.event.pageX) + "px")
                        .style("top", (d3.event.pageY - 28) + "px");
                });

            fixeddot2.attr("cx", function (d) {
                    return x(d.year);
                })
                .attr("cy", function (d) {
                    return y(d.male);
                })
                .on("mouseover", function (d) {
                    div.transition()
                        .duration(200)
                        .style("opacity", .9);
                    div.html("<p>Year:" + d.year + "</p> <p>Suicide rate:" + d.male + "</p>")
                        .style("left", (d3.event.pageX) + "px")
                        .style("top", (d3.event.pageY - 28) + "px");
                });

        }
        
            // When the button is changed, run the updateChart function
            d3.select("#contBtn").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>
</body>
Posted

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