{
const groupedData = lodash.groupBy(CensusData, d => `${d.Year}-${d.Age}`);
const withPercentages = lodash.map(groupedData, (group, key) => {
const [year, age] = key.split('-');
const total = lodash.sumBy(group, d => parseInt(d.People));
const males = parseInt(lodash.find(group, {Sex: "1"})?.People || 0);
const females = parseInt(lodash.find(group, {Sex: "2"})?.People || 0);
return {
Year: year,
Age: parseInt(age),
MalePercentage: (males / total * 100).toFixed(1),
FemalePercentage: (females / total * 100).toFixed(1)
};
});
const longFormatData = [];
withPercentages.forEach(d => {
longFormatData.push({
Age: d.Age,
Sex: "Male",
Year: d.Year,
Percentage: parseFloat(d.MalePercentage),
Category: `${d.Year} Male`
});
longFormatData.push({
Age: d.Age,
Sex: "Female",
Year: d.Year,
Percentage: parseFloat(d.FemalePercentage),
Category: `${d.Year} Female`
});
});
const sortedData = lodash.sortBy(longFormatData, ['Category', 'Age']);
// Common encoding specifications
const baseEncoding = (scale) => vl.data(sortedData)
.encode(
vl.x().fieldQ('Age')
.scale({zero: false})
.axis({
grid: true,
tickMinStep: 5,
title: 'Age (years)',
labelFontSize: 11
}),
vl.y().fieldQ('Percentage')
.scale(scale)
.axis({
grid: true,
labelFontSize: 11
}),
vl.color().fieldN('Category')
.scale({
domain: ['1900 Male', '1900 Female', '2000 Male', '2000 Female'],
range: [
'#A8C8E8', // Light blue for 1900 Male
'#FFAFAF', // Light red for 1900 Female
'#1B4B82', // Dark blue for 2000 Male
'#B22222' // Dark red for 2000 Female
]
})
.title('Gender and Year')
);
// Create both visualizations side by side
const percentageScale = {domain: [0, 100], type: 'linear'};
const logScale = {type: 'log', domain: [1, 100]};
return vl.hconcat(
// Percentage scale visualization
vl.layer(
baseEncoding(percentageScale).mark({
type: 'line',
strokeWidth: 2.5,
interpolate: 'linear'
}),
baseEncoding(percentageScale).mark({
type: 'point',
size: 100,
filled: true
})
.encode(
vl.shape().field('Sex')
.scale({
domain: ['Male', 'Female'],
range: ['square', 'circle']
})
)
)
.width(400)
.height(400)
.title({
text: 'Linear Percentage Scale',
subtitle: '0-100% scale',
fontSize: 14,
subtitleFontSize: 11
}),
// Logarithmic scale visualization
vl.layer(
baseEncoding(logScale).mark({
type: 'line',
strokeWidth: 2.5,
interpolate: 'linear'
}),
baseEncoding(logScale).mark({
type: 'point',
size: 100,
filled: true
})
.encode(
vl.shape().field('Sex')
.scale({
domain: ['Male', 'Female'],
range: ['square', 'circle']
})
)
)
.width(400)
.height(400)
.title({
text: 'Logarithmic Scale',
subtitle: 'Log scale emphasizes relative changes',
fontSize: 14,
subtitleFontSize: 11
})
)
.config({
axis: {
gridColor: '#EEEEEE',
gridOpacity: 0.5
},
legend: {
orient: 'right',
labelFontSize: 11
}
})
.render();}