diff --git a/app.py b/app.py index c41f644..23fc4a4 100644 --- a/app.py +++ b/app.py @@ -7,6 +7,7 @@ import leafmap.maplibregl as leafmap import requests import geopandas as gpd +import altair as alt st.set_page_config(page_title="Redlining & GBIF", layout="wide") st.title("Redlining & GBIF") @@ -84,7 +85,6 @@ @st.cache_data def compute_hexes(_gdf, gdf_name, rank, taxa, zoom, distinct_taxa = ""): - # FIXME check if dest exists in cache dest = unique_path(gdf_name, rank, taxa, zoom, distinct_taxa) bucket = "public-gbif" url = base_url + f"/{bucket}/" + dest @@ -93,7 +93,10 @@ def compute_hexes(_gdf, gdf_name, rank, taxa, zoom, distinct_taxa = ""): if response.status_code != 404: return url - sel = con.read_parquet("s3://public-gbif/app/redlined_cities_gbif.parquet") + sel = (con + .read_parquet("s3://public-gbif/app/redlined_cities_gbif.parquet") + .filter(_[rank] == taxa) + ) sel = (sel .rename(hex = "h" + str(zoom)) # h3 == 41,150 hexes. h5 == 2,016,830 hexes @@ -119,13 +122,14 @@ def compute_hexes(_gdf, gdf_name, rank, taxa, zoom, distinct_taxa = ""): -import altair as alt - @st.cache_data def bar_chart(gdf_name, rank, taxa, zoom, distinct_taxa = ""): sel = con.read_parquet("s3://public-gbif/app/redlined_cities_gbif.parquet") - sel = sel.filter(_[rank] == taxa) - + sel = (sel + .filter(_[rank] == taxa) + .mutate(geom = _.geom.convert('EPSG:4326', 'ESRI:54009')) + .mutate(area = _.geom.area()) + ) if gdf_name != "All": sel = sel.filter(_.city == gdf_name) @@ -136,7 +140,7 @@ def bar_chart(gdf_name, rank, taxa, zoom, distinct_taxa = ""): else: sel = sel.agg(n = _.count(), area = _.area.sum()) sel = (sel - .mutate(density = _.n /_.area) + .mutate(density = _.n /_.area * 10000) # per hectre .group_by(_.grade) .agg(mean = _.density.mean(),sd = _.density.std()) .order_by(_.mean.desc()) @@ -168,27 +172,30 @@ def bar_chart(gdf_name, rank, taxa, zoom, distinct_taxa = ""): mapcol, chartcol = st.columns([4,1]) if submitted: - gdf = get_polygon(gdf_name, area_source, con) - url = compute_hexes(gdf, gdf_name, rank, taxa, zoom, distinct_taxa = distinct_taxa) - layer = HexagonLayer(url, v_scale) - - - m = leafmap.Map(style=terrain_styling(), center=[-120, 37.6], zoom=2, pitch=35, bearing=10) - if gdf is not None: - m.add_gdf(gdf[[gdf.geometry.name]], "fill", paint = {"fill-opacity": 0.2}) # adds area of interest & zooms in - m.add_pmtiles(mappinginequality, style=redlines, visible=True, opacity = 0.9, fit_bounds=False) - m.add_deck_layers([layer]) - m.add_layer_control() - with mapcol: + gdf = get_polygon(gdf_name, area_source, con) + url = compute_hexes(gdf, gdf_name, rank, taxa, zoom, distinct_taxa = distinct_taxa) + layer = HexagonLayer(url, v_scale) + digest = hashlib.md5(str(layer).encode()).hexdigest() + print(digest) + + m = leafmap.Map(style=terrain_styling(), center=[-120, 37.6], zoom=2, pitch=35, bearing=10) + if gdf is not None: + m.add_gdf(gdf[[gdf.geometry.name]], "fill", paint = {"fill-opacity": 0.2}) # adds area of interest & zooms in + m.add_pmtiles(mappinginequality, style=redlines, visible=True, opacity = 0.9, fit_bounds=False) + m.add_deck_layers([layer]) + m.add_layer_control() m.to_streamlit() + with chartcol: - st.markdown("Mean number of " + count + " by redline grade") bar_chart(gdf_name, rank, taxa, zoom, distinct_taxa = distinct_taxa) + st.markdown("Mean density of " + count + " by redline grade, count per hectre") + st.divider() + ''' ## Overview diff --git a/utilities.py b/utilities.py index 2bb1866..95b355e 100644 --- a/utilities.py +++ b/utilities.py @@ -24,7 +24,7 @@ def set_source_secrets(con): if secret is None: secret = st.secrets["SOURCE_SECRET"] - ket = os.getenv("SOURCE_KEY") + key = os.getenv("SOURCE_KEY") if key is None: key = st.secrets["SOURCE_KEY"] @@ -110,32 +110,6 @@ def HexagonLayer(data, v_scale = 1): get_fill_color="[255 - value, 255, value]", ) -def DeckGlobe(layer): - view_state = pdk.ViewState(latitude=51.47, longitude=0.45, zoom=0) - view = pdk.View(type="_GlobeView", controller=True, width=1000, height=600) - COUNTRIES = "https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_scale_rank.geojson" - - layers = [ - pdk.Layer( - "GeoJsonLayer", - id="base-map", - data=COUNTRIES, - stroked=False, - filled=True, - get_fill_color=[200, 200, 200], - ), - layer, - ] - deck = pdk.Deck( - views=[view], - initial_view_state=view_state, - layers=layers, - map_provider=None, - # Note that this must be set for the globe to be opaque - parameters={"cull": True}, - ) - return deck - def terrain_styling(): maptiler_key = os.getenv("MAPTILER_KEY") @@ -192,7 +166,6 @@ def get_city(name = "Oakland", con = ibis.duckdb.connect()): return gdf -@st.cache_data def get_polygon(name = "New Haven", source = "City", _con = ibis.duckdb.connect()): @@ -211,9 +184,10 @@ def get_polygon(name = "New Haven", import pandas as pd def unique_path(gdf_name, rank, taxa, zoom, distinct_taxa): #gdf_hash = str(pd.util.hash_pandas_object(gdf).sum()) - text = gdf_name + rank + taxa + str(zoom) + distinct_taxa - hash_object = hashlib.sha1(text.encode()) - sig = hash_object.hexdigest() + text = [gdf_name, rank, taxa, str(zoom), distinct_taxa] + sig = "-".join(text) + print(sig) + sig = hashlib.sha1(sig.encode()).hexdigest() dest = "cache/gbif_" + sig + ".json" return dest