Public
Edited
Mar 8
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
projection = d3.geoConicConformal().center([2.454071, 46.279229]).scale(2800)
Insert cell
path = d3.geoPath(projection)
Insert cell
map = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width , 500])
.style("width", "100%")
.style("height", "auto")
.style("background-color", "white");

svg
.append("g")
.append("path")
.datum(departements)
.attr("d", path)
.style("fill", "black")
.style("stroke", "white")
.attr("stroke-width", 0.5)
.attr("stroke-opacity", 0.6)
.attr("fill-opacity", 1);

svg
.append("g")
.append("path")
.attr("d", path)
.style("fill", "none")
.style("stroke", "white")
.attr("stroke-width", 1)
.attr("fill-opacity", 1);

return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
data.map(d=>{
d.sexe=parseInt(d.sexe)
d.hosp = parseInt(d.hosp)
d.rea = parseInt(d.rea)
d.HospConv = parseInt(d.HospConv)
d.SSR_USLD = parseInt(d.SSR_USLD)
d.autres = parseInt(d.autres)
d.rad = parseInt(d.rad)
d.dc = parseInt(d.dc)
return d
})
Insert cell
map_data(d3, departements, path, data )
Insert cell
function map_data (d3 ,departements, path, data){
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width , 500])
.style("width", "100%")
.style("height", "auto")
.style("background-color", "white");

let jourChoisi = "2021-09-12";
let cleanData = data.filter(d => d.sexe === 0 && d.jour === jourChoisi); // Filtre sexe == 0 (ce qui correspond à tous les genres, plutôt que 1 ou 2 / homme ou femme).
//let color = d3.scaleSequential(d3.interpolateOrRd).domain([0, 2000]); // échelle de couleur basée sur les hospitalisations.
let color = d3.scaleSequential(d3.interpolateOrRd).domain([0, 2000]);

for (let j = 0; j < departements.features.length; j++) {
let depCode = departements.features[j].properties.code;
let jourDepChoisi = cleanData.find(row => row.dep === depCode); // Associe les hospitalisations à chaque département.
departements.features[j].properties.value = jourDepChoisi ? jourDepChoisi.hosp : 0;
}

svg.append("g")
.selectAll("path")
.data(departements.features)
.join("path")
.attr("d", path)
.style("fill", d => {
let value = d.properties.value;
return value ? color(value) : "#ccc"; // gérer les départements sans données en leur assignant une couleur grise
})
.style("stroke", "white")
.attr("stroke-width", 0.5)
.attr("stroke-opacity", 0.6);

return svg.node();
}
Insert cell
Insert cell
parseDate = d3.timeFormat("%Y-%m-%d")
Insert cell
Insert cell
Insert cell
map_interactive(d3, calendrier, departements, data, width, height)
Insert cell
function map_interactive(d3, calendrier, france, covid, width, height) {

  const mapWidth = width;
  const mapHeight = height;
  const hospValues = Array.from(new Set(covid.map(item => item.hosp)));
  const sexes = Array.from(new Set(covid.map(d => d.sexe)));
  const colorScale = d3.scaleSequential(d3.interpolateOrRd).domain(d3.extent(hospValues));
  var sexs = sexes.indexOf(sex0);

  const svgElement = d3.create("svg")
    .attr("viewBox", [0, 0, width, mapHeight])
    .style("width", "100%")
    .style("height", "auto")
    .style("background-color", "white");

  for (var i = 0; i < france.features.length; i++) {
    let departement = france.features[i].properties.code;
    let data = covid.filter(d => d.dep == departement && d.jour == calendrier.toISOString().split('T')[0] && d.sexe == sexs);
    france.features[i].properties.data = data;
  }

  const tooltip = d3.select("body").append("div")
    .attr("class", "tooltip")
    .style("position", "absolute")
    .style("background", "white")
    .style("border", "1px solid black")
    .style("padding", "5px")

    .style("display", "none");



  const mapGroup = svgElement.append('g').attr("class", "topg");
  mapGroup.selectAll('path')
    .data(france.features)
    .enter().append('path')
    .attr('d', path)
    .style('fill', d => {
      if (d.properties.data && d.properties.data.length > 0) {
        return colorScale(+d.properties.data[0].hosp);
      } else {
        return '#ccc';
      }
    })

    .style('stroke', 'white')
    .attr("stroke-width", 0.5)
    .attr("stroke-opacity", 0.6)
    .on("mouseover", function (event, d) {
      tooltip.style("display", "block")
        .html(`${d.properties.nom}: ${d.properties.data.length ? d.properties.data[0].hosp : 0} hospitalisations`);
      d3.select(this).style("stroke", "black");
    })
    .on("mousemove", function (event) {
      tooltip.style("left", (event.pageX + 10) + "px")
        .style("top", (event.pageY - 10) + "px");
    })
    .on("mouseout", function () {
      tooltip.style("display", "none");
      d3.select(this).style("stroke", "none");
    });

  const zoomBehavior = d3.zoom()
    .scaleExtent([1, 8])
    .on('zoom', event => mapGroup.attr('transform', event.transform));

  svgElement.call(zoomBehavior);

  return svgElement.node();
}
Insert cell
Insert cell
viewof sex2 = Inputs.select([].concat(Array.from([...new Set(data.map(d => d.sexe))])), { label: "Choisissez le sexe à étudier", value: 0 });
Insert cell
Insert cell
Insert cell
map_interactive2(d3, calendrier_debut_1, calendrier_fin_1, departements, data, width, height)
Insert cell
function map_interactive2(d3, calendrierDebut, calendrierFin, france, covid, width, height) {
const mapWidth = width;
const mapHeight = height;
const hospValues = Array.from(new Set(covid.map(item => item.hosp)));
const sexes = Array.from(new Set(covid.map(d => d.sexe)));

// Gestion du sexe
const sexs = sexes.indexOf(sex2); // Assurez-vous que 'sex' est défini globalement ou passé en paramètre

const svgElement = d3.create("svg")
.attr("viewBox", [0, 0, width, mapHeight])
.style("width", "100%")
.style("height", "auto")
.style("background-color", "white");

const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("background", "white")
.style("border", "1px solid black")
.style("border-radius", "5px")
.style("padding", "5px")
.style("display", "none");

const mapGroup = svgElement.append('g').attr("class", "topg");

const foreground = svgElement.append("g").attr("class", "foreground");

const title = foreground.append("text")
.attr("x", mapWidth / 2)
.attr("y", 30)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.style("font-weight", "bold")
.text("Carte des hospitalisations COVID par département");

mapGroup.selectAll('path')
.data(france.features)
.enter().append('path')
.attr('d', path)
.style('fill', d => {
for (let i = 0; i < france.features.length; i++) {
let totalHosp = 0;
let departement = france.features[i].properties.code;
let data = covid.filter(d =>
d.dep == departement &&
d.sexe == sexs && // Filtre par sexe
new Date(d.jour) >= calendrierDebut && // Filtre date de début
new Date(d.jour) <= calendrierFin // Filtre date de fin
);
if (data.length > 0) {
totalHosp += data.reduce((sum, item) => sum + item.hosp, 0); // Somme des hosp pour le département
}
france.features[i].properties.totalHosp = totalHosp // Stocke la somme pour chaque département
}
const maxHosp = d3.max(france.features, d => d.properties.totalHosp);
const colorScale = maxHosp === undefined || maxHosp === 0 ?
d3.scaleSequential(d3.interpolateOrRd).domain([0, 1]) :
d3.scaleSequential(d3.interpolateOrRd).domain([0, maxHosp]);
if (d.properties.totalHosp > 0) {
return colorScale(d.properties.totalHosp);
} else {
return '#ccc';
}
})
.style('stroke', 'white')
.attr("stroke-width", 0.5)
.attr("stroke-opacity", 0.6)
.on("mouseover", function (event, d) {
tooltip.style("display", "block")
.html(`${d.properties.nom}: ${d.properties.totalHosp ? d.properties.totalHosp : 0} hospitalisations`); // Affiche la somme
d3.select(this).style("stroke", "black");
mapGroup.selectAll('path').style("opacity", e => e === d ? 1 : 0.5);
})
.on("mousemove", function (event) {
tooltip.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 10) + "px");
})
.on("mouseout", function () {
tooltip.style("display", "none");
d3.select(this).style("stroke", "none");
mapGroup.selectAll('path').style("opacity", 1);
});
const maxHosp = d3.max(france.features, d => d.properties.totalHosp);
const colorScale = maxHosp === undefined || maxHosp === 0 ?
d3.scaleSequential(d3.interpolateOrRd).domain([0, 1]) :
d3.scaleSequential(d3.interpolateOrRd).domain([0, maxHosp]);
const legend = svgElement.append("g")
.attr("transform", `translate(${mapWidth - 150}, ${mapHeight - 200})`);

const legendScale = d3.scaleLinear()
.domain(colorScale.domain())
.range([100, 0]);

const legendAxis = d3.axisRight(legendScale).ticks(5);

const gradient = svgElement.append("defs")
.append("linearGradient")
.attr("id", "legendGradient")
.attr("x1", "0%").attr("y1", "0%")
.attr("x2", "0%").attr("y2", "100%");

gradient.selectAll("stop")
.data(d3.range(0, 1.1, 0.1))
.enter().append("stop")
.attr("offset", d => `${d * 100}%`)
.attr("stop-color", d => colorScale(legendScale.invert(d * 100)));

legend.append("rect")
.attr("width", 15)
.attr("height", 100)
.style("fill", "url(#legendGradient)");

legend.append("g")
.attr("transform", "translate(15,0)")
.call(legendAxis);

const zoomBehavior = d3.zoom()
.scaleExtent([1, 8])
.on('zoom', event => mapGroup.attr('transform', event.transform));

svgElement.call(zoomBehavior);

return svgElement.node();
}
Insert cell
Insert cell
viewof sex3 = Inputs.select([].concat(Array.from([...new Set(data.map(d => d.sexe))])), { label: "Choisissez le sexe à étudier", value: 0 });
Insert cell
viewof calendrier_debut_3 = Inputs.date(
{
min: d3.min(Array.from(new Set(data.map(d => d.jour)))),
max: d3.max(Array.from(new Set(data.map(d => d.jour)))),
value: "2021-09-12" ,
label: "Date de début"
}
)
Insert cell
viewof calendrier_fin_3 = Inputs.date({
min: calendrier_debut_3, // Minimum is linked to debut
max: d3.max(Array.from(new Set(data.map(d => d.jour)))),
value: "2021-09-19", // Or some default value after the debut
label: "Date de fin"
});
Insert cell
map_interactive3(d3,calendrier_debut_3, calendrier_fin_3, departements, data, width, height, sex3)
Insert cell
function map_interactive3(d3, calendrierDebut, calendrierFin, france, covid, width, height, sexe_select) {
const mapWidth = width;
const mapHeight = height;
const hospValues = Array.from(new Set(covid.map(item => item.hosp)));
const sexes = Array.from(new Set(covid.map(d => d.sexe)));

// Gestion du sexe
const sexs = sexes.indexOf(sexe_select); // Assurez-vous que 'sex' est défini globalement ou passé en paramètre

const svgElement = d3.create("svg")
.attr("viewBox", [0, 0, width, mapHeight])
.style("width", "100%")
.style("height", "auto")
.style("background-color", "white");

const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("background", "white")
.style("border", "1px solid black")
.style("border-radius", "5px")
.style("padding", "5px")
.style("display", "none");

const mapGroup = svgElement.append('g').attr("class", "topg");

const foreground = svgElement.append("g").attr("class", "foreground");

const title = foreground.append("text")
.attr("x", mapWidth / 2)
.attr("y", 30)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.style("font-weight", "bold")
.text("Carte des hospitalisations COVID par département");

mapGroup.selectAll('path')
.data(france.features)
.enter().append('path')
.attr('d', path)
.style('fill', d => {
for (let i = 0; i < france.features.length; i++) {
let totalHosp = 0;
let totalRea = 0;
let totalConv = 0;
let totalSoins = 0;
let departement = france.features[i].properties.code;
let data = covid.filter(d =>
d.dep == departement &&
d.sexe == sexs && // Filtre par sexe
new Date(d.jour) >= calendrierDebut && // Filtre date de début
new Date(d.jour) <= calendrierFin // Filtre date de fin
);
if (data.length > 0) {
totalHosp += data.reduce((sum, item) => sum + item.hosp, 0); // Somme des hosp pour le département
totalRea += data.reduce((sum, item) => sum + item.rea, 0);
totalConv += data.reduce((sum, item) => sum + item.HospConv, 0);
totalSoins += data.reduce((sum, item) => sum + item.SSR_USLD, 0);
}
france.features[i].properties.totalHosp = totalHosp // Stocke la somme pour chaque département
france.features[i].properties.totalRea = totalRea
france.features[i].properties.totalConv = totalConv
france.features[i].properties.totalSoins = totalSoins
}
const maxHosp = d3.max(france.features, d => d.properties.totalHosp);
const colorScale = maxHosp === undefined || maxHosp === 0 ?
d3.scaleSequential(d3.interpolateOrRd).domain([0, 1]) :
d3.scaleSequential(d3.interpolateOrRd).domain([0, maxHosp]);
if (d.properties.totalHosp > 0) {
return colorScale(d.properties.totalHosp);
} else {
return '#ccc';
}
})
.style('stroke', 'white')
.attr("stroke-width", 0.5)
.attr("stroke-opacity", 0.6)
.on("mouseover", function (event, d) {
tooltip.style("display", "block")
.html(`<div style="font-size: 14px; font-weight: bold;">${d.properties.nom}</div>` +
`${d.properties.totalHosp} hospitalisations <br/>` +
`${d.properties.totalRea} individus en réanimation <br/>` +
`${d.properties.totalConv} individus en convalescence <br/>` +
`${d.properties.totalSoins} individus en soins continus et en récupération`);
d3.select(this).style("stroke", "black");
mapGroup.selectAll('path').style("opacity", e => e === d ? 1 : 0.5);
})
.on("mousemove", function (event) {
tooltip.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 10) + "px");
})
.on("mouseout", function () {
tooltip.style("display", "none");
d3.select(this).style("stroke", "none");
mapGroup.selectAll('path').style("opacity", 1);
});
const maxHosp = d3.max(france.features, d => d.properties.totalHosp);
const colorScale = maxHosp === undefined || maxHosp === 0 ?
d3.scaleSequential(d3.interpolateOrRd).domain([0, 1]) :
d3.scaleSequential(d3.interpolateOrRd).domain([0, maxHosp]);
const legend = svgElement.append("g")
.attr("transform", `translate(${mapWidth - 150}, ${mapHeight - 200})`);

const legendScale = d3.scaleLinear()
.domain(colorScale.domain())
.range([100, 0]);

const legendAxis = d3.axisRight(legendScale).ticks(5);

const gradient = svgElement.append("defs")
.append("linearGradient")
.attr("id", "legendGradient")
.attr("x1", "0%").attr("y1", "0%")
.attr("x2", "0%").attr("y2", "100%");

gradient.selectAll("stop")
.data(d3.range(0, 1.1, 0.1))
.enter().append("stop")
.attr("offset", d => `${d * 100}%`)
.attr("stop-color", d => colorScale(legendScale.invert(d * 100)));

legend.append("rect")
.attr("width", 15)
.attr("height", 100)
.style("fill", "url(#legendGradient)");

legend.append("g")
.attr("transform", "translate(15,0)")
.call(legendAxis);

const zoomBehavior = d3.zoom()
.scaleExtent([1, 8])
.on('zoom', event => mapGroup.attr('transform', event.transform));

svgElement.call(zoomBehavior);

return svgElement.node();
}
Insert cell
Insert cell
viewof sex4 = Inputs.select([].concat(Array.from([...new Set(data.map(d => d.sexe))])), { label: "Choisissez le sexe à étudier", value: 0 });
Insert cell
Insert cell
Insert cell
map_interactive4(d3, calendrier_debut_4, calendrier_fin_4, departements, data, width, height, sex4, path)
Insert cell
function map_interactive4(d3, calendrierDebut, calendrierFin, france, covid, width, height, sex, path) {
const mapWidth = width;
const mapHeight = height;
const sexes = Array.from(new Set(covid.map(item => item.sexe)));
const sexIndex = sexes.indexOf(sex);

const svgElement = d3.create("svg")
.attr("viewBox", [0, 0, width, mapHeight])
.style("width", "100%")
.style("height", "auto")
.style("background-color", "white");

const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("background", "white")
.style("border", "1px solid black")
.style("border-radius", "5px")
.style("padding", "5px")
.style("display", "none");

const mapGroup = svgElement.append('g').attr("class", "topg");

const foreground = svgElement.append("g").attr("class", "foreground");

const title = foreground.append("text")
.attr("x", mapWidth / 2)
.attr("y", 30)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.style("font-weight", "bold")
.text("Carte des hospitalisations COVID par département");

france.features.forEach(feature => {
let departement = feature.properties.code;
let data = covid.filter(c =>
c.dep == departement &&
c.sexe == sexIndex && // Use sexIndex here
new Date(c.jour) >= calendrierDebut &&
new Date(c.jour) <= calendrierFin
);
feature.properties.totalHosp = data.reduce((sum, item) => sum + item.hosp, 0);
});

const maxHosp = d3.max(france.features, d => d.properties.totalHosp);
const colorScale = maxHosp === undefined || maxHosp === 0 ?
d3.scaleSequential(d3.interpolateOrRd).domain([0, 1]) :
d3.scaleSequential(d3.interpolateOrRd).domain([0, maxHosp]);
const legend = svgElement.append("g")
.attr("transform", `translate(${mapWidth - 150}, ${mapHeight - 200})`);

mapGroup.selectAll('path')
.data(france.features)
.enter().append('path')
.attr('d', path)
.style('fill', d => colorScale(d.properties.totalHosp))
.style('stroke', 'white')
.attr("stroke-width", 0.5)
.attr("stroke-opacity", 0.6)
.on("mouseover", function (event, d) {
tooltip.style("display", "block")
.html(""); // Clear previous tooltip content

let departement = d.properties.code;
let graphData = covid.filter(c =>
c.dep === departement &&
c.sexe === sexIndex && // Use sexIndex here
new Date(c.jour) >= calendrierDebut &&
new Date(c.jour) <= calendrierFin
);

const scatterplotData = graphData.map(item => ({
x: new Date(item.jour),
y: item.hosp
}));

const tooltipWidth = 250;
const tooltipHeight = 150;

const svg = d3.create("svg")
.attr("width", tooltipWidth)
.attr("height", tooltipHeight);

tooltip.node().appendChild(svg.node());

create_linechart(svg, scatterplotData, tooltipWidth, tooltipHeight, "x", "y");

d3.select(this).style("stroke", "black");
mapGroup.selectAll('path').style("opacity", e => e === d ? 1 : 0.5);
})
.on("mousemove", function (event) {
tooltip.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 10) + "px");
})
.on("mouseout", function () {
tooltip.style("display", "none");
d3.select(this).style("stroke", "white"); // Reset stroke color
mapGroup.selectAll('path').style("opacity", 1);
});
const legendScale = d3.scaleLinear()
.domain(colorScale.domain())
.range([100, 0]);

const legendAxis = d3.axisRight(legendScale).ticks(5);

const gradient = svgElement.append("defs")
.append("linearGradient")
.attr("id", "legendGradient")
.attr("x1", "0%").attr("y1", "0%")
.attr("x2", "0%").attr("y2", "100%");

gradient.selectAll("stop")
.data(d3.range(0, 1.1, 0.1))
.enter().append("stop")
.attr("offset", d => `${d * 100}%`)
.attr("stop-color", d => colorScale(legendScale.invert(d * 100)));

legend.append("rect")
.attr("width", 15)
.attr("height", 100)
.style("fill", "url(#legendGradient)");

legend.append("g")
.attr("transform", "translate(15,0)")
.call(legendAxis);

const zoomBehavior = d3.zoom()
.scaleExtent([1, 8])
.on('zoom', event => mapGroup.attr('transform', event.transform));

svgElement.call(zoomBehavior);


return svgElement.node();
}



Insert cell
function create_linechart(svg, data, width, height, xAccessor, yAccessor) {
const margin = { top: 20, right: 40, bottom: 50, left: 45 },
plotWidth = width - margin.left - margin.right,
plotHeight = height - margin.top - margin.bottom;

const g = svg.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);

const xScale = d3.scaleTime()
.domain(d3.extent(data, d => d[xAccessor]))
.range([0, plotWidth]);

const yScale = d3.scaleLinear()
.domain(d3.extent(data, d => d[yAccessor]))
.range([plotHeight, 0]);

const dateFormatter = d3.timeFormat("%d-%m-%y");
const totalHospitalizations = d3.sum(data, d => d[yAccessor]);

g.append("text")
.attr("x", plotWidth / 2) // Center horizontally
.attr("y", 0 - margin.top / 2) // Position at the top, above the chart
.attr("text-anchor", "middle")
.style("font-size", "0.9rem") // Adjust font size as needed
.style("font-weight", "bold")
.text(`Somme: ${totalHospitalizations}`);
g.append("rect")
.attr("width", plotWidth)
.attr("height", plotHeight)
.attr("fill", "#f0f0f0");

g.append("g")
.attr("transform", `translate(0,${plotHeight})`)
.call(d3.axisBottom(xScale)
.ticks(data.length <= 14 ? d3.timeDay.every(2) : d3.timeWeek.every(1))
.tickFormat(dateFormatter))
.selectAll("text")
.attr("transform", "rotate(-45)")
.style("font-size", "0.6rem")
.style("text-anchor", "end");

g.append("text")
.attr("transform", `translate(${plotWidth / 2},${plotHeight + margin.top + 20})`)
.style("font-size", "0.7rem")
.style("text-anchor", "middle")
.text("Date");

g.append("g")
.call(d3.axisLeft(yScale)
.ticks(5)
.tickFormat(d3.format("d"))
.tickSize(-plotWidth)
.tickPadding(10))
.selectAll("line")
.style("stroke-opacity", 0.5)
.style("shape-rendering", "crispEdges");

g.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left + 5)
.attr("x", 0 - (plotHeight / 2))
.attr("dy", "1em")
.style("font-size", "0.7rem")
.style("text-anchor", "middle")
.text("Hospitalisations");

// Line path
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 2)
.attr("d", d3.line()
.x(d => xScale(d[xAccessor]))
.y(d => yScale(d[yAccessor])));


// Tooltip interaction (optional, but often useful for line charts)
const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0)
.style("position", "absolute")
.style("background", "white")
.style("border", "1px solid #ccc")
.style("padding", "5px")
.style("pointer-events", "none"); // So tooltip doesn't block mouse events

g.selectAll(".dot") // Keep dots for hover effect
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("cx", d => xScale(d[xAccessor]))
.attr("cy", d => yScale(d[yAccessor]))
.attr("r", 3)
.style("fill", "steelblue")
.style("opacity", 0.7)
.on("mouseover", (event, d) => {
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(`${dateFormatter(d[xAccessor])}: ${d[yAccessor]}`)
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 10) + "px");
})
.on("mouseout", () => {
tooltip.transition()
.duration(500)
.style("opacity", 0);
});
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more