Spaces:
Sleeping
Sleeping
| # -*- 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 | |
| ''' | |