Published
Edited
Nov 19, 2020
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
colorscale(lookups.get("usa-" + date).income_per_person_long_series)
Insert cell
scale_life(70)
Insert cell
colorScale = d3.scaleOrdinal(d3.schemeCategory10).domain(country_feather.getColumn("REGION_UN"))
Insert cell
colorscale = d3.scaleSequentialLog(d3.interpolateViridis).domain([1, 1e6]).clamp(true)
Insert cell
colorscale(1)
Insert cell
size_scale = d3.scaleSqrt().domain([1, 2e9]).range([.01, .3]).clamp(true)
Insert cell
country_feather.getColumn("ADM0_A3_IS").toArray().filter(d => d=="USA")
Insert cell
draw_frame = function(date) {
// const overall_radius = jitter_radius / 100 * (Math.sin(Date.now()/1000) + 1)/2
const prop_list = []
let ix = -1
for (let feature of country_feather) {
ix += 1
const lookup = lookups.get(feature['ADM0_A3_IS'].toLowerCase() + "-" + date)
if (lookup===undefined) {
continue
}
const { REGION_WB } = feature;
let SCALE = size_scale(lookup.population_total/feature.pixel_area);
if (feature.vertices === null) {continue}
if (feature.coordinates === null) {continue}
if (handler.element_handler.get(ix) === undefined) {
handler.element_handler.set(ix, gl.elements({
primitive: 'triangles',
usage: 'static',
data: feature.vertices,
type: "uint" + feature.coord_resolution,
length: feature.vertices.length, // in bytes
count: feature.vertices.length / feature.coord_resolution * 8
}))
handler.coord_handler.post_data(ix, feature.coordinates)
}
let color = d3.rgb(colorScale(feature.REGION_UN))
let {r, g, b} = color

const v = {
color: [r/255, g/255, b/255],
zoom: 1,
centroid: [feature.centroid_x, feature.centroid_y],
translate: [0, 0],
angle: handler.get_prop("angle", ix),
scale: SCALE,
elements: handler.element_handler.get(ix),
coords: handler.coord_handler.get(ix),
center: [scale_life(+lookup.life_expectancy_years), scale_income(+lookup.income_per_person_long_series)],
incidence: 1

}
prop_list.push(v)
}
gl.clear({color: [0, 0, 0, 0]})
render(prop_list)
}

Insert cell
draw_loop = {while(true) {
yield(draw_frame(date))
}}
Insert cell
income = aq.from(await d3.csv('https://raw.githubusercontent.com/open-numbers/ddf--gapminder--systema_globalis/master/countries-etc-datapoints/ddf--datapoints--income_per_person_long_series--by--geo--time.csv'))
Insert cell
render = gl(
//Starting point: https://observablehq.com/@marcom13/mesh-rendering-using-webgl-regl
{
depth: {
enable: false
},

blend: {enable: true, func: {
srcRGB: 'one',
srcAlpha: 'one',
dstRGB: 'one minus src alpha',
dstAlpha: 'one minus src alpha',
}
},
vert: `
precision mediump float;
attribute vec2 position;
uniform float aspect;
uniform float u_zoom;
uniform float u_scale;

uniform float u_incidence;
uniform float u_theta;
uniform vec3 color;
uniform vec2 translate;
uniform vec2 u_centroid;
uniform vec2 u_center;
varying vec3 fragColor;

mat2 rotate2d(float _angle) {
return mat2(cos(_angle),-sin(_angle),
sin(_angle),cos(_angle));
}


void main () {
gl_PointSize = 2.;
vec2 rot;
fragColor = color;
vec2 p_from_centroid = position - u_centroid;
if (u_incidence == 0.) {
rot=p_from_centroid*rotate2d(u_theta);
} else {

float angle = atan(p_from_centroid.x, p_from_centroid.y);
float magnitude = sqrt(dot(p_from_centroid, p_from_centroid));
/*
float adjust = (6. + cos(angle) * cos(u_theta) + sin(angle) * sin(u_theta))/6.;
//if (adjust < 1.) {adjust = 1./adjust;}
rot = vec2(magnitude * adjust * sin(angle), magnitude* adjust * cos(angle));
*/
float adjust = magnitude * (2. + sin(angle - u_theta)) / 2.;
rot = vec2(adjust * sin(angle), adjust * cos(angle));

//rot = vec2(.03 * sin(angle), .03 * cos(angle));
}
//vec2 rot_adj = rot * u_scale + u_centroid;
vec2 rot_adj = rot * u_scale + u_center;
gl_Position = vec4(
rot_adj.x *u_zoom + translate.x * u_zoom,
-rot_adj.y * u_zoom * aspect - translate.y*u_zoom*aspect, 0., 1.);
}
`,
frag: `
precision mediump float;
varying vec3 fragColor;
void main () {
gl_FragColor = vec4(fragColor * .25, .25);
}
`,
attributes: {
position: (state, props) => props.coords
},
elements: function (state, props) {return props.elements},
uniforms: {
u_centroid: gl.prop('centroid'),
u_center: (_, {centroid, center}) => center ? center: centroid,
u_theta: (_, {angle}) => angle !== undefined ? angle : 0,
u_zoom: (_, {zoom}) => zoom * zoom,
u_scale: (_, {scale}) => scale,
u_incidence: (_, {incidence}) => incidence == "distortion" ? 1 : 0,
aspect: width/height,
translate: (state, props) => props.translate,
color: (state, props) => props.color
},
primitive: "triangle",
}

)
Insert cell
function plot_variable() {}
Insert cell
//aq.fromArrow(country_feather).view()
Insert cell
diff(country_feather.getColumn("ADM0_A3_IS").toArray().map(d=>d.toLowerCase()), g)
Insert cell
lookups.get("usa-2017").income_per_person_long_series
Insert cell
function diff(a, b) {
const s = new Set(a)
return Array.from(b).filter(d=> !s.has(d))
}
Insert cell
g = new Set(pop.column("geo").data)
Insert cell
import {handler, myCanvas, country_feather, gl, Scrubber} from '@bmschmidt/countries-spinning-out-of-control'
Insert cell
join_natural = function(a, b) {
// Arquero does some weird things on joins.
const names = a.columnNames()
return a.join(b, undefined, [names,b.columnNames().filter(d => names.indexOf(d) == -1)])
}
Insert cell
viewof joint_data = join_natural(join_natural(pop, lifespans), income).view()
Insert cell
margin = .1
Insert cell
scale_income = d3.scaleLog().domain(d3.extent(joint_data.column("income_per_person_long_series").data.map(d => +d))).range([1 - margin*2, -1 + margin*2])
Insert cell
scale_life(100)
Insert cell
lookups = d3.rollup(joint_data, r => r[0], k=> k.geo + "-" + k.time)
Insert cell
pop = aq.from(await d3.csv("https://raw.githubusercontent.com/open-numbers/ddf--gapminder--systema_globalis/master/countries-etc-datapoints/ddf--datapoints--population_total--by--geo--time.csv"))
Insert cell
lifespans = aq.from(await d3.csv("https://raw.githubusercontent.com/open-numbers/ddf--gapminder--systema_globalis/master/countries-etc-datapoints/ddf--datapoints--life_expectancy_years--by--geo--time.csv"))
Insert cell
d3 = require('d3@v6')
Insert cell
height = width * .66
Insert cell
import { aq, op } from '@uwdata/arquero'
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