Public
Edited
Apr 16, 2024
1 fork
Insert cell
Insert cell
Insert cell
import { slider, checkbox } from "@jashkenas/inputs"
Insert cell
import {Player} from "@oscar6echo/player"
Insert cell
import { style as faStyle } from "@airbornemint/fontawesome"
Insert cell
a = faStyle({ solid: true })
Insert cell
import {select} from "f5d4cba9b02532ea"
Insert cell
Insert cell
import {Text} from "@observablehq/inputs@426"
Insert cell
height = 600
Insert cell
width = 600
Insert cell
viewof año = slider({
title: "Año",
min: 2012,
max: 2022,
step: 1,
value: 2012,
})
Insert cell
Insert cell
// Data a visualizar

proyeccionNna1 = FileAttachment("comuna_anno@10.json").json()
Insert cell
año_opciones = [...new Set(proyeccionNna1.map(data => data.anno))]
Insert cell
dataFiltrada_nna = proyeccionNna1.filter(data => (data.anno === año))
Insert cell
Insert cell
mapanna = showMap_nna()
Insert cell
viewof mapa_nna = map(
dataFiltrada_nna,
proyeccionNna1,
createTooltip,
"Monto promedio renta por comuna", [0, 250000, 500000, 750000, 1000000, 1250000, 1500000, 1750000],
"proyeccionNna"
)
Insert cell
map = function map(data, dataColorScale, createTooltip, legendTitle, tickThresholds, maptype){
let {geoObj, mapProjection} = getMapConf(tipoMapa);
const svg = d3.create("svg")
.style("width", "100%")
.style("height", "80%")
.attr("viewBox", function() {
return tipoMapa === 'País' ? "0 200 650 300": "-300 0 1200 750";
})
// Legend
if (data && data.length) {
svg.append("g")
.attr("transform", function() {
return tipoMapa === 'País'? `translate(${width/2 - 60}, ${height - 200})`: `translate(${width/2 - 140}, ${height + 50}) `;
})
.append(() =>
legend({
color: color(dataColorScale, maptype),
title: legendTitle,
tickFormat: ".0f",
width: tipoMapa === 'País'? 200 : 380,
height: tipoMapa === 'País' ? 50 : 64,
titleFontSize: tipoMapa === 'País' ? "7px" : "14px",
titleFontWeight: "200",
tickFontSize: tipoMapa === 'País' ? "5px": "10px",
tickSize: tipoMapa === 'País' ? 8: 20,
tickWidth: tipoMapa === 'País' ? 0.7 : 1,
tickPos: tipoMapa === 'País' ? 4 : 7,
tickThresholds: tickThresholds,
roundedValues: false,
sin_info: true
})
);
}
// Tooltip
if (createTooltip) {
var div = d3
.select("body")
.append("div")
.attr("class", "arrow_box");
}
// Mapa
svg.append("g")
.selectAll("path")
.data(geoObj.geometries)
.enter()
.append("path")
//.attr("class", "decideChileMap")
.attr("class", function() {
return tipoMapa === 'País'? "decideChilePais": "decideChileRegion";
})
.attr("fill", d => map_color(d.properties.canonical_key, data, dataColorScale, tickThresholds, maptype))
.attr("d", d3.geoPath(mapProjection))
.attr('transform', function() {
return tipoMapa === 'País' ? 'rotate(-90 300 300)': null;
})
.on('mouseover', function (d, i) {
svg.selectAll("path")
.attr("fill-opacity", 0.2)
d3.select(this).transition()
.duration('25')
.attr("fill-opacity", 0.8)

//Tooltip
div.html(createTooltip(d, data, maptype))
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY + 20) + "px")
.style("box-shadow", "0 10px 16px 0 rgba(0,0,0,0.2),8px 6px 15px 0 rgba(0,0,0,0.19)")
.transition()
.duration('25')
.style("opacity", 1) ;
})
.on('mouseout', function (d) {
svg.selectAll("path")
.attr("fill-opacity", 0.8)
d3.select(this).transition()
.duration('25')

//Tooltip
div.transition()
.duration('25')
.style("opacity", 0);
});
return svg.node()
}
Insert cell
Insert cell
// URL base para descargar los mapas de DecideChile
mapBuildUrl = 'https://s3.amazonaws.com/staging.decidechile.cl/api/v1/maps/m.2020/20200320161219.a8ed46'
Insert cell
baseTopo = fetch(mapBuildUrl + '/t/base.topo.json').then(res => res.json())
Insert cell
res = fetch('https://d109f9uztt08nv.cloudfront.net/colunga/viz-colunga/topo-json-mapa/topo2@1.json')
Insert cell
topologia = res.json()
Insert cell
resGS = fetch('https://d109f9uztt08nv.cloudfront.net/colunga/viz-colunga/topo-json-mapa/GranSantiago3.json')
Insert cell
topologiaGS = resGS.json()
Insert cell
// A partir del mapa comunal detallado, genera un diccionario de region -> listado de comunas
comunasPorRegion = filterComunasBy('Region')
Insert cell
comunasPorProvincia = filterComunasBy('Provincia')
Insert cell
comunasPorPais = filterComunasBy('País')
Insert cell
// regiones = Object.keys(comunasPorRegion)
regiones = ["Región de Arica y Parinacota", "Región de Tarapacá", "Región de Antofagasta", "Región de Atacama", "Región de Coquimbo", "Región de Valparaíso", "Región Metropolitana de Santiago", "Región del Libertador Bernardo O'Higgins", "Región del Maule", "Región de Ñuble", "Región del Bío-Bío", "Región de La Araucanía", "Región de Los Ríos", "Región de Los Lagos", "Región de Aysén del Gral.Ibañez del Campo", "Región de Magallanes y Antártica Chilena"]
Insert cell
provincias = Object.keys(comunasPorProvincia).sort()
Insert cell
comunasPorPais.undefined
Insert cell
topos = ({
'Regional': filterTopologia(region, comunasPorRegion),
'País': filterTopologia('País', comunasPorPais.undefined)
})
Insert cell
comunasKey = ({
'Regional': comunasPorRegion[region],
'País': comunasPorPais
})
Insert cell
comunaList = comunasKey[tipoMapa]
Insert cell
Insert cell
showMap_nna = () => {
if (tipoMapa === 'País') {
return html`
<div class="map-container">
${viewof mapa_nna}
</div>`
}
return html`${viewof mapa_nna}`}
Insert cell
selectDiv_nna= () => {
if (tipoMapa === 'Regional')
{ return html`
<div class="grid-container-select">
<div class="item3">${viewof tipoMapa}</div>
<div class="item4">${viewof region}</div>
<div class="item3">${viewof año}</div>
</div>
`
}
else
{
return html`
<div class="grid-container-select">
<div class="item3">${viewof tipoMapa}</div>
<div class="item3">${viewof año}</div>
</div>`
}
}
Insert cell
viewof region = select({
selected: "Región Metropolitana de Santiago",
options: regiones,
onchange: objs => {
d3.select(objs.select)
//.style('background', '#EDEDED')
.on('end', () => objs.div.update(objs.select.value));
}
})
Insert cell
viewof tipoMapa = select({
options: [
'País',
'Regional',
// 'Provincial',
// 'Distrito',
]
});
Insert cell
Insert cell
Insert cell
//FileAttachment("dataset_exp.json").json()
Insert cell
// viewof file3 = Text({label: "File name", value: "dataset_exp.json"})
Insert cell
map_color = (comuna, data, dataScale, tickThresholds, maptype) => {

let val = data.find(el => el.comuna_key === comuna);
if (val.value == 0) {
console.log('el valor es cero')
return "#D2DCFA"
}
return Object.is(val.value, null) ? "#EDEDED" : color(dataScale, maptype,val.value, tickThresholds);
}
Insert cell
function color(data, maptype=undefined, val=false, tickThresholds=undefined) {
let bounds = tickThresholds === undefined ? dataBounds(data) : [tickThresholds[0], tickThresholds[tickThresholds.length - 1]]

if (maptype === 'm2') {
let scale = d3.scaleQuantize(bounds, [
"#d1e48f",
"#c9df7a",
"#c0da66",
"#b8d551",
"#b0d03c",
"#a3c42f",
"#8a9a25",
"#92af2a"
]) //get_colors(6, 'blue2', 1, 6))// get_colors(5, 'red'))
if (val) {
return scale(val)
}
return scale
}
if (maptype == 'proyeccionNna') {
let scale = d3.scaleQuantize(bounds, [
"#E8EDFC",
"#D2DCFA",
"#A6B9F5",
"#7996F1",
"#4D72EC",
"#2150E8",
"#1236ab"
])
if (val) {
return scale(val)
}
return scale
}
else {
let scale = d3.scaleQuantize(bounds, [
"#fcdb7a",
"#fbd461",
"#fbce48",
"#fac72f",
"#f9c016",
"#f0b506",
"#d7a305",
"#be8f05"
])
if (val) {
return scale(val)
}
return scale
}
}
Insert cell
function dataBounds(data){
return [d3.format('.2r')(Math.min.apply(Math, data.map(function(o) { return o.value; }))),
d3.format('.2r')(Math.max.apply(Math, data.map(function(o) { return o.value; })))]
}
Insert cell
function dataBounds2(data){
return [
d3.format('.2r')(Math.min.apply(Math, data.filter(
d => d[año] != 'Sin Información'
).map(
function(o) { return o[año]; }
))),
d3.format('.2r')(Math.max.apply(Math, data.filter(
d => d[año] != 'Sin Información'
).map(
function(o) { return o[año]; }
)))
]
}
Insert cell
getMapConf = (mapType) => {
const geoObj = getGeoObj(mapType);
const mapProjection = projection(geoObj);
return {
geoObj: geoObj,
mapProjection: mapProjection
}
}
Insert cell
getGeoObj = (mapType) => {
const topo = topos[mapType];
return {
type: 'GeometryCollection',
geometries: topo.geometries.map(comuna => {
const mesh = topo.extra? topojson.mesh(topologiaGS, comuna) : topojson.mesh(topologia, comuna);
return {
...mesh,
properties: {
canonical_key: comuna.properties.canonical_key,
centroid: d3.geoCentroid(mesh),
comuna: comuna.properties.comuna
}
}
})
}
}
Insert cell
filterTopologia = (filter, distList) => {
const geometries = topologia.objects.base.geometries
console.log(filter)
if (filter === "Gran Santiago"){
return {
type: 'GeometryCollection',
geometries: topologiaGS.objects.base.geometries,
extra: true
}
}

if (filter === "País"){
return {
type: 'GeometryCollection',
geometries: geometries.filter(
geom => distList.includes(geom.properties.canonical_key))
}
}

return {
type: 'GeometryCollection',
geometries: geometries.filter(
geom => distList[filter].includes(geom.properties.canonical_key))
}
}
Insert cell
filterComunasBy = (filter) => {
const reducer = (key) => {
return function reducer(accumulator, {properties}) {
const {canonical_key} = properties
const dist = properties[key]
if(accumulator[dist]) {
accumulator[dist].push(canonical_key)
} else {
accumulator[dist] = [canonical_key]
}
return accumulator
}
}
let comunas = baseTopo.objects.base.geometries.reduce(reducer(filter), {})

if (filter === 'Region'){
comunas["Gran Santiago"] = topologiaGS.objects.base.geometries.reduce(reducer(filter), {}).undefined}
return comunas
}
Insert cell
projection = (geom) => {
return d3.geoMercator().fitSize([width, height], geom)
}
Insert cell
Insert cell
<style>
@import url('${fonts['condensed']['url']}');

/* Grid container select */
.item3 {
grid-area: tipomapa;
min-width: 0;
min-height: 15;
}
.item4 {
grid-area: seleccion;
min-width: 0;
min-height: 15;
}

.item5 {
grid-area: genero;
min-width: 0;
min-height: 15;
}

.item6 {
grid-area: ano;
min-width: 15;
}

.grid-container-select {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
grid-gap: 20px;
}

/* Mapa */

.decideChileMap {
stroke:#FFFFFF;
stroke-linejoin: round;
}

.decideChilePais {
stroke:#FFFFFF;
stroke-linejoin: round;
stroke-width: 0.2;
}

.decideChileRegion {
stroke:#FFFFFF;
stroke-linejoin: round;
stroke-width: 1.5;
}

.map-container {
max-height: 750px;
}

/* Tooltip */

.arrow_box {
pointer-events: none;
font-family: ${fonts['default']['family']};
font-size: 13px;
padding: 8px 15px;
position: absolute;
background: #ffffff;
border-radius: 2px;
display: flex;
flex-direction: column;
}

strong {
border-bottom: 1px solid black;
font-family: ${fonts['default']['family']};
padding-bottom: 2px;
justify-content: center;
display: flex;
color: #1A1A1A;
font-weight: 900;
font-size: 13px;
}

.texto-subtitulo {
font-family: ${fonts['condensed']['family']};
color: #1A1A1A;
font-weight: 400;
font-size: 10px;
justify-content: center;
display: flex;
}

.texto-primario {
color: #000000;
font-family: ${fonts['default']['family']};
font-weight: 700;
font-size: 16px;
padding-top: 0px;
justify-content: center;
display: flex;
}

.texto-sin-informacion {
color: #CC0014;
font-family: ${fonts['condensed']['family']};
font-weight: 450;
font-size: 12px;
padding-top: 3px;
justify-content: center;
display: flex;
}

.texto-secundario {
color: #828282;
font-family: ${fonts['condensed']['family']};
font-size: 10px;
font-weight: 400;
justify-content: center;
display: flex;
}
.titulo_mapa {
color: #2150E8 ;
font-family: ${fonts['default']['family']};
font-weight: 900;
font-size: 24px;
padding-top: 0px;
justify-content: center;
display: flex;
}

</style>

Insert cell
d3 = require("d3@5", "d3-geo")
Insert cell
d3tip = require('d3-tip')
Insert cell
topojson = require("topojson-client")
Insert cell
import { get_secuential_colors, get_colors, fonts, colors, legend } from "981f894a8cb8875d"
Insert cell
import {filterComunas, getComunaData} from "87cac52600ff7ed8"
Insert cell
import {uniqueValid} from "@uwdata/data-utilities"
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