Public
Edited
Jun 1, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
ciudades.map(d => d[xAttrib])
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof maxX = slider({
min: 0.0001,
max: 0.1,
step: 0.0001,
value: 0.01
})
Insert cell
// swatches({color: colorScale})
legend({color: colorScale})
Insert cell
colorScale.domain()
Insert cell
aWeek = 7*24*3600*1000;
Insert cell
aWeekAgo = new Date()- aWeek
Insert cell
twoWeeksAgo = aWeekAgo - aWeek
Insert cell
daysChartSpec = {
console.log("vega");
const brush = vl
.selectInterval("date")
.encodings("x")
.init({ x: [twoWeeksAgo, aWeekAgo] });

return vl
.markBar({ tooltip: true })
.select(brush)
.data(countsByDate.filter(d => d.key <= maxDate))
.encode(
vl.x().fieldT("key"),
vl.y().fieldQ("value"),
vl.opacity().fieldQ("Confiabilidad")
)
.width(width - 200)
.toSpec();
}
Insert cell
onMouseMove = (canvas, selection, simulation) => {
console.log("mouse move");

// if (!d3.event.active) simulation.alphaTarget(0);

const mousePos = getMousePos(canvas, d3.event);

console.log("mouse pos", mousePos);

var node = simulation.find(mousePos.x, mousePos.y);
console.log("node", node);
if (node) highlightNode(node, selection);
}
Insert cell
//https://stackoverflow.com/questions/17130395/real-mouse-position-in-canvas
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}

Insert cell
highlightNode = function(node, svg) {
if (!node) return;
svg
// .attr("dy", chart.rAttr(node) * 2 + 15 + "px")
// .attr("dx", (chart.rAttr(node) * 2) + "px")
.style("left", node.x + "px")
.style("top", node.y + "px")
// .attr("transform", "translate(" + node.x + "," + node.y + ")")
.text( node.municipio);
}
Insert cell
drawNodes = (nodes, ctx) => {
const xd = xScale.domain();
for(let n of nodes) {
ctx.beginPath();
ctx.fillStyle= colorScale(n[colorBy]);
ctx.moveTo(n.x, n.y);
ctx.arc(n.x, n.y, n.r, 0, 2*Math.PI);
ctx.fill();
}

ctx.fillStyle="black";
ctx.textAlign="center";
ctx.beginPath();
for(let n of nodes) {
if (n.total_votantes>300000 || n.casos_por_votantes > (xd[1]-xd[0])/4) {
ctx.moveTo(n.x, n.y);
ctx.fillText(n.municipio, n.x, n.y);
// ctx.stroke();
}
}


}
Insert cell
margin = ({
left: 140,
right: 20,
top: 40,
bottom: 10
})
Insert cell
xScale = {
// daysSelected;
return (
d3
.scalePow()
.exponent(0.2)
// .domain(d3.extent(ciudades, d => d[xAttrib]))
.domain([0, maxX])
.range([margin.left, width - margin.right])
);
}
Insert cell
// yScale = {
// // daysSelected;
// // return d3.scaleLinear()
// return d3.scaleBand()
// .domain(d3.set(ciudades.map(d => d[groupBy])).values())
// // .domain(d3.extent(ciudades, d => d[groupBy] ))
// .range([margin.top, height-margin.bottom]);
// }
Insert cell
yScale = {
const deptos = d3.rollups(ciudades, v => d3.sum(v, e => e.total_votantes), d => d.departamento)
.sort((a,b) => b[1]-a[1]);
let sum = 0;
const deptosStacked = deptos.map(dep => {
const res = [
dep[0],
sum + dep[1]/2
];
sum+=dep[1];
return res;
});

const y = d3.scaleLinear().domain([0, sum]).range([margin.top, height-margin.bottom]);
return d3.scaleOrdinal()
.domain(deptosStacked.map(d=> d[0]))
.range(deptosStacked.map(d=> y(d[1])));
}
Insert cell
rScale = {
return d3.scalePow()
.exponent(0.5)
.domain([0, 5*10**6])
.range([r, 30]);
}
Insert cell
// colorScale = d3.scaleOrdinal(d3.schemeCategory10)
// .domain(d3.set(data.map(d => d[colorBy])).values())
colorScale = d3.scaleSequential(d3.interpolateOrRd).domain([0, maxX / 3])
// .domain([0 , d3.max(ciudades.map(d => d[colorBy]))/2])
Insert cell
Insert cell
countsByCity = {
console.log("compute data", daysSelected);
if (daysSelected && daysSelected.date) {
cs.fis.filter(daysSelected.date.key);
} else {
cs.fis.filter([twoWeeksAgo, aWeekAgo]);
}

return cs.cityGroup.all()
.filter(d => d.key)
// .map(d => {
// const ciudad = dCiudades.get(+d.key);
// if (ciudad)
// return {
// key: d.key,
// casos: d.value,
// ciudad: ciudad.municipio,
// depto: ciudad.departamento,
// total_votantes: ciudad.total_votantes,
// casos_por_votantes: d.value/ciudad.total_votantes,
// r: rScale(ciudad.total_votantes),
// c: ciudad
// };
// else
// console.log("ciudad no encontrada", d[0])
// })
}
Insert cell
countsByDate = cs.fisGroup.all()
.filter(d => d.key!=="Asintomático")
.map(d => ({...d, "Confiabilidad": d.key < aWeekAgo ? 1 : (new Date()-d.key)/aWeekAgo }))

Insert cell
cs = {
const cs = crossfilter(rawData);
cs.city = cs.dimension((d) => d.ciudad_municipio);
cs.fis = cs.dimension((d) => dateParse(d.fis));
cs.cityGroup = cs.city.group();
cs.fisGroup = cs.fis.group();
return cs;
}
Insert cell
crossfilter = require("crossfilter2")
Insert cell
height = 600
Insert cell
// rawData = loadSocrata("https://www.datos.gov.co/resource/gt2j-8ykr.csv", {
// progressive: false
// })
rawData = fetch(
"https://www.datos.gov.co/resource/gt2j-8ykr.csv?$order=id_de_caso DESC&$limit=50000"
)
.then((res) => res.text())
.then(d3.csvParse)
.then((res) => res.map((d) => ((d.fis = d["fecha_inicio_sintomas"]), d)))
Insert cell
dCiudades = new Map(rawCiudades.map(d => [d.dane, d]))
Insert cell
rawCiudades = FileAttachment("segunda_vuelta_presidencial.csv")
.text()
.then(res => d3.csvParse(res, d3.autoType))
.then(res => res.filter(d => {
d.alineacionPolitica = (d["iván duque"]-d["gustavo petro"])/d.total_votantes;
return d.departamento!=="Consulados"}
))
Insert cell
ciudades = {
const ciudades = rawCiudades;
countsByCity.forEach(d => {
const ciudad = dCiudades.get(+d.key);
if (!ciudad) {
console.log("Ciudad not found", d);
return;
}
ciudad.casos= d.value;
ciudad.casos_por_votantes= d.value/ciudad.total_votantes;

// ciudad.y=100;
// ciudad.r = rScale(ciudad.total_votantes);
// ciudad.x = xScale(ciudad[xAttrib])
// ciudad.y = yScale(ciudad[groupBy])
});

return ciudades;
}
Insert cell
// poblacion = FileAttachment("Departamentos_y_municipios_de_Colombia.csv").text().then(res => d3.csvParse(res, d3.autoType))
Insert cell
dateParse = d3.timeParse("%Y-%m-%d 00:00:00")
Insert cell
rawData.map((d) => dateParse(d.fis))
Insert cell
rawData.map((d) => d.fis)
Insert cell
// https://gist.github.com/callumlocke/cc258a193839691f60dd
function scaleCanvas(canvas, context, width, height) {
// assume the device pixel ratio is 1 if the browser doesn't specify it
const devicePixelRatio = window.devicePixelRatio || 1;

// determine the 'backing store ratio' of the canvas context
const backingStoreRatio = (
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1
);

// determine the actual ratio we want to draw at
const ratio = devicePixelRatio / backingStoreRatio;

if (devicePixelRatio !== backingStoreRatio) {
// set the 'real' canvas size to the higher width/height
canvas.width = width * ratio;
canvas.height = height * ratio;

// ...then scale it back down with CSS
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
}
else {
// this is a normal 1:1 device; just scale it simply
canvas.width = width;
canvas.height = height;
canvas.style.width = '';
canvas.style.height = '';
}

// scale the drawing context so everything will work at the higher ratio
context.scale(ratio, ratio);
}
Insert cell
import {slider, select, checkbox} from "@jashkenas/inputs"
Insert cell
import {swatches, legend} from "@d3/color-legend"
Insert cell
d3 = require("d3@6")
Insert cell
import {loadSocrata} from "@john-guerra/socrata-load-multiples-pages"
Insert cell
import {vl} from "@vega/vega-lite-api"
Insert cell
import { vegaSelected } from "@john-guerra/vega-selected"
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