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>
.line {
fill: none;
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>
var margin = {
top: 50,
right: 20,
bottom: 30,
left: 80
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
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);
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 + ")");
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; })
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()
d3.select("#contBtn")
.selectAll('myOptions')
.data(countriess)
.enter()
.append('option')
.text(function (d) { return d; })
.attr("value", function (d) { return d; })
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);
})]);
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)
}
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");
});
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
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) {
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)
}
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");
});
}
d3.select("#contBtn").on("change", function(d) {
var selectedOption = d3.select(this).property("value");
update(selectedOption);
});
});
</script>
</body>