Spaces:
Running
Running
# -*- coding: utf-8 -*- | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
import leafmap.foliumap as leafmap | |
import rioxarray | |
import geopandas as gpd | |
import streamlit as st | |
import altair as alt | |
import ibis | |
from ibis import _ | |
import ibis.selectors as s | |
from streamlit_folium import st_folium | |
import json | |
def extract_geom(gdf, cog): | |
x = (rioxarray. | |
open_rasterio('/vsicurl/'+cog, masked=True). | |
rio.clip(gdf.geometry.values, gdf.crs, from_disk=True) | |
) | |
return x | |
def read_polygon(polygon): | |
geojson_str = json.dumps(polygon) | |
gdf = gpd.read_file(geojson_str, driver='GeoJSON') | |
gdf.set_crs('epsg:4326') | |
return gdf | |
def area_hectares(gdf): | |
area = gdf.to_crs("EPSG:9822").area / 10000. | |
return area | |
# + | |
st.set_page_config(layout="wide", page_title="Leafmap Explorer", page_icon="⚡") | |
st.title("Demo Carbon Calculator") | |
DESCRIPTION=''' | |
Pan and zoom to the desired location on the map. Then, use the map tools to draw a polygon (pentagon tool), bounding box (square tool) or other shape anywhere on the map. | |
(use esc key to exit drawing mode). Map will display the tons of carbon lost between 2002 - 2022 below. | |
Data comes from Vizzuality repo on [source.coop](https://beta.source.coop/repositories/vizzuality/lg-land-carbon-data/description/). | |
''' | |
code_ex = "" | |
deforest = "https://data.source.coop/vizzuality/lg-land-carbon-data/deforest_carbon_100m_cog.tif" | |
# measured in Mg / Hct (tons) | |
irrecoverable = "https://data.source.coop/cboettig/carbon/cogs/irrecoverable_c_total_2018.tif" | |
vulnerable = "https://data.source.coop/cboettig/carbon/cogs/vulnerable_c_total_2018.tif" | |
manageable = "https://data.source.coop/cboettig/carbon/cogs/manageable_c_total_2018.tif" | |
#rsr = "https://data.source.coop/cboettig/mobi/range-size-rarity-all/RSR_All.tif" | |
#richness = "https://data.source.coop/cboettig/mobi/species-richness-all/SpeciesRichness_All.tif" | |
# Use signed data layers | |
#rsr = "https://data.source.coop/cboettig/mobi/range-size-rarity-all/RSR_All.tif" | |
#richness = "https://data.source.coop/cboettig/mobi/species-richness-all/SpeciesRichness_All.tif" | |
m = leafmap.Map(center=[35, -100], zoom=3) | |
## Map controls sidebar | |
with st.sidebar: | |
st.markdown(DESCRIPTION) | |
cog_layers = { | |
"Carbon Lost, 2002-2022": deforest, | |
"Vulnerable Carbon (2018)": vulnerable, | |
"Manageable Carbon (2018)": manageable, | |
"Irrecoverable Carbon (2018)": irrecoverable | |
} | |
selection = st.radio("Data", cog_layers) | |
cog = cog_layers[selection] | |
m.add_cog_layer(cog, palette="reds", name=selection, | |
transparent_bg=True, opacity = 0.8, | |
zoom_to_layer=False) | |
"### python code for map layer:" | |
"adjust options or add additional layers using leafmap" | |
code = st.text_area( | |
label = "code:", | |
value = code_ex, | |
height = 400) | |
# run whatever python code is in the python box, just for fun | |
eval(compile(code, "<string>", "exec")) | |
st_data = m.to_streamlit(height=400, bidirectional=True) | |
units="Tonnes" | |
polygon = st_data["last_active_drawing"] | |
# Here we actually compute the total carbon in the requested polygon | |
if polygon is not None: | |
gdf = read_polygon(polygon) | |
x = extract_geom(gdf, cog).fillna(0) | |
count = x.count() | |
area = round(float(area_hectares(gdf))) | |
carbon_total = round(float(x.mean()) * area) # no, mean does not include zeros | |
col1, col2, col3 = st.columns(3) | |
col1.metric(label=f"{selection}", value=f"{carbon_total:,} {units}") | |
col2.metric(label=f"Area", value=f"{area:,} Hectares") | |
col3.metric(label=f"pixels", value=f"{count:,}") | |
# pixel sums instead of means | |
# value = round(float(x.sum())) | |
# if(selection in ["Vulnerable Carbon (2018)", | |
# "Manageable Carbon (2018)", | |
# "Irrecoverable Carbon (2018)"]): | |
# value = value * 9 # 300m pixels, each pixel is 9 hectres | |
st.divider() | |
"## Explore further" | |
with st.expander("code examples"): | |
st.write(''' | |
Try adding additional options to the map. Some suggested examples are shown below. | |
(Of course any self-respecting streamlit app would make these into toggle buttons, | |
but this is a demo and it's fun & flexible to be able to execute arbitrary code). | |
To explore further, simply modify the Streamlit app.py file from the Files menu up top! | |
''' | |
) | |
st.code(''' | |
# irrecoverable carbon (Conservation International): | |
carbon = "https://data.source.coop/cboettig/carbon/cogs/irrecoverable_c_total_2018.tif" | |
m.add_cog_layer(carbon, palette="reds", name="irrecoverable carbon", | |
transparent_bg=True, opacity = 0.8, zoom_to_layer=False) | |
# Human Impacts, Vizzuality | |
hi="https://data.source.coop/vizzuality/hfp-100/hfp_2021_100m_v1-2_cog.tif" | |
m.add_cog_layer(hi, palette="purples", name="human impact", | |
transparent_bg=True, opacity = 0.8, zoom_to_layer=False) | |
# Fire Polygons, USGS | |
usgs = "https://data.source.coop/cboettig/fire/usgs-mtbs.pmtiles" | |
combined_style = { | |
"version": 8, | |
"sources": { | |
"source1": { | |
"type": "vector", | |
"url": "pmtiles://" + usgs, | |
"attribution": "USGS"}}, | |
"layers": [{ | |
"id": "usgs", | |
"source": "source1", | |
"source-layer": "mtbs_perims_DD", | |
"type": "fill", | |
"paint": {"fill-color": "#FFA500", "fill-opacity": 0.2}}]} | |
m.add_pmtiles(usgs, name="Fire", style=combined_style, overlay=True, show=True, zoom_to_layer=False) | |
''') | |
st.divider() | |
''' | |
Note: this is just a proof-of-principle demonstration of these tools, and these calculations have not been validated. | |
## Credits | |
### Data sources | |
- Carbon-loss by Vizzuality, on https://beta.source.coop/repositories/vizzuality/lg-land-carbon-data. citation: https://doi.org/10.1101/2023.11.01.565036, License: CC-BY | |
- Irrecoverable Carbon from Conservation International, reprocessed to COG on https://beta.source.coop/cboettig/carbon, citation: https://doi.org/10.1038/s41893-021-00803-6, License: CC-BY-NC | |
- Fire polygons by USGS, reprocessed to PMTiles on https://beta.source.coop/cboettig/fire/, License: Public Domain. | |
### Software stack | |
- Streamlit (python) app hosted on free-tier HuggingFace spaces ([source code](https://huggingface.co/spaces/boettiger-lab/leafmap/blob/main/app.py)). | |
- Cloud-optimized geotifs hosted on [Source.Coop](https://source.coop) | |
- Mapping with Leafmap, calculations with rasterio | |
''' | |