Plot = import("https://esm.sh/@observablehq/plot@0.6.13")
d = transpose(data)
distinct_cutoff = 10
disc_types = ['string', 'boolean']
disc_vars = vars.filter(d => disc_types.includes(d.type) && d.statistics.numDistinct <= distinct_cutoff).map(d => [d.label, d.name])
disc_opts = new Map([['', null]].concat(disc_vars))
cont_types = ['integer', 'float', 'date', 'datetime', 'time']
cont_vars = vars.filter(d => cont_types.includes(d.type) && d.statistics.numDistinct > distinct_cutoff).map(d => [d.label, d.name])
cont_opts = new Map(cont_vars)
viewof x_var = Inputs.select(cont_opts, {value: Array.from(cont_opts.values())[0], label: "X axis"})
viewof y_var = Inputs.select(cont_opts, {value: Array.from(cont_opts.values())[1], label: "Y axis"})
viewof color_var = Inputs.select(disc_opts, {value: Array.from(disc_opts.values())[1], label: "Color"})
default_color = d3.schemeCategory10[0]
plt_color = color_var || default_color
all_vars = cont_vars.concat(disc_vars)
channels = Object.fromEntries(all_vars.map(k => [k[1], k[1]]))
viewof scatter = Plot.plot({
style: { fontFamily: "var(--sans-serif)" },
inset: 8,
grid: true,
x: { tickFormat: "" },
color: { legend: true },
marks: [
Plot.dot(d, {
x: x_var,
y: y_var,
stroke: plt_color,
tip: true,
channels: channels
}),
]
})
viewof x_hist = Plot.plot({
style: { fontFamily: "var(--sans-serif)" },
width: 640/2,
x: { tickFormat: "" },
y: { grid: true },
marks: [
Plot.rectY(d, Plot.binX({y: "count"}, {x: x_var, fill: plt_color})),
Plot.ruleY([0])
]
})
viewof y_hist = Plot.plot({
style: { fontFamily: "var(--sans-serif)" },
width: 640/2,
y: { grid: true },
marks: [
Plot.rectY(d, Plot.binX({y: "count"}, {x: y_var, fill: plt_color})),
Plot.ruleY([0])
]
})
html`<div style="display: flex; flex-wrap: wrap; align-items: flex-end;">
<div style="flex-basis: 25%"> ${viewof y_hist} </div>
<div style="flex-basis: 50%"> ${viewof scatter} </div>
<div style="flex-basis: 25%"> ${viewof x_hist} </div>
</div>`
viewof map_var = Inputs.select(cont_opts, {value: Array.from(cont_opts.values())[1], label: "Measure"})
viewof years = interval([d3.min(data.year), d3.max(data.year)], {step: 1, label: "Years"})
viewof bins = Inputs.range([2, 10], {value: 5, step: 1, label: "Bins"})
world = FileAttachment("countries-110m.json").json()
countries = topojson.feature(world, world.objects.countries)
//land = topojson.feature(world, world.objects.land)
slim3 = FileAttachment("slim-3.json").json()
codes = new Map(slim3.map(d => [d["country-code"], d["alpha-3"]]))
td = transpose(data)
tdf = td.filter(d => d.year >= years[0] && d.year <= years[1])
dg = d3.rollup(tdf, v => d3.mean(v, d => d[map_var]), d => d.code)
viewof map = Plot.plot({
style: { fontFamily: "var(--sans-serif)" },
projection: "equal-earth",
marks: [
Plot.sphere(),
Plot.graticule(),
Plot.geo(countries, Plot.centroid({
stroke: "black",
strokeWidth: 0.5,
fill: d => dg.get(codes.get(d.id)),
tip: true,
channels: {country: d => d.properties.name}
})),
],
color: {
type: "quantile",
n: bins,
scheme: "blues",
unknown: "#ddd",
legend: true,
label: "Mean " + map_var,
tickFormat: d => Math.round(d)
}
})
html`<div style="display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: center;">
<div style="flex-basis: 50%"> ${viewof map} </div>
</div>`