Spaces:
Sleeping
Sleeping
Commit
Β·
3c693f3
1
Parent(s):
7289e5d
fixed chart filters
Browse files
app.py
CHANGED
@@ -83,30 +83,76 @@ us_lower_48_area_m2 = 7.8e+12
|
|
83 |
## Helper functions
|
84 |
|
85 |
#@st.cache_resource
|
86 |
-
def ibis_connection(parquet):
|
87 |
-
|
88 |
-
pad_data = ibis_connection(parquet)
|
|
|
|
|
|
|
|
|
89 |
|
90 |
#@st.cache_data()
|
91 |
-
def summary_table(column, colors):
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
df = df.to_pandas()
|
107 |
-
df[column] = df[column].astype(str)
|
108 |
return df
|
109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
def bar_chart(df, x, y):
|
111 |
chart = alt.Chart(df).mark_bar().encode(
|
112 |
x=x,
|
@@ -345,7 +391,9 @@ bil_fill = {
|
|
345 |
#"fill-extrusion-height": ["*", .01, ["get", "FundingAmo"]],
|
346 |
"fill-extrusion-height": ["*", 50, ["sqrt", ["get", "FundingAmo"]]],
|
347 |
"fill-extrusion-opacity": 0.9,
|
348 |
-
}
|
|
|
|
|
349 |
|
350 |
###########################################################################################################
|
351 |
|
@@ -383,66 +431,72 @@ with st.sidebar:
|
|
383 |
# if st.toggle("Protected Areas", True):
|
384 |
|
385 |
color_choice = st.radio("Color by:", style_options)
|
|
|
386 |
alpha = st.slider("transparency", 0.0, 1.0, 0.5)
|
387 |
|
388 |
"Data layers:"
|
389 |
with st.expander("π¦ Biodiversity"):
|
|
|
390 |
show_richness = st.toggle("Species Richness", False)
|
|
|
391 |
if show_richness:
|
392 |
m.add_tile_layer(url="https://data.source.coop/cboettig/mobi/tiles/red/species-richness-all/{z}/{x}/{y}.png",
|
393 |
name="MOBI Species Richness",
|
394 |
attribution="NatureServe",
|
395 |
-
opacity=
|
396 |
)
|
397 |
show_rsr = st.toggle("Range-Size Rarity")
|
398 |
if show_rsr:
|
399 |
m.add_tile_layer(url="https://data.source.coop/cboettig/mobi/tiles/green/range-size-rarity-all/{z}/{x}/{y}.png",
|
400 |
name="MOBI Range-Size Rarity",
|
401 |
attribution="NatureServe",
|
402 |
-
opacity=
|
403 |
)
|
404 |
#m.add_cog_layer("https://data.source.coop/cboettig/mobi/range-size-rarity-all/RSR_All.tif",
|
405 |
# palette="greens", name="Range-Size Rarity", transparent_bg=True, opacity = 0.9, fit_bounds=False)
|
406 |
with st.expander("β
Carbon & Climate"):
|
|
|
407 |
show_carbon_lost = st.toggle("Carbon Lost (2002-2022)")
|
|
|
408 |
if show_carbon_lost:
|
409 |
m.add_cog_layer("https://data.source.coop/vizzuality/lg-land-carbon-data/deforest_carbon_100m_cog.tif",
|
410 |
-
palette="reds", name="Carbon Lost (2002-2022)", transparent_bg=True, opacity =
|
411 |
-
|
412 |
-
if
|
413 |
m.add_cog_layer("https://data.source.coop/cboettig/carbon/cogs/irrecoverable_c_total_2018.tif",
|
414 |
-
palette="purples", name="Irrecoverable Carbon", transparent_bg=True, opacity =
|
415 |
-
|
416 |
-
if
|
417 |
m.add_cog_layer("https://data.source.coop/cboettig/carbon/cogs/manageable_c_total_2018.tif",
|
418 |
-
palette="greens", name="Manageable Carbon", transparent_bg=True, opacity =
|
419 |
|
420 |
with st.expander("π Human Impacts"):
|
|
|
421 |
show_human_impact = st.toggle("Human Impact")
|
422 |
if show_human_impact:
|
423 |
hi="https://data.source.coop/vizzuality/hfp-100/hfp_2021_100m_v1-2_cog.tif"
|
424 |
-
m.add_cog_layer(hi, palette="purples", name="Human Impact", transparent_bg=True, opacity =
|
425 |
|
426 |
-
show_crop_expansion = st.toggle("
|
427 |
if show_crop_expansion:
|
428 |
-
m.add_cog_layer("https://data.source.coop/vizzuality/lg-land-carbon-data/natcrop_expansion_100m_cog.tif",)
|
429 |
# palette="greens", name="cropland expansion", transparent_bg=True, opacity = 0.8, fit_bounds=False)
|
430 |
-
|
431 |
-
if
|
432 |
m.add_cog_layer("https://data.source.coop/vizzuality/lg-land-carbon-data/natcrop_bii_100m_cog.tif",
|
433 |
-
palette="reds", name="
|
434 |
-
|
435 |
-
if
|
436 |
m.add_cog_layer("https://data.source.coop/vizzuality/lg-land-carbon-data/natcrop_fii_100m_cog.tif",
|
437 |
-
palette="reds", name="
|
438 |
|
439 |
|
440 |
with st.expander("π° Conservation Investment"):
|
441 |
if st.toggle("Bipartisan Infrastructure Law"):
|
442 |
m.add_geojson(bil_url, layer_type="fill-extrusion", paint=bil_fill, name="BIL", fit_bounds=False)
|
443 |
-
|
444 |
-
with st.expander("π» Custom
|
445 |
-
if st.toggle("Custom
|
446 |
|
447 |
code = st.text_area(label = "leafmap code:",
|
448 |
value = code_ex,
|
@@ -519,6 +573,28 @@ colors = (ibis
|
|
519 |
# +
|
520 |
|
521 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
522 |
main = st.container()
|
523 |
|
524 |
with main:
|
@@ -527,13 +603,13 @@ with main:
|
|
527 |
with map_col:
|
528 |
to_streamlit(m, height=700)
|
529 |
|
530 |
-
df = summary_table(column, colors)
|
531 |
-
total_percent = df.percent_protected.sum().round(1)
|
532 |
-
richness_chart = bar_chart(df, column, 'mean_richness')
|
533 |
-
rsr_chart = bar_chart(df, column, 'mean_rsr')
|
534 |
-
carbon_lost = bar_chart(df, column, 'carbon_lost')
|
535 |
-
crop_expansion = bar_chart(df, column, 'crop_expansion')
|
536 |
-
human_impact = bar_chart(df, column, 'human_impact')
|
537 |
|
538 |
with stats_col:
|
539 |
with st.container():
|
@@ -551,15 +627,33 @@ with main:
|
|
551 |
|
552 |
if show_carbon_lost:
|
553 |
"Carbon Lost ('02-'22)"
|
554 |
-
st.altair_chart(
|
555 |
|
556 |
if show_crop_expansion:
|
557 |
-
"Crop
|
558 |
-
st.altair_chart(
|
559 |
|
560 |
if show_human_impact:
|
561 |
"Human Impact"
|
562 |
-
st.altair_chart(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
563 |
|
564 |
|
565 |
# +
|
|
|
83 |
## Helper functions
|
84 |
|
85 |
#@st.cache_resource
|
86 |
+
# def ibis_connection(parquet):
|
87 |
+
# return ibis.read_parquet(parquet)
|
88 |
+
# pad_data = ibis_connection(parquet)
|
89 |
+
|
90 |
+
con = ibis.duckdb.connect(extensions=["spatial"])
|
91 |
+
pad_data = con.read_parquet(parquet)
|
92 |
+
|
93 |
|
94 |
#@st.cache_data()
|
95 |
+
# def summary_table(column, colors):
|
96 |
+
# df = (pad_data
|
97 |
+
# .rename(area = "area_square_meters")
|
98 |
+
# .group_by(_[column])
|
99 |
+
# .aggregate(
|
100 |
+
# )
|
101 |
+
# .mutate(percent_protected = _.percent_protected.round(1))
|
102 |
+
# .inner_join(colors, column)
|
103 |
+
# )
|
104 |
+
# df = df.to_pandas()
|
105 |
+
# df[column] = df[column].astype(str)
|
106 |
+
# return df
|
107 |
+
|
108 |
+
|
109 |
+
from functools import reduce
|
110 |
+
|
111 |
+
def get_summary(pad_data, combined_filter, column, colors=None): #summary stats, based on filtered data
|
112 |
+
# ca = ca.filter(_.gap_code.isin([1,2])) #only gap 1 and 2
|
113 |
+
df = pad_data.filter(combined_filter)
|
114 |
+
df = (df
|
115 |
+
.rename(area = "area_square_meters")
|
116 |
+
.group_by(*column) # unpack the list for grouping
|
117 |
+
.aggregate(hectares_protected = (_.area.sum() / 10000).round(),
|
118 |
+
percent_protected = 100 * _.area.sum() / us_lower_48_area_m2,
|
119 |
+
mean_richness = (_.richness * _.area).sum() / _.area.sum(),
|
120 |
+
mean_rsr = (_.rsr * _.area).sum() / _.area.sum(),
|
121 |
+
mean_irrecoverable_carbon = (_.irrecoverable_carbon * _.area).sum() / _.area.sum(),
|
122 |
+
mean_manageable_carbon = (_.manageable_carbon * _.area).sum() / _.area.sum(),
|
123 |
+
mean_carbon_lost = (_.deforest_carbon * _.area).sum() / _.area.sum(),
|
124 |
+
mean_crop_expansion = (_.crop_expansion * _.area).sum() / _.area.sum(),
|
125 |
+
mean_human_impact = (_.human_impact * _.area).sum() / _.area.sum(),
|
126 |
+
mean_forest_integrity_loss = (_.forest_integrity_loss*_.area).sum() / _.area.sum(),
|
127 |
+
mean_bio_intact_loss = (_.biodiversity_intactness_loss * _.area).sum() / _.area.sum(),
|
128 |
+
)
|
129 |
+
.mutate(percent_protected=_.percent_protected.round(1))
|
130 |
+
)
|
131 |
+
if colors is not None and not colors.empty: #only the df will have colors, df_tab doesn't since we are printing it.
|
132 |
+
df = df.inner_join(colors, column)
|
133 |
+
df = df.cast({col: "string" for col in column})
|
134 |
df = df.to_pandas()
|
|
|
135 |
return df
|
136 |
|
137 |
+
|
138 |
+
def summary_table(column, colors, filter_cols, filter_vals,colorby_vals): # get df for charts + df_tab for printed table + df_percent for percentage (only gap 1 and 2)
|
139 |
+
filters = []
|
140 |
+
if filter_cols and filter_vals: #if a filter is selected, add to list of filters
|
141 |
+
for filter_col, filter_val in zip(filter_cols, filter_vals):
|
142 |
+
if len(filter_val) > 1:
|
143 |
+
filters.append(getattr(_, filter_col).isin(filter_val))
|
144 |
+
else:
|
145 |
+
filters.append(getattr(_, filter_col) == filter_val[0])
|
146 |
+
if column not in filter_cols: #show color_by column in table by adding it as a filter (if it's not already a filter)
|
147 |
+
filter_cols.append(column)
|
148 |
+
filters.append(getattr(_, column).isin(colorby_vals[column]))
|
149 |
+
combined_filter = reduce(lambda x, y: x & y, filters) #combining all the filters into ibis filter expression
|
150 |
+
df = get_summary(pad_data, combined_filter, [column], colors) # df used for charts
|
151 |
+
df_tab = get_summary(pad_data, combined_filter, filter_cols, colors = None) #df used for printed table
|
152 |
+
df_percent = get_summary(pad_data.filter(_.gap_code.isin([1,2])), combined_filter, [column], colors) # only gap 1 and 2 count towards percentage
|
153 |
+
return df, df_tab, df_percent
|
154 |
+
|
155 |
+
|
156 |
def bar_chart(df, x, y):
|
157 |
chart = alt.Chart(df).mark_bar().encode(
|
158 |
x=x,
|
|
|
391 |
#"fill-extrusion-height": ["*", .01, ["get", "FundingAmo"]],
|
392 |
"fill-extrusion-height": ["*", 50, ["sqrt", ["get", "FundingAmo"]]],
|
393 |
"fill-extrusion-opacity": 0.9,
|
394 |
+
}
|
395 |
+
|
396 |
+
|
397 |
|
398 |
###########################################################################################################
|
399 |
|
|
|
431 |
# if st.toggle("Protected Areas", True):
|
432 |
|
433 |
color_choice = st.radio("Color by:", style_options)
|
434 |
+
colorby_vals = getColorVals(style_options, color_choice) #get options for selected color_by column
|
435 |
alpha = st.slider("transparency", 0.0, 1.0, 0.5)
|
436 |
|
437 |
"Data layers:"
|
438 |
with st.expander("π¦ Biodiversity"):
|
439 |
+
a_bio = st.slider("transparency", 0.0, 1.0, 0.4, key = "biodiversity")
|
440 |
show_richness = st.toggle("Species Richness", False)
|
441 |
+
|
442 |
if show_richness:
|
443 |
m.add_tile_layer(url="https://data.source.coop/cboettig/mobi/tiles/red/species-richness-all/{z}/{x}/{y}.png",
|
444 |
name="MOBI Species Richness",
|
445 |
attribution="NatureServe",
|
446 |
+
opacity=a_bio
|
447 |
)
|
448 |
show_rsr = st.toggle("Range-Size Rarity")
|
449 |
if show_rsr:
|
450 |
m.add_tile_layer(url="https://data.source.coop/cboettig/mobi/tiles/green/range-size-rarity-all/{z}/{x}/{y}.png",
|
451 |
name="MOBI Range-Size Rarity",
|
452 |
attribution="NatureServe",
|
453 |
+
opacity=a_bio
|
454 |
)
|
455 |
#m.add_cog_layer("https://data.source.coop/cboettig/mobi/range-size-rarity-all/RSR_All.tif",
|
456 |
# palette="greens", name="Range-Size Rarity", transparent_bg=True, opacity = 0.9, fit_bounds=False)
|
457 |
with st.expander("β
Carbon & Climate"):
|
458 |
+
a_climate = st.slider("transparency", 0.0, 1.0, 0.3, key = "climate")
|
459 |
show_carbon_lost = st.toggle("Carbon Lost (2002-2022)")
|
460 |
+
|
461 |
if show_carbon_lost:
|
462 |
m.add_cog_layer("https://data.source.coop/vizzuality/lg-land-carbon-data/deforest_carbon_100m_cog.tif",
|
463 |
+
palette="reds", name="Carbon Lost (2002-2022)", transparent_bg=True, opacity = a_climate, fit_bounds=False)
|
464 |
+
show_irr_carbon = st.toggle("Irrecoverable Carbon")
|
465 |
+
if show_irr_carbon:
|
466 |
m.add_cog_layer("https://data.source.coop/cboettig/carbon/cogs/irrecoverable_c_total_2018.tif",
|
467 |
+
palette="purples", name="Irrecoverable Carbon", transparent_bg=True, opacity = a_climate, fit_bounds=False)
|
468 |
+
show_man_carbon = st.toggle("Manageable Carbon")
|
469 |
+
if show_man_carbon:
|
470 |
m.add_cog_layer("https://data.source.coop/cboettig/carbon/cogs/manageable_c_total_2018.tif",
|
471 |
+
palette="greens", name="Manageable Carbon", transparent_bg=True, opacity = a_climate, fit_bounds=False)
|
472 |
|
473 |
with st.expander("π Human Impacts"):
|
474 |
+
a_hi = st.slider("transparency", 0.0, 1.0, 0.5, key = "hi")
|
475 |
show_human_impact = st.toggle("Human Impact")
|
476 |
if show_human_impact:
|
477 |
hi="https://data.source.coop/vizzuality/hfp-100/hfp_2021_100m_v1-2_cog.tif"
|
478 |
+
m.add_cog_layer(hi, palette="purples", name="Human Impact", transparent_bg=True, opacity = a_hi, fit_bounds=False)
|
479 |
|
480 |
+
show_crop_expansion = st.toggle("Cropland Expansion")
|
481 |
if show_crop_expansion:
|
482 |
+
m.add_cog_layer("https://data.source.coop/vizzuality/lg-land-carbon-data/natcrop_expansion_100m_cog.tif",opacity = a_hi, name = "Cropland Expansion")
|
483 |
# palette="greens", name="cropland expansion", transparent_bg=True, opacity = 0.8, fit_bounds=False)
|
484 |
+
show_bio_loss = st.toggle("Biodiversity Intactness Loss")
|
485 |
+
if show_bio_loss:
|
486 |
m.add_cog_layer("https://data.source.coop/vizzuality/lg-land-carbon-data/natcrop_bii_100m_cog.tif",
|
487 |
+
palette="reds", name="Biodiversity Intactness Loss", transparent_bg=True, opacity = a_hi, fit_bounds=False)
|
488 |
+
show_forest_loss = st.toggle("Forest Integrity Loss")
|
489 |
+
if show_forest_loss:
|
490 |
m.add_cog_layer("https://data.source.coop/vizzuality/lg-land-carbon-data/natcrop_fii_100m_cog.tif",
|
491 |
+
palette="reds", name="Forest Integrity Loss", transparent_bg=True, opacity = a_hi, fit_bounds=False)
|
492 |
|
493 |
|
494 |
with st.expander("π° Conservation Investment"):
|
495 |
if st.toggle("Bipartisan Infrastructure Law"):
|
496 |
m.add_geojson(bil_url, layer_type="fill-extrusion", paint=bil_fill, name="BIL", fit_bounds=False)
|
497 |
+
|
498 |
+
with st.expander("π» Custom Code"):
|
499 |
+
if st.toggle("Custom Map Layers"):
|
500 |
|
501 |
code = st.text_area(label = "leafmap code:",
|
502 |
value = code_ex,
|
|
|
573 |
# +
|
574 |
|
575 |
|
576 |
+
|
577 |
+
# get summary tables used for charts + printed table + percentage
|
578 |
+
# df - charts; df_tab - printed table (omits colors) + df_percent - only gap codes 1 & 2 count towards percentage
|
579 |
+
df,df_tab,df_percent = summary_table(column, colors, filter_cols, filter_vals, colorby_vals)
|
580 |
+
|
581 |
+
# compute area covered (only gap 1 and 2)
|
582 |
+
# df_onlygap = df[df.gap_code.isin([1,2])]
|
583 |
+
total_percent = df_percent.percent_protected.sum().round(1)
|
584 |
+
|
585 |
+
|
586 |
+
# charts displayed based on color_by variable
|
587 |
+
richness_chart = bar_chart(df, column, 'mean_richness')
|
588 |
+
rsr_chart = bar_chart(df, column, 'mean_rsr')
|
589 |
+
irr_carbon_chart = bar_chart(df, column, 'mean_irrecoverable_carbon')
|
590 |
+
man_carbon_chart = bar_chart(df, column, 'mean_manageable_carbon')
|
591 |
+
carbon_loss_chart = bar_chart(df, column, 'mean_carbon_lost')
|
592 |
+
hi_chart = bar_chart(df, column, 'mean_human_impact')
|
593 |
+
crop_expansion_chart = bar_chart(df, column, 'mean_crop_expansion')
|
594 |
+
bio_intact_loss_chart = bar_chart(df, column, 'mean_bio_intact_loss')
|
595 |
+
forest_integrity_loss_chart = bar_chart(df, column, 'mean_forest_integrity_loss')
|
596 |
+
|
597 |
+
|
598 |
main = st.container()
|
599 |
|
600 |
with main:
|
|
|
603 |
with map_col:
|
604 |
to_streamlit(m, height=700)
|
605 |
|
606 |
+
# df = summary_table(column, colors)
|
607 |
+
# total_percent = df.percent_protected.sum().round(1)
|
608 |
+
# richness_chart = bar_chart(df, column, 'mean_richness')
|
609 |
+
# rsr_chart = bar_chart(df, column, 'mean_rsr')
|
610 |
+
# carbon_lost = bar_chart(df, column, 'carbon_lost')
|
611 |
+
# crop_expansion = bar_chart(df, column, 'crop_expansion')
|
612 |
+
# human_impact = bar_chart(df, column, 'human_impact')
|
613 |
|
614 |
with stats_col:
|
615 |
with st.container():
|
|
|
627 |
|
628 |
if show_carbon_lost:
|
629 |
"Carbon Lost ('02-'22)"
|
630 |
+
st.altair_chart(carbon_loss_chart, use_container_width=True)
|
631 |
|
632 |
if show_crop_expansion:
|
633 |
+
"Crop Expansion"
|
634 |
+
st.altair_chart(crop_expansion_chart, use_container_width=True)
|
635 |
|
636 |
if show_human_impact:
|
637 |
"Human Impact"
|
638 |
+
st.altair_chart(hi_chart, use_container_width=True)
|
639 |
+
|
640 |
+
if show_irr_carbon:
|
641 |
+
"Irrecoverable Carbon"
|
642 |
+
st.altair_chart(irr_carbon_chart, use_container_width=True)
|
643 |
+
|
644 |
+
if show_man_carbon:
|
645 |
+
"Manageable Carbon"
|
646 |
+
st.altair_chart(man_carbon_chart, use_container_width=True)
|
647 |
+
|
648 |
+
if show_bio_loss:
|
649 |
+
"Biodiversity Intactness Loss"
|
650 |
+
st.altair_chart(bio_intact_loss_chart, use_container_width=True)
|
651 |
+
|
652 |
+
if show_forest_loss:
|
653 |
+
"Forest Integrity Loss"
|
654 |
+
st.altair_chart(forest_integrity_loss_chart, use_container_width=True)
|
655 |
+
# charts displayed based on color_by variable
|
656 |
+
|
657 |
|
658 |
|
659 |
# +
|