Skip to content

Commit 6e0ada9

Browse files
author
William
committed
Rebase time series to 2008
Change spiders to ranked percentile Add more hover info to spider
1 parent e84bf65 commit 6e0ada9

File tree

2 files changed

+70
-26
lines changed

2 files changed

+70
-26
lines changed

Streamlit_itl3-compare.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ def img_to_base64(path):
127127
# Initialise data
128128
all_data, uk_data = load_data()
129129

130+
all_data['GVA/H volume'] = all_data.groupby("code")["GVA/H volume"].transform(
131+
lambda x: (x / x.loc[all_data.loc[x.index, "year"] == 2008].values[0]) * 100
132+
)
133+
uk_data['GVA/H volume'] = uk_data.groupby("code")["GVA/H volume"].transform(
134+
lambda x: (x / x.loc[uk_data.loc[x.index, "year"] == 2008].values[0]) * 100
135+
)
136+
130137
driver = {
131138
'GVA per hour worked': ['Productivity measured as Gross Value Added per hour worked', '2023', '2004', '<a href="https://www.ons.gov.uk/employmentandlabourmarket/peopleinwork/labourproductivity/datasets/subregionalproductivitylabourproductivitygvaperhourworkedandgvaperfilledjobindicesbyuknuts2andnuts3subregions" target="_blank">Source</a>'],
132139
'Export Intensity': ['Exports as a percentage of GDP ', '2023', '2016', '<a href="https://www.ons.gov.uk/businessindustryandtrade/internationaltrade/datasets/subnationaltradeingoods" target="_blank">Source</a>'],

visualisations.py

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def time_series(data, regions, uk_data):
7373
fig.update_layout(
7474
title={
7575
'text': '<span style="font-weight:normal;">' +
76-
'<br>'.join(textwrap.wrap(f"Time Series of {regions[0]} against {regions[1]} - <b>GVA per hour (chained 2022)</b>", width=100)) +
76+
'<br>'.join(textwrap.wrap(f"Time Series of {regions[0]} against {regions[1]} - <b>GVA per hour (chained 2008)</b>", width=100)) +
7777
'</span>',
7878
'font': {'size': 14},
7979
'x': 0.05, # move slightly to the right (0=left, 1=right)
@@ -82,7 +82,7 @@ def time_series(data, regions, uk_data):
8282
'yanchor': 'top', # align title relative to y
8383
},
8484
xaxis_title="Year",
85-
yaxis_title=f"GVA per hour (chained 2022) (%)",
85+
yaxis_title=f"GVA per hour (chained 2008) (%)",
8686
autosize=True,
8787
template="plotly_white", # Use a clean white background
8888
legend=dict(
@@ -108,42 +108,79 @@ def spider(data, indicators, region, colour, driver):
108108
# Merge so values align by code
109109
row = row.merge(sub, on='name', how='left')
110110

111-
# Compute the medians for each column in the indicators
112-
medians = row.drop(columns='name').median()[indicators]
113-
114-
temp = row.loc[row['name'] == region, indicators].copy()
115-
opposite_indicators = ['Low Skilled', 'Inactive due to Illness']
111+
# Compute percentile ranks for each indicator
112+
percentile_ranks = pd.DataFrame({'name': data['name'].unique()})
113+
116114
for ind in indicators:
117-
if ind in opposite_indicators:
118-
temp[ind] = (medians[ind] / temp[ind]) * 100
119-
else:
120-
temp[ind] = (temp[ind] / medians[ind]) * 100
115+
# For each indicator, get the series
116+
series = row[ind]
121117

118+
# Compute percentile rank of each value
119+
ranks = series.rank(pct=True) * 100 # gives 0–100
120+
percentile_ranks[ind] = ranks
121+
122+
# Subset to your region of interest
123+
temp = percentile_ranks.loc[percentile_ranks['name'] == region, indicators].copy()
124+
125+
# Handle "opposite indicators" (lower values = better)
126+
opposite_indicators = ['Low Skilled', 'Inactive due to Illness']
127+
for ind in opposite_indicators:
128+
if ind in temp.columns:
129+
temp[ind] = 100 - temp[ind] # invert percentile so "lower = better"
122130
# Handle missing data by filtering out NaN values
123131
temp = temp.dropna(axis=1) # Drop columns with NaN values
124-
valid_indicators = temp.columns.tolist() # Get the corresponding valid indicators
132+
# Compute real values for the region
133+
real_values = row.loc[row['name'] == region, indicators].copy()
125134

126-
# Close the loop by appending the first value to the end
127-
r_values = temp.values.flatten().tolist()
128-
r_values.append(r_values[0]) # Append the first value to close the loop
135+
# Compute medians for each indicator
136+
medians = row[indicators].median()
137+
138+
# Handle missing values consistently
139+
valid_indicators = [ind for ind in indicators if ind in temp.columns]
140+
141+
# Close the loop
142+
r_values = temp[valid_indicators].values.flatten().tolist()
143+
r_values.append(r_values[0])
129144

130145
theta_values = ['<br>'.join(textwrap.wrap(ind, width=10)) for ind in valid_indicators]
131-
theta_values.append(theta_values[0]) # Close the loop
146+
theta_values.append(theta_values[0])
132147

133-
# Create a time series plot
148+
# Build custom hover text
149+
hover_texts = []
150+
for ind in valid_indicators:
151+
raw_val = real_values[ind].values[0]
152+
median_val = medians[ind]
153+
percentile_val = temp[ind].values[0]
154+
if ind in ['GVA per hour worked', 'GFCF per job', 'ICT per job', 'Intangibles per job']:
155+
hover_texts.append(
156+
f"<b>Indicator:</b> {ind}<br>"
157+
f"<b>Value:</b> £{raw_val:,.2f}<br>"
158+
f"<b>UK Median:</b> £{median_val:,.2f}<br>"
159+
f"<b>Percentile:</b> {percentile_val:.2f}%"
160+
)
161+
else:
162+
hover_texts.append(
163+
f"<b>Indicator:</b> {ind}<br>"
164+
f"<b>Value:</b> {raw_val:,.2%}<br>"
165+
f"<b>UK Median:</b> {median_val:,.2%}<br>"
166+
f"<b>Percentile:</b> {percentile_val:.2f}%"
167+
)
168+
# Close the loop
169+
hover_texts.append(hover_texts[0])
170+
171+
# Create the figure
134172
fig = go.Figure()
135-
# Add the trace for the selected region
136173
fig.add_trace(go.Scatterpolar(
137-
r=r_values, # Values for the radar plot
138-
theta=theta_values, # Categories (indicators)
139-
fill='toself', # Fill the area under the curve
174+
r=r_values,
175+
theta=theta_values,
176+
text=hover_texts, # supply custom hover text
177+
hoverinfo="text", # only show text
178+
fill='toself',
140179
name=region,
141-
line=dict(color=colour, width=2), # Customize line color and width
142-
hoverinfo="text", # Enable custom hover text
143-
hovertemplate="<b>Indicator:</b> %{theta}<br><b>Relative to UK Median:</b> %{r:.2f}%<extra></extra>" # Custom hover text
180+
line=dict(color=colour, width=2),
144181
))
145182
fig.add_trace(go.Scatterpolar(
146-
r=[100]*len(r_values), # Values for the radar plot
183+
r=[50]*len(r_values), # Values for the radar plot
147184
theta=theta_values, # Categories (indicators)
148185
fill='toself', # Fill the area under the curve
149186
name=f"UK median",
@@ -158,7 +195,7 @@ def spider(data, indicators, region, colour, driver):
158195
polar=dict(
159196
radialaxis=dict(
160197
visible=True,
161-
range=[20, 200], # Adjust the range as needed
198+
range=[0, 100], # Adjust the range as needed
162199
showticklabels=False, # Remove radial axis ticks
163200
),
164201
angularaxis=dict(

0 commit comments

Comments
 (0)