Spaces:
Running
Running
import streamlit as st | |
import streamlit.components.v1 as components | |
import base64 | |
import leafmap.maplibregl as leafmap | |
import altair as alt | |
import ibis | |
from ibis import _ | |
import ibis.selectors as s | |
from typing import Optional | |
def to_streamlit( | |
self, | |
width: Optional[int] = None, | |
height: Optional[int] = 600, | |
scrolling: Optional[bool] = False, | |
**kwargs, | |
): | |
try: | |
import streamlit.components.v1 as components | |
import base64 | |
raw_html = self.to_html().encode("utf-8") | |
raw_html = base64.b64encode(raw_html).decode() | |
return components.iframe( | |
f"data:text/html;base64,{raw_html}", | |
width=width, | |
height=height, | |
scrolling=scrolling, | |
**kwargs, | |
) | |
except Exception as e: | |
raise Exception(e) | |
ca_pmtiles = "https://data.source.coop/cboettig/ca30x30/ca_areas.pmtiles" | |
# ca_pmtiles = "ca_areas.pmtiles" | |
# ca_parquet = "https://data.source.coop/cboettig/ca30x30/ca_areas.parquet" | |
ca_parquet = "ca_areas.parquet" | |
ca_area_acres = 1.014e8 #acres | |
style_choice = "GAP Status Code" | |
# style_choice = "Easement" | |
# style_choice = "Year" | |
con = ibis.duckdb.connect() | |
ca = (con | |
.read_parquet(ca_parquet) | |
.cast({"SHAPE": "geometry"}) | |
.mutate( | |
area=_.SHAPE.area()) | |
# .head() | |
) | |
# print(ca.schema()) | |
# ca = ca.filter(ca.Release_Year == 2024) | |
private_color = "#DE881E" # orange #"#850101" # red | |
tribal_color = "#BF40BF" # purple | |
mixed_color = "#005a00" # green | |
public_color = "#3388ff" # blue | |
year2023_color = "#26542C" # green | |
year2024_color = "#F3AB3D" # orange | |
def summary_table(column, colors): | |
df = (ca | |
# .rename(area = "area_square_meters") | |
.group_by(column) | |
.aggregate(hectares_protected = (_.area.sum() / 10000).round(), | |
percent_protected = 100 * _.Acres.sum() / ca_area_acres | |
) | |
.mutate(percent_protected = _.percent_protected.round(1), | |
) | |
.inner_join(colors, column) | |
) | |
df = df.to_pandas() | |
df[column] = df[column].astype(str) | |
return df | |
def area_plot(df, column): | |
base = alt.Chart(df).encode( | |
alt.Theta("percent_protected:Q").stack(True), | |
) | |
pie = ( base | |
.mark_arc(innerRadius= 40, outerRadius=100) | |
.encode(alt.Color("color:N").scale(None).legend(None), | |
tooltip=['percent_protected', 'hectares_protected', column]) | |
) | |
text = ( base | |
.mark_text(radius=80, size=14, color="white") | |
.encode(text = column + ":N") | |
) | |
plot = pie # pie + text | |
return plot.properties(width="container", height=300) | |
def pad_style(paint, alpha): | |
return { | |
"version": 8, | |
"sources": { | |
"ca": { | |
"type": "vector", | |
"url": "pmtiles://" + ca_pmtiles, | |
}}, | |
"layers": [{ | |
"id": "layer1", | |
"source": "ca", | |
"source-layer": "CA_Cons_Areas_parentlyr_Merge_ecofix", | |
"type": "fill", | |
"paint": { | |
"fill-color": paint, | |
"fill-opacity": alpha | |
} | |
}]} | |
manager = { | |
'property': 'cpad_MNG_AG_LEV', | |
'type': 'categorical', | |
'stops': [ | |
['Federal', "darkblue"], | |
['State', public_color], | |
['Non Profit', "lightblue"], | |
['Special District', "darkgreen"], | |
['', "grey"], | |
['Joint', "green"], | |
['Tribal', tribal_color], | |
['Private', "darkred"], | |
['City', "pink"], | |
['County', "blue"], | |
['Home Owners Association', "lightgreen"] | |
] | |
} | |
easement = { | |
'property': 'Easement', | |
'type': 'categorical', | |
'stops': [ | |
[0, public_color], | |
[1, private_color] | |
] | |
} | |
year = { | |
'property': 'Release_Year', | |
'type': 'categorical', | |
'stops': [ | |
[2023, year2023_color], | |
[2024, year2024_color] | |
] | |
} | |
access = { | |
'property': 'ACCESS_TYP', | |
'type': 'categorical', | |
'stops': [ | |
['Open Access', public_color], | |
['No Public Access', private_color], | |
['Unknown Access', "grey"], | |
['Restricted Access', tribal_color] | |
] | |
} | |
gap = { | |
'property': 'reGAP', | |
'type': 'categorical', | |
'stops': [ | |
[1, "#26633d"], | |
[2, "#879647"], | |
[3, "#BBBBBB"], | |
[4, "#F8F8F8"] | |
] | |
} | |
style_options = { | |
"GAP Status Code": gap, | |
"Management Agency": manager, | |
"Easement": easement, | |
"Public Access": access, | |
"Year": year | |
} | |
st.set_page_config(layout="wide", page_title="CA Protected Areas Explorer", page_icon=":globe:") | |
''' | |
# CA 30X30 Prototype | |
''' | |
m = leafmap.Map(style="positron") | |
with st.sidebar: | |
if st.toggle("Protected Areas", True): | |
style_choice = st.radio("Color by:", style_options) | |
alpha = st.slider("transparency", 0.0, 1.0, 0.5) | |
style = pad_style(style_options[style_choice], alpha) | |
m.add_pmtiles(ca_pmtiles, style=style, visible=True, opacity=alpha, tooltip=True) | |
select_column = { | |
"GAP Status Code": "reGAP", | |
"Management Agency": "cpad_MNG_AG_LEV", | |
"Easement": "Easement", | |
"Year": "Release_Year", | |
"Public Access": "ACCESS_TYP"} | |
column = select_column[style_choice] | |
select_colors = { | |
"Management Agency": manager["stops"], | |
"Easement": easement["stops"], | |
"Public Access": access["stops"], | |
"Year": year["stops"], | |
"GAP Status Code": gap["stops"]} | |
colors = (ibis | |
.memtable(select_colors[style_choice], columns = [column, "color"]) | |
.to_pandas() | |
) | |
main = st.container() | |
with main: | |
map_col, stats_col = st.columns([2,1]) | |
with map_col: | |
to_streamlit(m, height=700) | |
df = summary_table(column, colors) | |
total_percent = df.percent_protected.sum().round(1) | |
with stats_col: | |
with st.container(): | |
f"{total_percent}% CA Covered" | |
st.altair_chart(area_plot(df, column), use_container_width=True) | |
st.divider() | |
footer = st.container() | |