Spaces:
Build error
Build error
feat: adjust document styling
Browse files- planning_ai/document.py +60 -30
- planning_ai/main.py +0 -1
planning_ai/document.py
CHANGED
@@ -4,6 +4,7 @@ import re
|
|
4 |
from collections import Counter
|
5 |
|
6 |
import geopandas as gpd
|
|
|
7 |
import matplotlib.pyplot as plt
|
8 |
import numpy as np
|
9 |
import polars as pl
|
@@ -11,6 +12,9 @@ from polars.dependencies import subprocess
|
|
11 |
|
12 |
from planning_ai.common.utils import Paths
|
13 |
|
|
|
|
|
|
|
14 |
|
15 |
def _process_postcodes(final):
|
16 |
documents = final["documents"]
|
@@ -83,8 +87,9 @@ def _process_stances(final):
|
|
83 |
|
84 |
def _process_themes(final):
|
85 |
documents = final["documents"]
|
86 |
-
themes =
|
87 |
-
|
|
|
88 |
themes = pl.DataFrame(themes).transpose(include_header=True)
|
89 |
themes_breakdown = themes.with_columns(
|
90 |
((pl.col("column_0") / pl.sum("column_0")) * 100).round(2).alias("percentage")
|
@@ -96,41 +101,61 @@ def _process_themes(final):
|
|
96 |
|
97 |
|
98 |
def fig_oa(postcodes):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
oac = pl.read_csv(Paths.RAW / "oac21ew.csv")
|
100 |
-
|
|
|
101 |
postcodes.join(oac, left_on="OA21", right_on="oa21cd")
|
102 |
.group_by("supergroup")
|
103 |
-
.
|
|
|
104 |
.sort("supergroup")
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
)
|
106 |
-
|
107 |
|
108 |
_, ax1 = plt.subplots()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
|
110 |
-
ax1.bar(postcodes_pd["supergroup"], postcodes_pd["len"])
|
111 |
ax1.set_xlabel("Output Area Classification (OAC) Supergroup")
|
112 |
-
ax1.set_ylabel("
|
|
|
|
|
113 |
|
|
|
114 |
plt.tight_layout()
|
115 |
|
116 |
plt.savefig(Paths.SUMMARY / "figs" / "oas.png")
|
117 |
|
118 |
|
119 |
def fig_wards(postcodes):
|
120 |
-
wards = (
|
121 |
-
pl.read_csv(Paths.RAW / "TS001-2021-3-filtered-2025-01-09T11_07_15Z.csv")
|
122 |
-
.rename(
|
123 |
-
{
|
124 |
-
"Electoral wards and divisions Code": "OSWARD",
|
125 |
-
"Electoral wards and divisions": "WARDNAME",
|
126 |
-
}
|
127 |
-
)
|
128 |
-
.group_by(["OSWARD", "WARDNAME"])
|
129 |
-
.sum()
|
130 |
-
)
|
131 |
-
postcodes = postcodes.join(wards, on="OSWARD").with_columns(
|
132 |
-
((pl.col("count") / pl.col("Observation")) * 100).alias("prop")
|
133 |
-
)
|
134 |
ward_boundaries = gpd.read_file(
|
135 |
Paths.RAW / "Wards_December_2021_GB_BFE_2022_7523259277605796091.zip"
|
136 |
)
|
@@ -218,7 +243,7 @@ def fig_imd(postcodes):
|
|
218 |
x - bar_width / 2, # Shift to the left
|
219 |
postcodes_pd["perc_count"],
|
220 |
width=bar_width,
|
221 |
-
label="Percentage of
|
222 |
)
|
223 |
|
224 |
# Plot the second set of bars
|
@@ -226,17 +251,17 @@ def fig_imd(postcodes):
|
|
226 |
x + bar_width / 2, # Shift to the right
|
227 |
postcodes_pd["perc_pop"],
|
228 |
width=bar_width,
|
229 |
-
label="Percentage of Population (
|
230 |
)
|
231 |
|
232 |
# Set labels and ticks
|
233 |
ax1.set_xlabel("IMD Quintile")
|
234 |
-
ax1.set_ylabel("Proportion of Population (
|
235 |
ax1.set_xticks(x) # Set x-ticks to correspond to the positions
|
236 |
ax1.set_xticklabels(postcodes_pd["LA_decile"])
|
237 |
|
238 |
# Add a legend
|
239 |
-
ax1.legend()
|
240 |
|
241 |
# Adjust layout
|
242 |
plt.tight_layout()
|
@@ -284,15 +309,20 @@ The following section provides a detailed breakdown of notable details from resp
|
|
284 |
f"{introduction_paragraph}\n\n"
|
285 |
"\n# Figures\n\n"
|
286 |
f"{figures_paragraph}\n\n"
|
287 |
-
f"{{#fig-imd}}\n\n"
|
290 |
-
"
|
|
|
291 |
f"{themes_paragraph}\n\n"
|
292 |
f"{themes}{{#tbl-themes}}\n\n"
|
293 |
-
"##
|
|
|
|
|
294 |
f"{support_policies}\n\n"
|
295 |
-
"##
|
|
|
|
|
296 |
f"{object_policies}\n\n"
|
297 |
"## Other\n\n"
|
298 |
f"{other_policies}\n\n"
|
|
|
4 |
from collections import Counter
|
5 |
|
6 |
import geopandas as gpd
|
7 |
+
import matplotlib as mpl
|
8 |
import matplotlib.pyplot as plt
|
9 |
import numpy as np
|
10 |
import polars as pl
|
|
|
12 |
|
13 |
from planning_ai.common.utils import Paths
|
14 |
|
15 |
+
mpl.rcParams["text.usetex"] = True
|
16 |
+
mpl.rcParams["text.latex.preamble"] = r"\usepackage{libertine}"
|
17 |
+
|
18 |
|
19 |
def _process_postcodes(final):
|
20 |
documents = final["documents"]
|
|
|
87 |
|
88 |
def _process_themes(final):
|
89 |
documents = final["documents"]
|
90 |
+
themes = Counter(
|
91 |
+
[theme["theme"].value for doc in documents for theme in doc["themes"]]
|
92 |
+
)
|
93 |
themes = pl.DataFrame(themes).transpose(include_header=True)
|
94 |
themes_breakdown = themes.with_columns(
|
95 |
((pl.col("column_0") / pl.sum("column_0")) * 100).round(2).alias("percentage")
|
|
|
101 |
|
102 |
|
103 |
def fig_oa(postcodes):
|
104 |
+
oa_pop = pl.read_csv(Paths.RAW / "oa_populations.csv")
|
105 |
+
oa_pop = (
|
106 |
+
oa_pop.group_by(pl.col("Output Areas Code"))
|
107 |
+
.sum()
|
108 |
+
.rename({"Output Areas Code": "OA2021", "Observation": "population"})
|
109 |
+
.select(["OA2021", "population"])
|
110 |
+
)
|
111 |
+
|
112 |
oac = pl.read_csv(Paths.RAW / "oac21ew.csv")
|
113 |
+
oac = oac.join(oa_pop, left_on="oa21cd", right_on="OA2021")
|
114 |
+
oac = (
|
115 |
postcodes.join(oac, left_on="OA21", right_on="oa21cd")
|
116 |
.group_by("supergroup")
|
117 |
+
.sum()
|
118 |
+
.select(["supergroup", "population", "count"])
|
119 |
.sort("supergroup")
|
120 |
+
.with_columns(
|
121 |
+
((pl.col("count") / pl.col("count").sum()) * 100).alias("perc_count"),
|
122 |
+
((pl.col("population") / pl.col("population").sum()) * 100).alias(
|
123 |
+
"perc_pop"
|
124 |
+
),
|
125 |
+
)
|
126 |
)
|
127 |
+
oa_pd = oac.to_pandas()
|
128 |
|
129 |
_, ax1 = plt.subplots()
|
130 |
+
bar_width = 0.35
|
131 |
+
x = np.arange(len(oa_pd))
|
132 |
+
|
133 |
+
ax1.bar(
|
134 |
+
x - bar_width / 2,
|
135 |
+
oa_pd["perc_count"],
|
136 |
+
width=bar_width,
|
137 |
+
label="Percentage of Representations (\%)",
|
138 |
+
)
|
139 |
+
|
140 |
+
ax1.bar(
|
141 |
+
x + bar_width / 2,
|
142 |
+
oa_pd["perc_pop"],
|
143 |
+
width=bar_width,
|
144 |
+
label="Percentage of Population (\%)",
|
145 |
+
)
|
146 |
|
|
|
147 |
ax1.set_xlabel("Output Area Classification (OAC) Supergroup")
|
148 |
+
ax1.set_ylabel("Proportion of Population (\%)")
|
149 |
+
ax1.set_xticks(x)
|
150 |
+
ax1.set_xticklabels(oa_pd["supergroup"])
|
151 |
|
152 |
+
ax1.legend(loc="upper center", bbox_to_anchor=(0.5, -0.1), ncol=5, frameon=False)
|
153 |
plt.tight_layout()
|
154 |
|
155 |
plt.savefig(Paths.SUMMARY / "figs" / "oas.png")
|
156 |
|
157 |
|
158 |
def fig_wards(postcodes):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
ward_boundaries = gpd.read_file(
|
160 |
Paths.RAW / "Wards_December_2021_GB_BFE_2022_7523259277605796091.zip"
|
161 |
)
|
|
|
243 |
x - bar_width / 2, # Shift to the left
|
244 |
postcodes_pd["perc_count"],
|
245 |
width=bar_width,
|
246 |
+
label="Percentage of Representations (\%)",
|
247 |
)
|
248 |
|
249 |
# Plot the second set of bars
|
|
|
251 |
x + bar_width / 2, # Shift to the right
|
252 |
postcodes_pd["perc_pop"],
|
253 |
width=bar_width,
|
254 |
+
label="Percentage of Population (\%)",
|
255 |
)
|
256 |
|
257 |
# Set labels and ticks
|
258 |
ax1.set_xlabel("IMD Quintile")
|
259 |
+
ax1.set_ylabel("Proportion of Population (\%)")
|
260 |
ax1.set_xticks(x) # Set x-ticks to correspond to the positions
|
261 |
ax1.set_xticklabels(postcodes_pd["LA_decile"])
|
262 |
|
263 |
# Add a legend
|
264 |
+
ax1.legend(loc="upper center", bbox_to_anchor=(0.5, -0.1), ncol=5, frameon=False)
|
265 |
|
266 |
# Adjust layout
|
267 |
plt.tight_layout()
|
|
|
309 |
f"{introduction_paragraph}\n\n"
|
310 |
"\n# Figures\n\n"
|
311 |
f"{figures_paragraph}\n\n"
|
312 |
+
f"{{#fig-wards}}\n\n"
|
313 |
+
f"{{#fig-oas}}\n\n"
|
314 |
f"{{#fig-imd}}\n\n"
|
315 |
+
r"\newpage"
|
316 |
+
"\n\n# Themes and Policies\n\n"
|
317 |
f"{themes_paragraph}\n\n"
|
318 |
f"{themes}{{#tbl-themes}}\n\n"
|
319 |
+
"## Supporting Representations\n\n"
|
320 |
+
"The following section outlines key points relating to policies, taken from documents where the "
|
321 |
+
"respondent indicated that they support the plan.\n\n"
|
322 |
f"{support_policies}\n\n"
|
323 |
+
"## Objecting Representations\n\n"
|
324 |
+
"The following section outlines key points relating to policies, taken from documents where the "
|
325 |
+
"respondent indicated that they object to the plan.\n\n"
|
326 |
f"{object_policies}\n\n"
|
327 |
"## Other\n\n"
|
328 |
f"{other_policies}\n\n"
|
planning_ai/main.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1 |
-
import random
|
2 |
import time
|
3 |
from pathlib import Path
|
4 |
|
|
|
|
|
1 |
import time
|
2 |
from pathlib import Path
|
3 |
|