-
Notifications
You must be signed in to change notification settings - Fork 2
/
mapper.py
107 lines (90 loc) · 2.59 KB
/
mapper.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import os
import subprocess
import tempfile
import xml.etree.cElementTree as et
import plotly.graph_objects as go
from load_data import load_county_geojson
BACKGROUND = "#222"
def produce_image(by_county, z, zmin, zmax, output, **kwargs):
fig = go.Figure(
go.Choropleth(
locations=by_county.index,
z=z,
colorscale="Viridis",
zmin=zmin,
zmax=zmax,
marker_line_width=0,
**kwargs,
)
)
fig.update(layout_showlegend=False)
fig.update(layout_coloraxis_showscale=False)
fig.update_layout(geo=dict(bgcolor=BACKGROUND, lakecolor=BACKGROUND))
fig.update_geos(scope="usa")
fig.write_image(output)
def produce_full_image(by_state, by_county, out_path, radius_display):
assert out_path.endswith(".png")
s, c = "states.svg", "counties.svg"
produce_image(
by_state,
by_state.mean_density_weighted,
0,
5_000,
s,
locationmode="USA-states",
)
produce_image(
by_county,
by_county.mean_density_weighted,
0,
5_000,
c,
geojson=load_county_geojson(),
)
process(s, s)
process(c, c)
with open("template.svg") as f:
svg = f.read()
svg = svg.replace("$states", s)
svg = svg.replace("$counties", c)
svg = svg.replace("$size", radius_display)
svg_path = "out.svg"
with open(svg_path, "w") as f:
f.write(svg)
subprocess.check_call(["inkscape", "--export-type=png", svg_path, "-w", "4096"])
os.rename("out.png", out_path)
os.remove(svg_path)
os.remove(s)
os.remove(c)
def groups(prefix, r):
for x in r:
if not x.tag.endswith("}g"):
continue
yield prefix, x
yield from groups((x.attrib.get("class"), *prefix), x)
def grab_group(r, name):
for _, g in groups((), r):
# print(*[repr(x) for x in (*p, g.attrib.get("class"))])
if g.attrib.get("class") == name:
return g
raise RuntimeError("not found")
def process(in_path, out_path):
with open(in_path) as f:
result = et.fromstring(f.read())
gs = [grab_group(result, s) for s in ("choroplethlayer",)]
result.clear()
for g in gs:
result.append(g)
with open(out_path, "wb") as f:
f.write(et.tostring(result))
trim(out_path)
def trim(out_path):
subprocess.check_call(
[
"inkscape",
"--batch-process",
"--verb",
"EditSelectAll;FitCanvasToSelection;FileSave;FileQuit",
out_path,
]
)