Public
Edited
Apr 25, 2023
2 forks
Importers
7 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
nepal_cenusus_2011_pyramid_plot = populationPyramidPlot(sample2011Data)
Insert cell
Insert cell
nepal_cenusus_2001_2011_comparison_pyramid_plot = populationPyramidPlot(sampleData, { facet: "year" })
Insert cell
Insert cell
Insert cell
Insert cell
function populationPyramidPlot(
data,
{
gender = "gender",
group = "group",
value = "population",
domain, // Arrays of values from 'group'. Can be use to assign particular order
facet, // The key of value based on which to generate facets
facetDirection = "x",

width = facet ? 960 : 400, // Width of the plot
height = facet ? undefined : 500, // Height of the plot

colorScheme = schemeContrasting, // Categoriecal color schemes like: d3.schemeAccent, d3.schemeCategory10,...
gap = 20 // Gap between two set of bar charts
} = {}
) {
const genderAccessor = accessor(gender);
const groupAccessor = accessor(group);
const valueAccessor = accessor(value);

domain = domain ?? [...new Set(data.map(groupAccessor))];
facetDirection = ["x", "y"].includes(facetDirection) ? facetDirection : "x";

const genders = [...new Set(data.map(genderAccessor))].sort().reverse();

const maxValue = d3.max(data, valueAccessor);
const ticks = d3.ticks(0, maxValue, 5);

const xAxis = [
Plot.ruleX(ticks, {
x: (d) => d,
dx: gap,
stroke: "currentColor",
strokeOpacity: 0.1,
insetBottom: -7.5
}),
Plot.text(ticks, { x: (d) => -d, dx: -gap, frameAnchor: "bottom", dy: 10 }),

Plot.ruleX(ticks, {
x: (d) => -d,
insetBottom: -5,
dx: -gap,
stroke: "currentColor",
strokeOpacity: 0.1
}),
Plot.text(ticks, { x: (d) => d, frameAnchor: "bottom", dx: gap, dy: 10 }),

Plot.text(
data,
Plot.selectFirst({
x: 0,
y: group,
dx: -gap,
dy: 40,
filter: (d) => genderAccessor(d) === genders[0],
text: (d) => `← ${genderAccessor(d).toUpperCase()}`,
textAnchor: "end",
fontWeight: "bold"
})
),
Plot.text(
data,
Plot.selectFirst({
x: 0,
y: group,
dx: gap,
dy: 40,
filter: (d) => genderAccessor(d) === genders[1],
text: (d) => `${genderAccessor(d).toUpperCase()} →`,
textAnchor: "start",
fontWeight: "bold"
})
)
];

const yAxis = [Plot.text(domain, { x: 0, text: (d) => d, y: (d) => d })];

const title = (d) =>
`${genderAccessor(d)} (${groupAccessor(d)}): ${valueAccessor(d)}`;

const plot = Plot.plot({
width,
height,
marginBottom: 40,
marginLeft: 30,
marginRight: 30,
...(facet && {
facet: { label: null, data: data, [facetDirection]: facet }
}),
fx: { axis: "top", padding: 0.2, label: "" },
color: {
type: "categorical",
legend: true,
domain: genders,
range: colorScheme
},
x: {
label: null,
tickFormat: Math.abs, // Only absolute value (without sign) is shown on ticks. Needed to show
axis: null
},
y: {
label: null,
domain,
reverse: true,
axis: null,
padding: 1 / 15,
align: 1
},
marks: [
xAxis, // customized
yAxis, // customized

Plot.barX(data, {
y: group,
x: (d) => -valueAccessor(d),
dx: -gap,
fill: gender,
filter: (d) => genderAccessor(d) === genders[0],
title
}),
Plot.barX(data, {
y: group,
x: value,
dx: gap,
fill: gender,
filter: (d) => genderAccessor(d) === genders[1],
title
})
]
});

d3.select(plot)
.selectAll("[aria-label=fx-axis] .tick text")
.style("font-weight", "bold")
.style("font-size", "0.75rem");

return plot;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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