Hello,
I’m having a problem with D3. Here’s what i would like to achieve : a multi line graph by cities (“ville”) with colours corresponding to categories.
I finally get a graph, tooltip and colours, but they don’t correspond to the data.
I believe the problem comes from my dataNest array but after multiple hours, trying to fix the array, the range and the domain of colours, i couldn’t find the right one.
Thanks for your answers
Here’s a sample of my data.csv file :
“ville,annee,taux,codeHexa
Arbonne la Forêt,2015,NaN,#65509C
Arbonne la Forêt,2016,NaN,#65509C
Arbonne la Forêt,2017,NaN,#65509C
Arbonne la Forêt,2018,9.13,#65509C
Arbonne la Forêt,2019,5.21,#65509C
Avon,2015,12.29,#65509C
Avon,2016,14.15,#65509C
Avon,2017,14.28,#65509C
Avon,2018,15.57,#65509C”
…
And here’s my code :
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body {
font-family: "PT Sans";
}
path {
stroke-width: 10px;
fill: none;
overflow: visible;
opacity: 0.5;
}
.axis path,
.axis line {
fill: none;
/*stroke: grey;*/
stroke-width: 0.2px;
shape-rendering: crispEdges;
}
.tooltip {
position: absolute;
text-align: center;
/*display: none;*/
padding: 5px;
background: #50C688;
opacity: 0.6;
border: 0px;
border-radius: 7px;
pointer-events: none;
}
</style>
<body>
<div id="container" height="500" width="960" , style="border:none"></>
<!--<g id="body"></g>-->
</svg>
</body>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v6.min.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// parse the date / time
var parseTime = d3.timeParse("%Y");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// define the line
var tauxRefus = d3.line()
//line with missing data
.defined(d => !isNaN(d.taux))
.x(d => x(d.annee))
.y(d => y(d.taux));
// define the container width and height
var svg = d3.select("#container")
.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 + ")");
// define the tooltip
var tooltip = d3.select("#container").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Get the data
d3.csv("SMICTOM_VilleAnneeTaux.csv").then(function(data) {
data.forEach(function(d) {
d.annee = parseTime(d.annee);
d.taux = +d.taux;
d.ville = d.ville;
d.couleur = d.codeHexa;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.annee; }));
y.domain([0, d3.max(data, function(d) { return d.taux; })]).nice();
// Grouper les entrées par nom de ville
var dataNest = Array.from(
d3.group(data, d => d.ville), ([ville, taux]) => ({ville, taux}))
var couleur = d3.scaleOrdinal()
.range(d3.map(dataNest, function(d) {return d.taux.couleur}))
.domain(d3.map(dataNest, function(d) {return d.ville; }));
// Boucle à travers chaque clef
dataNest.forEach(function(d, i) {
svg.append("path")
.attr("class", "line")
.style("stroke", function() {
return d.couleur = couleur(i)
})
.attr("d", tauxRefus(d.taux))
.on("mouseover", function(event, d) {
tooltip.transition()
tooltip.html("Ville : " + dataNest[i].ville + "<br>" + "Couleur : " + data[i].couleur)
.style("left", event.clientX + "px")
.style("top", event.clientY + 25 + "px")
.style("display", "inline")
d3.select(this).style("opacity", 1).style("stroke-width", 5)
})
.on("mousemove", function(event, d) {
tooltip.transition()
tooltip.html("Ville : " + dataNest[i].ville + "<br>" + "Année : " + data[i].couleur)
.style("left", event.clientX + "px")
.style("top", event.clientY + 25 + "px")
.style("display", "inline")
d3.select(this).style("opacity", 1)
})
.on("mouseleave", function(event, d) {
tooltip.transition()
.style("display", "none")
.style("opacity", 0.8)
d3.select(this).style("opacity", 0.5)
.style("stroke-width", 1)
})
});
// Add the X and Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.style("font-family", "PT Sans")
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0));
svg.append("g")
.attr("class", "axis")
.style("font-family", "PT Sans")
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
;
// line with missing data
svg.append("path")
.datum(dataNest.filter(tauxRefus.defined()))
.attr("stroke", "grey")
.attr("d", tauxRefus);
});
</script>
</html>
PS : i’m a kind of a noob in D3 but working hard to fix it.