rawData = FileAttachment("data/constituencies.json").json()
partyColors = ({
"Con": "#0087DC", "Lab": "#DC241f", "LD": "#FAA61A",
"Green": "#6AB023", "RUK": "#12B6CF", "SNP": "#FDF38E",
"PC": "#005B54", "Ind": "#999999", "Other": "#AAAAAA"
})
allVarsMap = [
{label: "Conservative 2024", value: "Con24"},
{label: "Labour 2024", value: "Lab24"},
{label: "Lib Dem 2024", value: "LD24"},
{label: "Reform 2024", value: "RUK24"},
{label: "Green 2024", value: "Green24"},
{label: "SNP 2024", value: "SNP24"},
{label: "Plaid Cymru 2024", value: "PC24"},
{label: "Other 2024", value: "Other24"},
{label: "Conservative 2019", value: "Con19"},
{label: "Labour 2019", value: "Lab19"},
{label: "Lib Dem 2019", value: "LD19"},
{label: "Reform/Brexit 2019", value: "Brexit19"},
{label: "Green 2019", value: "Green19"},
{label: "SNP 2019", value: "SNP19"},
{label: "Plaid Cymru 2019", value: "PC19"},
{label: "Turnout 2024", value: "Turnout24"},
{label: "Turnout 2019", value: "Turnout19"},
{label: "Majority 2024", value: "Majority24"},
{label: "Brexit Leave (Hanretty)", value: "HanrettyLeave"},
{label: "Population Density", value: "c21PopulationDensity"},
{label: "Age: Under 15", value: "AgeUnder15"},
{label: "Age: 16-24", value: "Age16to24"},
{label: "Age: 25-34", value: "Age25to34"},
{label: "Age: 35-44", value: "Age35to44"},
{label: "Age: 45-54", value: "Age45to54"},
{label: "Age: 55-64", value: "Age55to64"},
{label: "Age: Over 65", value: "AgeOver65"},
{label: "Ethnicity: White", value: "c21EthnicityWhite"},
{label: "Ethnicity: Asian", value: "c21EthnicityAsian"},
{label: "Ethnicity: Black", value: "c21EthnicityBlack"},
{label: "Ethnicity: Mixed", value: "c21EthnicityMixed"},
{label: "Born in UK", value: "born_uk"},
{label: "Religion: Christian", value: "c21Christian"},
{label: "Religion: Muslim", value: "c21Muslim"},
{label: "Religion: No Religion", value: "c21NoReligion"},
{label: "Qualification: None", value: "c21QualNone"},
{label: "Qualification: Level 4+", value: "c21QualLevel4"},
{label: "Housing: Owned Outright", value: "c21HouseOutright"},
{label: "Housing: Mortgage", value: "c21HouseMortgage"},
{label: "Housing: Social Rent", value: "c21HouseSocialLA"},
{label: "Housing: Private Rent", value: "c21HousePrivateLandlord"},
{label: "No Car", value: "c21CarsNone"},
{label: "Health: Very Good", value: "c21HealthVeryGood"},
{label: "Health: Bad/Very Bad", value: "c21HealthBad"},
{label: "Employment: Unemployed", value: "c21Unemployed"},
{label: "Deprivation: None", value: "c21DeprivedNone"},
{label: "Deprivation: 3+ dims", value: "c21Deprived3"}
]
mapVarsMap = [
{label: "2024 Winner", value: "Winner24"},
{label: "2019 Winner", value: "Winner19"},
...allVarsMap
]
allVarLabels = Object.fromEntries(allVarsMap.map(v => [v.value, v.label]))
mapVarLabels = Object.fromEntries(mapVarsMap.map(v => [v.value, v.label]))
allRegions = [...new Set(rawData.map(d => d.Region))].filter(Boolean).sort()
allWinners = [...new Set(rawData.map(d => d.Winner24))].filter(Boolean).sort()
allConsts = rawData.map(d => d.ConstituencyName).filter(Boolean).sort()Histogram
viewof histVar = Inputs.select(
new Map(allVarsMap.map(v => [v.label, v.value])),
{label: "Variable:", value: "HanrettyLeave"}
)
viewof histBins = Inputs.range([10, 80], {label: "Bins:", step: 1, value: 30})
viewof histFill = Inputs.radio(
new Map([["2024 Winner","winner"],["2019 Winner","winner19"],["Region","region"],["None","none"]]),
{label: "Fill by:", value: "winner"}
)Region:
2024 Winner:
filteredHist = rawData.filter(d =>
histRegions.includes(d.Region) && histWinners.includes(d.Winner24) && d[histVar] != null
)
histPlot = {
const vLabel = allVarLabels[histVar] || histVar;
let fillFn, colorSpec;
if (histFill === "winner") {
fillFn = d => partyColors[d.Winner24] || "#aaa";
colorSpec = {color: {legend: true, domain: Object.keys(partyColors), range: Object.values(partyColors)}};
} else if (histFill === "winner19") {
fillFn = d => partyColors[d.Winner19] || "#aaa";
colorSpec = {color: {legend: true, domain: Object.keys(partyColors), range: Object.values(partyColors)}};
} else if (histFill === "region") {
fillFn = "Region"; colorSpec = {color: {legend: true}};
} else {
fillFn = "#888888"; colorSpec = {};
}
return Plot.plot({
marks: [Plot.rectY(filteredHist, Plot.binX({y: "count"}, {x: histVar, fill: fillFn, thresholds: histBins, tip: true})), Plot.ruleY([0])],
x: {label: vLabel}, y: {label: "Count"}, ...colorSpec, width: 900, height: 520
});
}