Public
Edited
Mar 13, 2023
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof hr = Inputs.range([0, 10], {label: "Height", step: 2, value:6})
Insert cell
Insert cell
viewof bgcmode = Inputs.radio(["Light", "Dark", "Free"], {group: "mode", label: "Background Theme", value: "Light"})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof maplegend_toggle = Inputs.radio(["ON", "OFF"], {group: "mode", label: "Toggle Legend (map)", value: "OFF"})
Insert cell
Insert cell
Insert cell
viewof mode = Inputs.radio(["Libre", "Fitted (default)", "Zoom sur France"], {group: "mode", label: "Select Mode", value: "Fitted (default)"})
Insert cell
viewof scaleprojec = Inputs.range([100, 3000], {label: "Scale", step: 1, value:820})
// range = Inputs.range([100, 3000], {label: "Scale", step: 1})
Insert cell
viewof centerx = Inputs.range([0, 30], {label: "Center X", step: 0.0001, value:27.121})
// centerx = Inputs.range([0, 100], {label: "Center X", step: 0.0001})
Insert cell
viewof centery = Inputs.range([35, 75], {label: "Center Y", step: 0.0001, value: 74.4784})
// centery = Inputs.range([0, 90], {label: "Center Y", step: 0.0001})
Insert cell
width_tooltip_pie = 400
Insert cell
viewof pieform = Inputs.form({
list: Inputs.checkbox(feature_waste_liste, {label: "Type de déchet", value: refresh}),
// year: Inputs.select(feature_year_liste, {label: "Select year"}),
year : Inputs.range(d3.extent(feature_year_liste), {label: "Année", step: 2}),
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{ const years = [...new Set(d3.map(data_eu_raw, d => d.TIME_PERIOD))];
for (var i = 0; i < geojson.features.length; i++) {
geojson.features[i].waste =new Object();
for (var year_ind = 0; year_ind < years.length; year_ind++) {
geojson.features[i].waste[years[year_ind]] = new Object();
}
};
for (var j = 0; j < data_eu_raw.length; j++) {
var country = data_eu_raw[j].geo.substring(0,2);
var year = data_eu_raw[j].TIME_PERIOD;
var index = geojson.features.findIndex((d) => d.id == country);
if( index > -1){
geojson.features[index].waste[year][data_eu_raw[j].waste.split(":")[0]] = data_eu_raw[j].OBS_VALUE;
}
}

}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
geomap = (data, projection) => {
let map_bg = map_cbg
if(bgcmode == "Light"){
map_bg = cbg_light;
}
if(bgcmode == "Dark"){
map_bg = cbg_dark;
}
const missing_data_color = "#D0D0D0" // "#231F20";

var div = d3.create('div')
const svg = div.append("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.style("background-color", map_bg),
color = d3.scaleOrdinal()
// .domain()
.domain([0, country_with_data.length])
.range(all_colors),
// color = d3.scaleQuantize().domain([0, 1]).range(d3.schemeRdPu[5]),
path = d3.geoPath()
.projection(projection),
bounds = path.bounds(data),
margin = {top: 25, right: 35, bottom: 35, left: 45},
legend = {
sym:{
width: 105, height: -7, font_size: 10, size: 8
},
caption:{
width: 90, height: 0
},
step: 25
}

var color2 = d3
.scaleSequential()
.interpolator(d3.interpolateYlOrRd);

var max = 0,
min = 1E9;

var keys_country = Object.keys(filteredgetWasteByCountryYears)
console.log(keys_country)
for (var i = 0; i < keys_country.length; i++){
for (var j=0; j < filteredgetWasteByCountryYears[keys_country[i]].length; j++){
if (filteredgetWasteByCountryYears[keys_country[i]][j].year == pieform.year){
let total = filteredgetWasteByCountryYears[keys_country[i]][j].TOTAL
if ( total> max) {
max = total
}
else if (total != 0 && total < min)
min = total
}
}
}

color2.domain([min, max]);

// country label
const defaultText = 'Union Européenne',
infoText = svg
.append('g')
.attr("font-family", "EB Garamond")
.attr("font-size", 30)
.attr("fill", "#222")
.attr('transform', 'translate(20,50)')
.append('text');
infoText.text(defaultText);


// Ajout du Tooltip
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("visibility", "hidden")
.attr("class", "tooltip")
.style("border-radius", "5%")
.style("z-index", "8")
.style("font-family", "Lato")
.style("padding", "0.7% 1%")
.style("min-width", `${width_tooltip_pie-50}px`)
.style("max-width", `${width_tooltip_pie+50}px`)
.style("min-height", `${width_tooltip_pie/2}px`)
.style("max-height", "300px")
.style("height", "auto")
.style("background", "lightgray")

svg.selectAll("path")
.data(data.features)
.join("path")
.attr("d", path)
.attr('class', 'country')
.attr("fill", "#000")
.attr("stroke", d => handle_map_stroke(d))
.style("fill", (d,i) => handle_map_fill(d,i))
.on("click", (d,e) => handle_map_onClick(d,e))
.on('mouseover', (e,d) => showTooltip(e,d))
.on('mouseout', function(d) {
d3.select('h2').text(defaultText);
infoText.text(defaultText);
tooltip.style("visibility", "hidden");
});

const graticules = svg
.append("path")
.attr("fill", "none")
.attr("opacity", "0.3")
.attr("stroke", gratsC);
graticules.attr("d", path(d3.geoGraticule().step([20, 20])()));

// //Labels centrés sur le pays
if(maplegend_toggle == "ON"){
let hors_eu = true;
svg
.selectAll(".countryLabel")
.data(data.features)
.enter()
.append("text")
.attr("class", d => `countryLabel ${d.id}`)
.attr("transform", d => `translate(${path.centroid(d)})`)
.text(d => {
if (!hors_eu)
return d.id
if (!country_with_data.includes(d.id))
return d.id
})
.style("fill", "#000475")
}


const box_size = {x:40, y:25}

svg.append("rect")
.attr("id", "box_missing_data_box")
.attr("x", margin.left)
.attr("y", height - margin.bottom + legend.sym.height)
.attr("width", box_size.x)
.attr("height", box_size.y)
.attr("fill", missing_data_color);

// Append the text caption
svg.append("text")
.attr("class", "capt_missing_data_box")
.attr("x", margin.left + legend.sym.size + 40)
.attr("y", height - margin.bottom + legend.sym.height + 17)
.attr("font-size", "0.8em")
.attr("font-family", "GB Garamond")
.attr("fill", "black")
.text("Données manquantes");

// #############

const width2 = width - margin.left - margin.right

const height2 = height/3 - margin.top - margin.bottom;

var svg2 = div.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height/3 + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");

// List of subgroups = header of the csv files = soil condition here
var subgroups = selected_country
// List of groups = species here = value of the first column called group -> I show them on the X axis
var groups = pieform.list


// Add X axis
var x = d3.scaleBand()
.domain(groups)
.range([0, width2-50])
.padding([0.1])
svg2.append("g")
.attr("transform", "translate(20," + height2 + ")")
.call(d3.axisBottom(x).tickSize(0));

// Find maximum value for the selected country on the selected waste :

var max_value = 0
var current_value = 0
for (var i = 0; i < selected_country.length; i++){
for (var j = 0; j < pieform.list.length; j++){
for (var k = 0; k < groupKey.length; k++){
if (data_eu_by_waste_final[k].waste == pieform.list[j]){
current_value = data_eu_by_waste_final[k][selected_country[i]]
if(current_value > max_value){
max_value = current_value
}
}
}
}
}
// Add Y axis
var y = d3.scaleLinear()
.domain([0, max_value])
.range([ height2, 0 ]);
svg2.append("g")
.attr("transform", "translate(20,0)")
.call(d3.axisLeft(y));

// Another scale for subgroup position?
var xSubgroup = d3.scaleBand()
.domain(subgroups)
.range([0, x.bandwidth()])
.padding([0.05])

// color palette = one color per subgroup
var color2 = d3.scaleOrdinal()
.domain(subgroups)
.range(['#e41a1c','#377eb8','#4daf4a'])

var c = d3.scaleQuantize().domain([0, 1]).range(d3.schemeRdPu[5])

// Show the bars

svg2.append("g")
.selectAll("g")
// Enter in data = loop group per group
.data(data_eu_by_waste_final)
.enter()
.append("g")
.attr("transform", function(d) { return "translate(" + x(d.waste) + ",0)"; })
.selectAll("rect")
.data(function(d) { return subgroups.map(function(key) { return {key: key, value: d[key]}; }); })
.enter().append("rect")
.attr("x", function(d) {return xSubgroup(d.key) + 20; })
.attr("y", function(d) {return y(d.value) - margin.bottom - margin.top - 0.5;})
.attr("width", xSubgroup.bandwidth())
.attr("height", function(d) { return height/3 - y(d.value); })
.attr("fill", function(d) { if (d.value == 0) { return "white" } else {return color(d.key);}});

svg2.selectAll("rect2")
.data(selected_country)
.enter()
.append("rect")
.attr("id", "leg_box")
.attr("x", width - legend.sym.width)
.attr("y", (d,i) => margin.top +(legend.step* i)+ legend.sym.height)
.attr("width", legend.sym.size)
.attr("height", legend.sym.size)
.attr("fill", (d,i) => { return color(d)
//country_with_data.includes(d.id) ? color2(filteredgetWasteByCountryYears[d.id][1].TOTAL) : "black"
})
svg2.selectAll("#text")
.data(selected_country)
.enter()
.append("text")
.attr("class", "leg_capt")
.attr("x", width - legend.caption.width)
.attr("y", (d,i) => margin.top + (legend.step * i) + legend.caption.height )
.attr("font-size", legend.sym.font_size)
.attr("fill", "black")
.text(d=>d)

//

function handle_map_stroke(d) {
if (country_with_data.includes(d.id))
return "#616161"
else
return "#eee"
}

function handle_map_onClick(d,e){
tooltip.style("visibility", "hidden");
let country_name = e.id;
let active = country_with_data.includes(country_name)
if(active){
add_country(d, color(e.id))
}
}

function showTooltip(event, d) {
if (country_with_data.includes(d.id)){
const country_name = d.properties.name;
let data_pie_chart = country_getTopXWaste(15, d.id);

const values = Array.from(d3.map(data_pie_chart, d => d.value)),
labels = Array.from(d3.map(data_pie_chart, d => d.code));

d3.select('h2').text(d.properties.name);
infoText.text(d.properties.name);
tooltip.html(`
<div>
<strong>${d.properties.Continent}</strong>
</div>
<div>Pays: ${d.properties.name}</div>
<div style="width:100%">
<svg viewBox="-110 -180 600 500", style="width: ${width_tooltip_pie}px">
${
pie_chart(values, labels, 1, width_tooltip_pie, piechart_top4(data_pie_chart), color, true).innerHTML
}
</svg>
</div>
`)
.style("left", Math.max(0, event.pageX + 20) + "px")
.style("top", Math.max(0, event.pageY - 20) + "px")
.style("background",'#FFFFFF')
.style("visibility", "visible");
}
}
function handle_map_fill(d,i){
if (country_with_data.includes(d.id)){
for (var i = 0; i < filteredgetWasteByCountryYears[d.id].length; i++){
if (filteredgetWasteByCountryYears[d.id][i].year == pieform.year)
return color2(filteredgetWasteByCountryYears[d.id][1].TOTAL)
}
}
else return missing_data_color;
//country_with_data.includes(d.id) ? color2(filteredgetWasteByCountryYears[d.id][1].TOTAL) : "black"
}

return div.node()
}
Insert cell
filteredgetWasteByCountryYears["FR"][1].TOTAL
Insert cell
filteredgetWasteByCountryYears["FR"]
Insert cell
viewof refreshN = Inputs.range([4, feature_waste_liste.length], {label: "Amount", step: 1, value: 15})
Insert cell
viewof refreshButton = Inputs.button("Refresh")
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
map_chart_cschema = null // GRADIENT SCHEMA POUR COMPARER LES PLUS GROS PRODUCTEURS
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
country_with_data = [...new Set(d3.map(data_eu_raw, d => d.geo.split(":")[0]))]
Insert cell
hardcoded_feature_reference = geojson.features[6] //to clean up
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more