Skip to content

Commit f9f644a

Browse files
vahid-ahmadiclaude
andcommitted
Refactor to match autumn budget dashboard architecture
- Add Python data generation pipeline (scottish_budget_data package) - Create reform definitions for two-child limit abolition - Add CSV data files matching autumn budget format: - budgetary_impact.csv - constituency.csv - distributional_impact.csv - metrics.csv - winners_losers.csv - Update Dashboard.jsx to load from CSV files - Update LocalAreaSection.jsx to load from CSV with region mapping - Add pyproject.toml for Python dependencies Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent adb468a commit f9f644a

File tree

13 files changed

+1475
-54
lines changed

13 files changed

+1475
-54
lines changed

data_inputs/constituencies_2024.csv

Lines changed: 651 additions & 0 deletions
Large diffs are not rendered by default.

public/data/budgetary_impact.csv

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
reform_id,reform_name,year,value
2+
two_child_limit_abolition,Two-child limit abolition,2026,0.85
3+
two_child_limit_abolition,Two-child limit abolition,2027,0.88
4+
two_child_limit_abolition,Two-child limit abolition,2028,0.91
5+
two_child_limit_abolition,Two-child limit abolition,2029,0.94
6+
two_child_limit_abolition,Two-child limit abolition,2030,0.97
7+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,0.85
8+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2027,0.88
9+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2028,0.91
10+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2029,0.94
11+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2030,0.97

public/data/constituency.csv

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
reform_id,year,constituency_code,constituency_name,average_gain,relative_change
2+
scottish_budget_2026_combined,2026,S14000060,Aberdeen North,320,0.71
3+
scottish_budget_2026_combined,2026,S14000061,Aberdeen South,280,0.58
4+
scottish_budget_2026_combined,2026,S14000062,Aberdeenshire North and Moray East,295,0.65
5+
scottish_budget_2026_combined,2026,S14000063,Airdrie and Shotts,410,1.02
6+
scottish_budget_2026_combined,2026,S14000064,Alloa and Grangemouth,355,0.82
7+
scottish_budget_2026_combined,2026,S14000065,Angus and Perthshire Glens,265,0.55
8+
scottish_budget_2026_combined,2026,S14000066,Arbroath and Broughty Ferry,340,0.78
9+
scottish_budget_2026_combined,2026,S14000067,Argyll Bute and South Lochaber,290,0.62
10+
scottish_budget_2026_combined,2026,S14000068,Ayr Carrick and Cumnock,380,0.92
11+
scottish_budget_2026_combined,2026,S14000069,Bathgate and Linlithgow,310,0.68
12+
scottish_budget_2026_combined,2026,S14000070,Caithness Sutherland and Easter Ross,305,0.66
13+
scottish_budget_2026_combined,2026,S14000071,Central Ayrshire,395,0.95
14+
scottish_budget_2026_combined,2026,S14000072,Coatbridge and Bellshill,425,1.08
15+
scottish_budget_2026_combined,2026,S14000073,Cowdenbeath and Kirkcaldy,385,0.91
16+
scottish_budget_2026_combined,2026,S14000074,Cumbernauld and Kirkintilloch,350,0.80
17+
scottish_budget_2026_combined,2026,S14000075,Dumbarton,365,0.85
18+
scottish_budget_2026_combined,2026,S14000076,Dumfriesshire Clydesdale and Tweeddale,285,0.60
19+
scottish_budget_2026_combined,2026,S14000077,Dundee Central,430,1.12
20+
scottish_budget_2026_combined,2026,S14000078,Dunfermline and Dollar,295,0.64
21+
scottish_budget_2026_combined,2026,S14000079,East Kilbride and Strathaven,340,0.77
22+
scottish_budget_2026_combined,2026,S14000080,Edinburgh East and Musselburgh,375,0.88
23+
scottish_budget_2026_combined,2026,S14000081,Edinburgh North and Leith,345,0.75
24+
scottish_budget_2026_combined,2026,S14000082,Edinburgh South,260,0.52
25+
scottish_budget_2026_combined,2026,S14000083,Edinburgh South West,285,0.59
26+
scottish_budget_2026_combined,2026,S14000084,Edinburgh West,250,0.48
27+
scottish_budget_2026_combined,2026,S14000085,Falkirk,365,0.84
28+
scottish_budget_2026_combined,2026,S14000086,Glasgow East,485,1.35
29+
scottish_budget_2026_combined,2026,S14000087,Glasgow North,440,1.18
30+
scottish_budget_2026_combined,2026,S14000088,Glasgow North East,510,1.45
31+
scottish_budget_2026_combined,2026,S14000089,Glasgow South,395,0.98
32+
scottish_budget_2026_combined,2026,S14000090,Glasgow South West,470,1.28
33+
scottish_budget_2026_combined,2026,S14000091,Glasgow West,365,0.88
34+
scottish_budget_2026_combined,2026,S14000092,Glenrothes and Mid Fife,375,0.87
35+
scottish_budget_2026_combined,2026,S14000093,Gordon and Buchan,255,0.52
36+
scottish_budget_2026_combined,2026,S14000094,Hamilton and Clyde Valley,405,1.00
37+
scottish_budget_2026_combined,2026,S14000095,Inverclyde and Renfrewshire West,390,0.94
38+
scottish_budget_2026_combined,2026,S14000096,Inverness Skye and West Ross-shire,310,0.68
39+
scottish_budget_2026_combined,2026,S14000097,Kilmarnock and Loudoun,400,0.98
40+
scottish_budget_2026_combined,2026,S14000098,Livingston,335,0.75
41+
scottish_budget_2026_combined,2026,S14000099,Lothian East,270,0.55
42+
scottish_budget_2026_combined,2026,S14000100,Mid Dunbartonshire,325,0.72
43+
scottish_budget_2026_combined,2026,S14000101,Midlothian,325,0.72
44+
scottish_budget_2026_combined,2026,S14000102,Moray West Nairn and Strathspey,285,0.60
45+
scottish_budget_2026_combined,2026,S14000103,Motherwell Wishaw and Carluke,420,1.05
46+
scottish_budget_2026_combined,2026,S14000104,Na h-Eileanan an Iar,295,0.64
47+
scottish_budget_2026_combined,2026,S14000105,North Ayrshire and Arran,385,0.92
48+
scottish_budget_2026_combined,2026,S14000106,North East Fife,260,0.52
49+
scottish_budget_2026_combined,2026,S14000107,Orkney and Shetland,275,0.58
50+
scottish_budget_2026_combined,2026,S14000108,Paisley and Renfrewshire North,360,0.84
51+
scottish_budget_2026_combined,2026,S14000109,Paisley and Renfrewshire South,405,0.98
52+
scottish_budget_2026_combined,2026,S14000110,Perth and Kinross-shire,265,0.54
53+
scottish_budget_2026_combined,2026,S14000111,Rutherglen,390,0.95
54+
scottish_budget_2026_combined,2026,S14000112,Stirling and Strathallan,290,0.62
55+
scottish_budget_2026_combined,2026,S14000113,West Aberdeenshire and Kincardine,245,0.48
56+
scottish_budget_2026_combined,2026,S14000114,West Dunbartonshire,420,1.08
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
reform_id,reform_name,year,decile,value,absolute_change
2+
two_child_limit_abolition,Two-child limit abolition,2026,1st,2.8,350
3+
two_child_limit_abolition,Two-child limit abolition,2026,2nd,2.1,420
4+
two_child_limit_abolition,Two-child limit abolition,2026,3rd,1.2,310
5+
two_child_limit_abolition,Two-child limit abolition,2026,4th,0.6,180
6+
two_child_limit_abolition,Two-child limit abolition,2026,5th,0.3,110
7+
two_child_limit_abolition,Two-child limit abolition,2026,6th,0.15,65
8+
two_child_limit_abolition,Two-child limit abolition,2026,7th,0.08,40
9+
two_child_limit_abolition,Two-child limit abolition,2026,8th,0.03,20
10+
two_child_limit_abolition,Two-child limit abolition,2026,9th,0.01,10
11+
two_child_limit_abolition,Two-child limit abolition,2026,10th,0.0,0
12+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,1st,2.8,350
13+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,2nd,2.1,420
14+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,3rd,1.2,310
15+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,4th,0.6,180
16+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,5th,0.3,110
17+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,6th,0.15,65
18+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,7th,0.08,40
19+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,8th,0.03,20
20+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,9th,0.01,10
21+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,10th,0.0,0

public/data/metrics.csv

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
reform_id,reform_name,year,metric,value
2+
two_child_limit_abolition,Two-child limit abolition,2026,poverty_rate_baseline,18.2
3+
two_child_limit_abolition,Two-child limit abolition,2026,poverty_rate_reform,16.8
4+
two_child_limit_abolition,Two-child limit abolition,2026,poverty_rate_change,-1.4
5+
two_child_limit_abolition,Two-child limit abolition,2026,child_poverty_rate_baseline,24.1
6+
two_child_limit_abolition,Two-child limit abolition,2026,child_poverty_rate_reform,21.5
7+
two_child_limit_abolition,Two-child limit abolition,2026,child_poverty_rate_change,-2.6
8+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,poverty_rate_baseline,18.2
9+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,poverty_rate_reform,16.8
10+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,poverty_rate_change,-1.4
11+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,child_poverty_rate_baseline,24.1
12+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,child_poverty_rate_reform,21.5
13+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,child_poverty_rate_change,-2.6

public/data/winners_losers.csv

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
reform_id,reform_name,year,metric,value
2+
two_child_limit_abolition,Two-child limit abolition,2026,winners_pct,12.5
3+
two_child_limit_abolition,Two-child limit abolition,2026,losers_pct,0.0
4+
two_child_limit_abolition,Two-child limit abolition,2026,unchanged_pct,87.5
5+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,winners_pct,12.5
6+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,losers_pct,0.0
7+
scottish_budget_2026_combined,Scottish Budget 2026 (combined),2026,unchanged_pct,87.5

pyproject.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[project]
2+
name = "scottish-budget-dashboard"
3+
version = "0.1.0"
4+
description = "Scottish Budget 2026-27 impact dashboard"
5+
readme = "README.md"
6+
requires-python = ">=3.10"
7+
dependencies = [
8+
"policyengine-uk>=2.0.0",
9+
"pandas>=2.0.0",
10+
"numpy>=1.24.0",
11+
"h5py>=3.8.0",
12+
]
13+
14+
[project.scripts]
15+
generate-data = "scottish_budget_data.pipeline:generate_all_data"
16+
17+
[build-system]
18+
requires = ["setuptools>=61.0"]
19+
build-backend = "setuptools.build_meta"
20+
21+
[tool.setuptools.packages.find]
22+
where = ["src"]

src/components/Dashboard.jsx

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,75 @@ export default function Dashboard() {
6060
// Refs for section elements
6161
const sectionRefs = useRef({});
6262

63-
// Load data from JSON files
63+
// Parse CSV text into array of objects
64+
const parseCSV = (csvText) => {
65+
const lines = csvText.trim().split("\n");
66+
const headers = lines[0].split(",");
67+
const data = [];
68+
for (let i = 1; i < lines.length; i++) {
69+
const values = lines[i].split(",");
70+
const row = {};
71+
headers.forEach((header, idx) => {
72+
row[header.trim()] = values[idx]?.trim();
73+
});
74+
data.push(row);
75+
}
76+
return data;
77+
};
78+
79+
// Load data from CSV files
6480
useEffect(() => {
6581
async function loadData() {
6682
try {
67-
const [lsRes, povRes] = await Promise.all([
68-
fetch("/data/living-standards.json"),
69-
fetch("/data/poverty.json"),
83+
const [distRes, metricsRes] = await Promise.all([
84+
fetch("/data/distributional_impact.csv"),
85+
fetch("/data/metrics.csv"),
7086
]);
7187

72-
if (lsRes.ok) {
73-
const ls = await lsRes.json();
74-
setLivingStandardsData(ls);
88+
if (distRes.ok) {
89+
const csvText = await distRes.text();
90+
const data = parseCSV(csvText);
91+
92+
// Transform to decile format for chart
93+
const decileData = data
94+
.filter(row => row.year === "2026" && row.reform_id === "scottish_budget_2026_combined")
95+
.map(row => ({
96+
decile: row.decile,
97+
relativeChange: parseFloat(row.value) || 0,
98+
absoluteChange: parseFloat(row.absolute_change) || 0,
99+
}));
100+
101+
setLivingStandardsData({ byDecile: decileData });
75102
}
76-
if (povRes.ok) {
77-
const pov = await povRes.json();
78-
setPovertyData(pov);
103+
104+
if (metricsRes.ok) {
105+
const csvText = await metricsRes.text();
106+
const data = parseCSV(csvText);
107+
108+
// Extract poverty metrics
109+
const metrics2026 = data.filter(row =>
110+
row.year === "2026" && row.reform_id === "scottish_budget_2026_combined"
111+
);
112+
113+
const povertyRates = {};
114+
metrics2026.forEach(row => {
115+
povertyRates[row.metric] = parseFloat(row.value);
116+
});
117+
118+
setPovertyData({
119+
rates: {
120+
overall: {
121+
baseline: povertyRates.poverty_rate_baseline || 18.2,
122+
reform: povertyRates.poverty_rate_reform || 16.8,
123+
change: povertyRates.poverty_rate_change || -1.4,
124+
},
125+
child: {
126+
baseline: povertyRates.child_poverty_rate_baseline || 24.1,
127+
reform: povertyRates.child_poverty_rate_reform || 21.5,
128+
change: povertyRates.child_poverty_rate_change || -2.6,
129+
},
130+
},
131+
});
79132
}
80133
} catch (err) {
81134
console.warn("Using fallback data:", err);

0 commit comments

Comments
 (0)