Published
Edited
Jan 10, 2021
1 star
Insert cell
Insert cell
Insert cell
vote_map_population_bubble = {
const height = (width * 5) / 8;

const svg = d3
.select(DOM.svg(width, height))
.attr("viewBox", "0 0 960 600")
.style("width", "100%")
.style("height", "auto");
var defs = svg.append("defs");

var filter = defs
.append("filter")
.attr("id", "drop-shadow")
.attr("height", "130%");

// SourceAlpha refers to opacity of graphic that this filter will be applied to
// convolve that with a Gaussian with standard deviation 3 and store result
// in blur
filter
.append("feGaussianBlur")
.attr("in", "SourceAlpha")
.attr("stdDeviation", 6)
.attr("result", "blur");

// translate output of Gaussian blur to the right and downwards with 2px
// store result in offsetBlur
filter
.append("feOffset")
.attr("in", "blur")
.attr("dx", 2)
.attr("dy", 2)
.attr("result", "offsetBlur");

// overlay original SourceGraphic over translated blurred opacity by using
// feMerge filter. Order of specifying inputs is important!
var feMerge = filter.append("feMerge");

feMerge.append("feMergeNode").attr("in", "offsetBlur");
feMerge.append("feMergeNode").attr("in", "SourceGraphic");

svg
.append('rect')
.attr('width', width / 1.5)
.attr('x', 100)
.attr('y', 10)
.attr('height', height * 0.95)
// .attr('stroke', '#546767')//#FFF8E7
.attr('stroke', '#FFF8E7') //
.attr('stroke-width', 4)
.style("filter", "url(#drop-shadow)")
.attr('fill', 'none');

svg
.append('rect')
.attr('width', width / 1.5)
.attr('x', 100)
.attr('y', 10)
.attr('height', height * 0.95)
.attr('fill', '#FFF8E7');

const rovinj = [13.732390615654477, 45.02254149187571];

const legend = svg
.append("g")
.attr("fill", "#777")
.attr("transform", "translate(500,300)")
.attr("text-anchor", "middle")
.style("font", "7px sans-serif")
.selectAll("g")
.data(radiusScale.ticks(3).slice(1))
.join("g");

legend
.append("circle")
.attr("fill", "none")
.attr("stroke", "#ccc")
.attr("cy", d => -radiusScale(d))
.attr("r", radiusScale);

legend
.append("text")
.attr("y", d => -2 * radiusScale(d))
.attr("dy", "1.3em")
.text(radiusScale.tickFormat(4, "s"));

svg
.append('text')
.attr('x', 100 + 20)
.attr('y', 40)
.attr('fill', '#546767')
.attr('text-anchor', 'start')
.attr('font-size', 24)
.style('opacity', 1)
.text(`Predsjednički izbori 2020. (drugi krug)`);

svg
.append('text')
.attr('x', 100 + 20)
.attr('y', 65)
.attr('fill', '#546767')
.attr('text-anchor', 'start')
.attr('font-size', 20)
.style('opacity', 1)
.text(`Razlika u glasovima KGK-Zoky`);

let credit = svg
.append('text')
.attr('x', projection(rovinj)[0] - 20) // rovinj width / 2 + 100
.attr('y', projection(rovinj)[1]) //height / 2
.attr('fill', '#546767')
.attr('text-anchor', 'end')
.attr('font-size', 10)
.style('opacity', 1)
.text(`@velimirgasp`);

const paths = svg
.selectAll('path')
.data(topojson.feature(croatia, croatia.objects['hrvatska']).features)
.enter()
.append('path')
.attr('fill', 'white')
.attr('stroke', 'lightgrey')
.attr("stroke-linejoin", "round")
.attr('d', path);

svg
.append("g")
.selectAll("circle")
.data(municipalities)
.enter()
.append("circle")
.attr('opacity', 0.5)
.attr("fill", county => {
if (county.properties.votes.kgk < county.properties.votes.zoky) {
return '#c93135';
} else {
return '#1375b7';
}
})
.attr("cx", d => (d.properties.centroid ? d.properties.centroid[0] : 0))
.attr("cy", d => (d.properties.centroid ? d.properties.centroid[1] : 0))
.attr("r", d => d.properties.radius)
.style("stroke", "white")
.style('stroke-width', 0.4);

return svg.node();
}
Insert cell
Insert cell
jlsData = d3.csvParse(await FileAttachment('jls@1.csv').text(), d3.autoType)
Insert cell
municipalities = topojson
.feature(croatia, croatia.objects.hrvatska)
.features.map(municipality => {
const { population } = populations.find(
p => p.id === municipality.properties.ID_2
);

const name = `${municipality.properties.NAME_2}`;
const votingDatum = votingData.find(
d => d.gropNaziv.toUpperCase() == name.toUpperCase()
);

const jlsDatum = jlsData.find(
d => d.jls.toUpperCase() == name.toUpperCase()
);

let kgkWins = true;
if (votingDatum && votingDatum.diff < 0) kgkWins = true;

var diff = 0;
if (votingDatum) diff = votingDatum.diff;
diff = Math.abs(diff);

return {
...municipality,
properties: {
name,
//state: state.properties.name,
votes: { ...votingDatum },
jls: { ...jlsDatum },
population,
// density: population / municipality.properties.ALAND * 1e6,
centroid: projection(
turf.centroid(municipality.geometry).geometry.coordinates
),
radius: radiusScale(diff),
blueWin: kgkWins
// radius: radiusScale(population)
}
};
})
.filter(c => c.properties.centroid)
//.filter(c => c.geometry.type === "MultiPolygon")
.sort((a, b) =>
a.properties.centroid[0] < b.properties.centroid[0] ? -1 : 1
)
.map((d, i) => {
let geometry;
if (d.geometry.type !== "MultiPolygon") {
geometry = d.geometry;
} else {
geometry = {
type: d.geometry.type,
coordinates: d.geometry.coordinates
.sort((a, b) =>
turf.area(turf.polygon(a)) > turf.area(turf.polygon(b)) ? -1 : 1
)
.slice(0, 1)
};
}
return {
...d,
rank: i,
geometry
};
})
Insert cell
Insert cell
Insert cell
projection = d3
.geoAlbers()
.rotate([-15, 0])
.fitExtent(
[[20, 70], [width * 0.9, height * 0.9]],
topojson.feature(croatia, croatia.objects['hrvatska'])
)
Insert cell
Insert cell
populations.filter(d => d.found == false)
Insert cell
populations = {
let retval = new Array();
croatia.objects.hrvatska.geometries.forEach(opcina => {
let opcinaFound = populationData.find(
d => d.Name.toUpperCase() == opcina.properties.NAME_2.toUpperCase()
);

retval.push({
id: opcina.properties.ID_2,
name: opcina.properties.NAME_2,
found: opcinaFound ? true : false,
population: opcinaFound ? opcinaFound.Population : 0
});
});
return retval;
}
Insert cell
// populations.filter(d => d.found == false)
Insert cell
// glas = izbori.find(d=>d.gropNaziv.toUpperCase()=='Zagreb'.toUpperCase())
Insert cell
izbori = {
let retval = JSON.parse(await FileAttachment("izbori@7.json").text());
return retval;
}
Insert cell
// votingData.filter(d => d.zupNaziv != "" && d.gropNaziv == "")
Insert cell
Insert cell
Insert cell
// stanovnistvo = {
// let retval = d3.csvParse(await FileAttachment("hrvatska.stanovnistvo.2011@4.csv").text(), d3.autoType)
// let zagreb = 0;
// retval.filter(d=>d.county == 'Grad Zagreb').forEach(cetvrt=>{
// zagreb += cetvrt.population;
// })
// retval = retval.filter(d => d.county != 'Grad Zagreb')
// retval.push({
// county: 'Grad Zagreb',
// denomination: 'Grad',
// name: 'Zagreb',
// population: zagreb,
// });
// return retval
// }
Insert cell
populationData = d3.csvParse(
await FileAttachment('stanovnistvo_povrsina@2.csv').text(),
d3.autoType
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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