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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more