Public
Edited
Jan 4, 2023
1 fork
1 star
Insert cell
energyData = FileAttachment("energyData.csv").csv({ typed: true })
Insert cell
import { aq, op } from '@uwdata/arquero'
Insert cell
energyArq = aq.from(energyData).select({
country: 'country',
year: 'year',
iso_code: 'iso_code',
gdp: 'gdp',
population: 'population',
renewables_share_energy: 'renewablesShareCon',
renewables_share_elec: 'renewablesShareGen',
})
.derive({ gdpPerCap : d => d.gdp/d.population})
.filter(
(d) =>
op.abs(d.gdp) >= 0 &&
op.abs(d.renewablesShareCon) >= 0
)
Insert cell
continentsData = FileAttachment("continents.csv").csv({ typed: true })
Insert cell
continentsClean = aq.from(continentsData).select({
Entity: 'country',
Code: 'iso_code',
Continent: 'continent',
})

// d => d.continent !== undefined
// .filter(d => op.is_nan(d.continent))
// isNaN(arr) === true
Insert cell
joinedData = energyArq.join_full(continentsClean).objects()
Insert cell
continents = new Set(joinedData.map(d => d.continent))
Insert cell
continentsArray = Array.from(continents).filter(d => d !== undefined);
Insert cell
viewof parameters = Inputs.form({
year: Inputs.range([1965, 2018], {label: "Year", value: 1965, step: 1}),
})
Insert cell
selectedYear = joinedData.filter(d => d.year===parameters.year);
Insert cell
Insert cell
chart = {
const svg = d3.create('svg')
.attr('viewBox', [0, -30, width, height]);

const tooltip = d3
.select("body")
.append("div")
.attr("class", "svg-tooltip")
.style("position", "absolute")
.style("visibility", "hidden")
.style('font-family', 'Helvetica')
.style('background', 'white')
.style('opacity', .9)
.style('border-radius', '.1rem')
.style('border', '0px solid black')
.style('color', 'black')
.style('display', 'block')
.style('font-size', '14px')
.style('max-width', '320px')
.style('padding', '.2rem .4rem')
.style('position', 'absolute');
svg.append('g').call(xAxis);
svg.selectAll('.line-consumption')
.data(x.ticks())
.join('line')
.attr('class', 'line-consumption')
.attr('x1', d => x(d))
.attr('x2', d => x(d))
.attr('y1', 10)
.attr('y2', height - margin.top +35)
.attr('stroke-width', .6)
.attr('stroke', 'lightgray');
svg.selectAll('.label-continents')
.data(continentsArray)
.join('text')
.attr('class', 'label-continents')
.attr('x', 0)
.attr('y', d => y(d))
.style('font-family', 'Helvetica')
.style('font-size', '12px')
.attr('text-align', 'right')
.attr('alignment-baseline', 'right')
.text(d => d);
const simulation = d3.forceSimulation(selectedYear)
.force('x', d3.forceX((d) => x(d.renewablesShareCon)).strength(0.3))
.force('y', d3.forceY((d) => y(d.continent)).strength(0.3))
.force('collide', d3.forceCollide(d => size(d.gdpPerCap)/1.5 + padding).strength(1))
.stop();
for(let i = 0; i < 300; i++) {
simulation.tick();
}
simulation.stop();

svg.selectAll('circle')
.data(selectedYear)
.join('circle')
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', d => size(d.gdpPerCap)/1.5)
.attr('fill', d => color(d.continent))
.attr('opacity', .8);

svg.selectAll("circle")
.on("mouseover", function(d) {
d3.select(this)
.attr('stroke-width', '1')
.attr("stroke", "black")
tooltip
.style("visibility", "visible")
.html(`<b>Country:</b> ${d.country} <br><b>GDP per cap: </b>${d.gdpPerCap.toLocaleString('en-US', {maximumFractionDigits: 2})}<br><b>% of primary energy renewables consumption:</b> ${d.renewablesShareCon.toLocaleString('en-US', {maximumFractionDigits: 2})}%`)
})
.on("mousemove", function() {
tooltip
.style("top", d3.event.pageY - 10 + "px")
.style("left", d3.event.pageX + 10 + "px")
})
.on("mouseout", function() {
d3.select(this).attr('stroke-width', '0');

tooltip.style("visibility", "hidden");
});
return svg.node();

}
Insert cell
Insert cell
y = d3.scaleBand()
.domain(continentsArray)
.range([height + margin.bottom -50, margin.top-50])
Insert cell
x = d3.scaleLinear()
.domain([0,100])
.nice()
.range([margin.left, width - margin.right])
Insert cell
xAxis = g => g
.attr('transform', `translate(0,${height +30 - margin.top})`)
.call(d3.axisBottom(x))
Insert cell
popExtent = {
const bounds = data.map((d) => d.visites).sort(d3.ascending);
return [bounds[0], bounds[bounds.length - 1]];
}
Insert cell
size = d3.scaleSqrt()
.domain(popExtent)
.nice()
.range([0.5, 5])
Insert cell
dataExtent = {
const bounds = data.map((d) => d.visites).sort(d3.ascending);
return [bounds[0], bounds[bounds.length - 1]];
}
Insert cell
color = d3.scaleOrdinal()
.domain(continentsArray)
.range(d3.schemeTableau10)
Insert cell
radius = 1
Insert cell
padding = 0.5
Insert cell
height = 1200
Insert cell
margin = ({
left: 120,
right: 120,
top: 100,
bottom: 0
})
Insert cell
d3 = require("d3@5")
Insert cell
import { style } from '@connorrothschild/styles'
Insert cell
import {form} from "@mbostock/form-input"
Insert cell
specificStyles = html`
<style>

.svg-tooltip {
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
background: white;
opacity: .9;
border-radius: .1rem;
border: 0px solid black;
color: black;
display: block;
font-size: 14px;
max-width: 320px;
padding: .2rem .4rem;
position: absolute;
text-overflow: ellipsis;
white-space: pre;
z-index: 300;
visibility: hidden;
}
</style>`
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