ca-30x30 / app.py
cassiebuhler's picture
the maps work, still working on the stats
ba4e718
raw
history blame
6.54 kB
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()