cboettig commited on
Commit
8750848
·
unverified ·
1 Parent(s): fb98f2d

here we go

Browse files
Files changed (1) hide show
  1. app.py +255 -42
app.py CHANGED
@@ -14,19 +14,133 @@
14
  # +
15
  import leafmap.foliumap as leafmap
16
  import streamlit as st
 
 
 
 
 
17
  st.set_page_config(layout="wide", page_title="Protected Areas Explorer", page_icon=":globe:")
18
 
19
- low = st.slider("Red when richness is less than", 0, 30, 2)
20
- high = st.slider("Green for richness larger than", 0, 30, 3)
21
- "missing data in grey. in-between values in blue"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
- red = "#850101"
24
- purple = "#BF40BF"
25
- green = "#005a00"
26
- blue = "#3388ff"
27
 
28
 
29
  # +
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  richness = {
32
  "fill-color": [
@@ -37,12 +151,41 @@ richness = {
37
  # ["min", ["number", ["get", "richness"]]],
38
  "rgb(252, 226, 220)",
39
  #["max", ["get", "richness"]],
40
- 8,
41
  "rgb(102, 16, 66)"
42
  ],
43
  "fill-opacity": 0.9
44
  }
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  r = {
47
  "fill-color": [
48
  "rgb",
@@ -59,31 +202,7 @@ r = {
59
 
60
  # +
61
 
62
- thresholds = {
63
- "fill-color":
64
- ['case',
65
- ['<', ['get', 'richness'], low],
66
- red,
67
- ['>=', ['get', 'richness'], high],
68
- green,
69
- blue # default
70
- ],
71
- "fill-opacity": 0.5
72
- }
73
 
74
- bucket = {
75
- "fill-color":
76
- ['case',
77
- ['==', ['get', 'bucket'], 'public'],
78
- blue,
79
- ['==', ['get', 'bucket'], 'private'],
80
- red,
81
- ['==', ['get', 'bucket'], 'tribal'],
82
- purple,
83
- green # default (bucket == mixed)
84
- ],
85
- "fill-opacity": 0.5
86
- }
87
 
88
  # -
89
 
@@ -106,22 +225,116 @@ style = {
106
  "source": "pad",
107
  "source-layer": "pad-mobi",
108
  "type": "fill",
109
- "paint": r
110
  }]}
111
- m = leafmap.Map(center=[35, -100], zoom=3)
 
 
 
 
 
112
  #m.add_basemap("CartoDB.DarkMatter")
113
- m.add_pmtiles(url, name="Public", style=style, overlay=True, show=True, zoom_to_layer=False)
114
- #m.to_streamlit(height=900)
115
- m
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
  # +
118
- import ibis
119
- from ibis import _
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
- t = ibis.read_parquet("https://data.source.coop/cboettig/pad-us-3/pad-mobi.parquet")
 
 
 
 
122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  # -
124
 
125
- t.group_by(_.bucket).aggregate(mean = (_.richness * _.area).mean() / _.area.sum()).to_pandas()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
- t.group_by(_.bucket).aggregate(mean = (_.rsr * _.area).mean() / _.area.sum()).to_pandas()
 
14
  # +
15
  import leafmap.foliumap as leafmap
16
  import streamlit as st
17
+ import altair as alt
18
+ import ibis
19
+ from ibis import _
20
+ import ibis.selectors as s
21
+
22
  st.set_page_config(layout="wide", page_title="Protected Areas Explorer", page_icon=":globe:")
23
 
24
+ '''
25
+ # US Protected Area Database Explorer
26
+
27
+ The map below shows all continental US protected areas overlaid on [NatureServe's Map of Biodiversity Importance](https://www.natureserve.org/map-biodiversity-importance)
28
+ which shows species richness for some 2,216 imperiled species in (990 m grid cells).
29
+ Use the later tool in the top right to toggle layers on and off for visibility.
30
+ Zoom into the map for more detailed rendering -- e.g. try exploring the many tiny public mixed used lands inside Los Angeles.
31
+ Mouse over any polygon to see details about name, ownership, mean species richness, and mean rarity-weighted-richness.
32
+
33
+ By default, areas are divided into the following categories:
34
+ - Publicly managed lands in Gap 1 & 2 (e.g. National Parks) ("public use", blue)
35
+ - Publicly managed lands in Gap 3 & 4 (most national forests, BLM lands, etc)
36
+ - Privately managed lands
37
+ - Tribally managed lands
38
+
39
+ Alternative color rules can be applied, for instance, to distinguish between easements (rented) and fee (owned) protected areas. Below the interactive map,
40
+ charts summarize the total protected area and mean richness and mean RSR within each group.
41
+
42
+ '''
43
+ # -
44
 
45
+ private_color = "#850101" # red
46
+ tribal_color = "#BF40BF" # purple
47
+ mixed_color = "#005a00" # green
48
+ public_color = "#3388ff" # blue
49
 
50
 
51
  # +
52
+ with st.sidebar:
53
+
54
+ "## Map controls"
55
+
56
+ style_choice = st.radio(
57
+ "Color areas by",
58
+ ["management type",
59
+ "Fee/Easement",
60
+ "species richness (thresholds)",
61
+ "species richness (continuous)",
62
+ "custom"]
63
+ )
64
+
65
+ "### Management Types Color selector"
66
+
67
+ public_color = st.color_picker('Color for Public Protected (Gap 1 & 2) lands', public_color)
68
+ mixed_color = st.color_picker('Color for Public Mixed Use lands', mixed_color)
69
+ tribal_color = st.color_picker('Color for Tribal managed lands', tribal_color)
70
+ private_color = st.color_picker('Color for privately managed land', private_color)
71
+
72
+ "### Threshold selector"
73
+
74
+ low = st.slider("Red when richness is less than", 0, 30, 2)
75
+ high = st.slider("Green for richness larger than", 0, 30, 3)
76
+ "missing data in grey. in-between values in blue"
77
+
78
+
79
+ "### Custom styles"
80
+ custom = st.text_area("Define a custom mapbox fill-color rule",
81
+ value = '''{
82
+ "fill-color":
83
+ ['case',
84
+ ['==', ['get', 'bucket'], 'public'],
85
+ public_color,
86
+ ['==', ['get', 'bucket'], 'private'],
87
+ private_color,
88
+ ['==', ['get', 'bucket'], 'tribal'],
89
+ tribal_color,
90
+ mixed_color # default (bucket == mixed)
91
+ ],
92
+ "fill-opacity": 0.5
93
+ }
94
+ ''',
95
+ height = 300
96
+ )
97
+
98
+
99
+
100
+ # +
101
+
102
+ bucket = {
103
+ "fill-color":
104
+ ['case',
105
+ ['==', ['get', 'bucket'], 'public'],
106
+ public_color,
107
+ ['==', ['get', 'bucket'], 'private'],
108
+ private_color,
109
+ ['==', ['get', 'bucket'], 'tribal'],
110
+ tribal_color,
111
+ mixed_color # default (bucket == mixed)
112
+ ],
113
+ "fill-opacity": 0.5
114
+ }
115
+
116
+
117
+ easement = {
118
+ "fill-color":
119
+ ['case',
120
+ ['==', ['get', ''], 'Fee'],
121
+ public_color,
122
+ ['==', ['get', 'FeatClass'], 'Easement'],
123
+ private_color,
124
+ ['==', ['get', 'FeatClass'], 'Proclamation'],
125
+ tribal_color,
126
+ mixed_color # default (bucket == mixed)
127
+ ],
128
+ "fill-opacity": 0.5
129
+ }
130
+
131
+
132
+ thresholds = {
133
+ "fill-color":
134
+ ['case',
135
+ ['<', ['get', 'richness'], low],
136
+ private_color,
137
+ ['>=', ['get', 'richness'], high],
138
+ mixed_color,
139
+ public_color # default
140
+ ],
141
+ "fill-opacity": 0.5
142
+ }
143
+
144
 
145
  richness = {
146
  "fill-color": [
 
151
  # ["min", ["number", ["get", "richness"]]],
152
  "rgb(252, 226, 220)",
153
  #["max", ["get", "richness"]],
154
+ 6,
155
  "rgb(102, 16, 66)"
156
  ],
157
  "fill-opacity": 0.9
158
  }
159
 
160
+ rsr = {
161
+ "fill-color": [
162
+ "interpolate",
163
+ ["linear"],
164
+ ["get", "rsr"],
165
+ 0,
166
+ # ["min", ["number", ["get", "richness"]]],
167
+ "rgb(252, 226, 220)",
168
+ #["max", ["get", "richness"]],
169
+ 6,
170
+ "rgb(102, 16, 66)"
171
+ ],
172
+ "fill-opacity": 0.9
173
+ }
174
+
175
+
176
+ # +
177
+ if style_choice == "management type":
178
+ paint_fill = bucket
179
+ if style_choice == "Fee/Easement":
180
+ paint_fill = easement
181
+ if style_choice == "species richness (thresholds)":
182
+ paint_fill = thresholds
183
+ if style_choice == "species richness (continuous)":
184
+ paint_fill = richness
185
+ if style_choice == "custom":
186
+ paint_fill = custom
187
+
188
+
189
  r = {
190
  "fill-color": [
191
  "rgb",
 
202
 
203
  # +
204
 
 
 
 
 
 
 
 
 
 
 
 
205
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
  # -
208
 
 
225
  "source": "pad",
226
  "source-layer": "pad-mobi",
227
  "type": "fill",
228
+ "paint": paint_fill
229
  }]}
230
+ m = leafmap.Map(center=[35, -100],
231
+ zoom=4,
232
+ layers_control=True,
233
+ draw_control=False,
234
+ measure_control=False,
235
+ fullscreen_control=True)
236
  #m.add_basemap("CartoDB.DarkMatter")
237
+
238
+ m.add_basemap("Esri.WorldShadedRelief")
239
+
240
+ m.add_tile_layer(
241
+ url="https://minio.carlboettiger.info/shared-data/mobi-tiles/red/{z}/{x}/{y}.png",
242
+ name="MOBI",
243
+ attribution="NatureServe",
244
+ opacity=0.9
245
+ )
246
+
247
+
248
+ m.add_pmtiles(url, name="Protected Areas (PAD-US-3)", style=style, overlay=True, show=True, zoom_to_layer=False)
249
+
250
+
251
+ m.to_streamlit(height=900)
252
+
253
+ # -
254
+
255
+
256
 
257
  # +
258
+ #parquet = "https://data.source.coop/cboettig/pad-us-3/pad-mobi.parquet"
259
+ parquet = "https://minio.carlboettiger.info/public-biodiversity/pad-us-3/pad-mobi.parquet"
260
+
261
+ t = ibis.read_parquet(parquet)
262
+
263
+
264
+ # +
265
+ us_lower_48_area_m2 = 7.8e+12
266
+
267
+ @st.cache_data()
268
+ def summary_table():
269
+ x = ibis.memtable({"bucket": ["public", "tribal", "mixed", "private"],
270
+ "color": [public_color, tribal_color, mixed_color, private_color]})
271
+ df = (t.
272
+ group_by(_.bucket).
273
+ aggregate(percent_protected = 100 * _.area.sum() / us_lower_48_area_m2,
274
+ mean_richness = (_.richness * _.area).sum() / _.area.sum(),
275
+ mean_rsr = (_.rsr * _.area).sum() / _.area.sum()
276
+ ).
277
+ mutate(percent_protected = _.percent_protected.round())
278
+ ).inner_join(x, "bucket")
279
+ return df.to_pandas()
280
+
281
+ df = summary_table()
282
+ # st.table(richness_table)
283
+
284
+
285
+ # +
286
+ #summary_table.to_pandas()
287
+
288
+ # +
289
+
290
+ base = alt.Chart(df).encode(
291
+ alt.Theta("percent_protected:Q").stack(True),
292
+ alt.Color("color:N").scale(None).legend(None)
293
+ )
294
+
295
 
296
+ area_chart = (
297
+ base.mark_arc(innerRadius=50, outerRadius=120) +
298
+ base.mark_text(radius=170, size=20).encode(text="bucket") +
299
+ base.mark_text(radius=135, size=20).encode(text="percent_protected:N")
300
+ )
301
 
302
+ # area_chart
303
+
304
+ # +
305
+
306
+ richness_chart = alt.Chart(df).mark_bar().encode(
307
+ x='bucket',
308
+ y='mean_richness',
309
+ color=alt.Color('color').scale(None)
310
+ )
311
+ #richness_chart
312
+
313
+
314
+ # +
315
+
316
+ rsr_chart = alt.Chart(df).mark_bar().encode(
317
+ x='bucket',
318
+ y='mean_rsr',
319
+ color=alt.Color('color').scale(None)
320
+ )
321
  # -
322
 
323
+ "## Summary Statistics"
324
+
325
+ # +
326
+ col1, col2, col3 = st.columns(3)
327
+
328
+ with col1:
329
+ st.altair_chart(area_chart, use_container_width=True)
330
+ "Percent of Continental US Area in each group"
331
+ # -
332
+
333
+ with col2:
334
+ st.altair_chart(richness_chart, use_container_width=True)
335
+
336
+
337
+ with col3:
338
+ st.altair_chart(rsr_chart, use_container_width=True)
339
+
340