Published
Edited
Mar 31, 2021
1 fork
17 stars
Insert cell
Insert cell
Insert cell
vl.markBar({ opacity: 0.4 })
.params(
// interactive parameter for the current year, bind to an internal slider
vl.param('Year').value(2000).bind(vl.slider(1850, 2000, 10))
)
.data('data/population.json')
.transform(
vl.calculate('datum.sex === 1 ? "Male" : "Female"').as('sex'),
vl.filter('datum.year === Year') // filter based on the Year param
)
.encode(
vl.x().sum('people')
.scale({ domain: [0, 12e6] }) // hardwire domain for better stability
.stack(null) // disable stacking to layer bars directly on top of each other
.axis({ format: 's' }) // use 1M, not 1,000,000
.title('People'),
vl.y().fieldO('age')
.sort('descending') // ordinal axis, place lower values at the bottom
.title('Age'),
vl.color().fieldN('sex')
.scale({ range: ['#675193', '#ca8861'] }) // custom colors
.title('Sex')
)
.width(300)
.height(350) // fixed height
.render()
Insert cell
Insert cell
Insert cell
{
// custom age axis to use between the mirrored plots
const customAxis = {
titleX: -10, titleY: -2, titleAngle: 0, titleAlign: 'center', // place title above
domain: false, ticks: false, // hide domain and tick lines
labelPadding: 10, labelAlign: 'center' // space and center axis labels
};
// generate a subplot specification
const plot = (sex, axis) => {
return vl
.markBar({ opacity: 0.4 })
.transform(vl.filter(`datum.sex === "${sex}"`)) // filter to given value
.encode(
vl.x().sum('people')
.scale({ domain: [0, 12e6] })
.sort(axis ? 'ascending' : 'descending') // flip directions
.axis({ format: 's' })
.title(`${sex}s`),
vl.y().fieldO('age')
.axis(axis) // pass in custom axis setting
.sort('descending')
.title('Age'),
vl.color().fieldN('sex')
.scale({ range: ['#675193', '#ca8861'] })
.title('Sex')
)
.width(250)
.height(350);
};

return vl
.data('data/population.json')
.transform(
vl.calculate('datum.sex === 1 ? "Male" : "Female"').as('sex'),
vl.filter('datum.year === Year')
)
.params(
vl.param('Year').bind(viewof year) // bind year parameter to scrubber
)
.hconcat(
plot('Female', null), // subplot with no age axis
plot('Male', customAxis) // subplot with custom age axis
)
.bounds('flush') // ignore axes when spacing subplots
.spacing(20) // place subplots 20 pixels apart
.render();
}
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