cboettig commited on
Commit
60c8755
·
1 Parent(s): e85b9e8

:see_no_evil:

Browse files
Files changed (2) hide show
  1. app.py +27 -20
  2. utilities.py +5 -31
app.py CHANGED
@@ -7,6 +7,7 @@ from utilities import *
7
  import leafmap.maplibregl as leafmap
8
  import requests
9
  import geopandas as gpd
 
10
 
11
  st.set_page_config(page_title="Redlining & GBIF", layout="wide")
12
  st.title("Redlining & GBIF")
@@ -84,7 +85,6 @@ with st.form("my_form"):
84
  @st.cache_data
85
  def compute_hexes(_gdf, gdf_name, rank, taxa, zoom, distinct_taxa = ""):
86
 
87
- # FIXME check if dest exists in cache
88
  dest = unique_path(gdf_name, rank, taxa, zoom, distinct_taxa)
89
  bucket = "public-gbif"
90
  url = base_url + f"/{bucket}/" + dest
@@ -93,7 +93,10 @@ def compute_hexes(_gdf, gdf_name, rank, taxa, zoom, distinct_taxa = ""):
93
  if response.status_code != 404:
94
  return url
95
 
96
- sel = con.read_parquet("s3://public-gbif/app/redlined_cities_gbif.parquet")
 
 
 
97
 
98
  sel = (sel
99
  .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 = ""):
119
 
120
 
121
 
122
- import altair as alt
123
-
124
  @st.cache_data
125
  def bar_chart(gdf_name, rank, taxa, zoom, distinct_taxa = ""):
126
  sel = con.read_parquet("s3://public-gbif/app/redlined_cities_gbif.parquet")
127
- sel = sel.filter(_[rank] == taxa)
128
-
 
 
 
129
  if gdf_name != "All":
130
  sel = sel.filter(_.city == gdf_name)
131
 
@@ -136,7 +140,7 @@ def bar_chart(gdf_name, rank, taxa, zoom, distinct_taxa = ""):
136
  else:
137
  sel = sel.agg(n = _.count(), area = _.area.sum())
138
  sel = (sel
139
- .mutate(density = _.n /_.area)
140
  .group_by(_.grade)
141
  .agg(mean = _.density.mean(),sd = _.density.std())
142
  .order_by(_.mean.desc())
@@ -168,27 +172,30 @@ if nunique:
168
  mapcol, chartcol = st.columns([4,1])
169
 
170
  if submitted:
171
- gdf = get_polygon(gdf_name, area_source, con)
172
- url = compute_hexes(gdf, gdf_name, rank, taxa, zoom, distinct_taxa = distinct_taxa)
173
- layer = HexagonLayer(url, v_scale)
174
-
175
-
176
- m = leafmap.Map(style=terrain_styling(), center=[-120, 37.6], zoom=2, pitch=35, bearing=10)
177
- if gdf is not None:
178
- m.add_gdf(gdf[[gdf.geometry.name]], "fill", paint = {"fill-opacity": 0.2}) # adds area of interest & zooms in
179
- m.add_pmtiles(mappinginequality, style=redlines, visible=True, opacity = 0.9, fit_bounds=False)
180
- m.add_deck_layers([layer])
181
- m.add_layer_control()
182
-
183
  with mapcol:
 
 
 
 
 
 
 
 
 
 
 
 
184
  m.to_streamlit()
 
185
  with chartcol:
186
- st.markdown("Mean number of " + count + " by redline grade")
187
  bar_chart(gdf_name, rank, taxa, zoom, distinct_taxa = distinct_taxa)
 
188
 
189
 
 
190
  st.divider()
191
 
 
192
  '''
193
  ## Overview
194
 
 
7
  import leafmap.maplibregl as leafmap
8
  import requests
9
  import geopandas as gpd
10
+ import altair as alt
11
 
12
  st.set_page_config(page_title="Redlining & GBIF", layout="wide")
13
  st.title("Redlining & GBIF")
 
85
  @st.cache_data
86
  def compute_hexes(_gdf, gdf_name, rank, taxa, zoom, distinct_taxa = ""):
87
 
 
88
  dest = unique_path(gdf_name, rank, taxa, zoom, distinct_taxa)
89
  bucket = "public-gbif"
90
  url = base_url + f"/{bucket}/" + dest
 
93
  if response.status_code != 404:
94
  return url
95
 
96
+ sel = (con
97
+ .read_parquet("s3://public-gbif/app/redlined_cities_gbif.parquet")
98
+ .filter(_[rank] == taxa)
99
+ )
100
 
101
  sel = (sel
102
  .rename(hex = "h" + str(zoom)) # h3 == 41,150 hexes. h5 == 2,016,830 hexes
 
122
 
123
 
124
 
 
 
125
  @st.cache_data
126
  def bar_chart(gdf_name, rank, taxa, zoom, distinct_taxa = ""):
127
  sel = con.read_parquet("s3://public-gbif/app/redlined_cities_gbif.parquet")
128
+ sel = (sel
129
+ .filter(_[rank] == taxa)
130
+ .mutate(geom = _.geom.convert('EPSG:4326', 'ESRI:54009'))
131
+ .mutate(area = _.geom.area())
132
+ )
133
  if gdf_name != "All":
134
  sel = sel.filter(_.city == gdf_name)
135
 
 
140
  else:
141
  sel = sel.agg(n = _.count(), area = _.area.sum())
142
  sel = (sel
143
+ .mutate(density = _.n /_.area * 10000) # per hectre
144
  .group_by(_.grade)
145
  .agg(mean = _.density.mean(),sd = _.density.std())
146
  .order_by(_.mean.desc())
 
172
  mapcol, chartcol = st.columns([4,1])
173
 
174
  if submitted:
 
 
 
 
 
 
 
 
 
 
 
 
175
  with mapcol:
176
+ gdf = get_polygon(gdf_name, area_source, con)
177
+ url = compute_hexes(gdf, gdf_name, rank, taxa, zoom, distinct_taxa = distinct_taxa)
178
+ layer = HexagonLayer(url, v_scale)
179
+ digest = hashlib.md5(str(layer).encode()).hexdigest()
180
+ print(digest)
181
+
182
+ m = leafmap.Map(style=terrain_styling(), center=[-120, 37.6], zoom=2, pitch=35, bearing=10)
183
+ if gdf is not None:
184
+ m.add_gdf(gdf[[gdf.geometry.name]], "fill", paint = {"fill-opacity": 0.2}) # adds area of interest & zooms in
185
+ m.add_pmtiles(mappinginequality, style=redlines, visible=True, opacity = 0.9, fit_bounds=False)
186
+ m.add_deck_layers([layer])
187
+ m.add_layer_control()
188
  m.to_streamlit()
189
+
190
  with chartcol:
 
191
  bar_chart(gdf_name, rank, taxa, zoom, distinct_taxa = distinct_taxa)
192
+ st.markdown("Mean density of " + count + " by redline grade, count per hectre")
193
 
194
 
195
+
196
  st.divider()
197
 
198
+
199
  '''
200
  ## Overview
201
 
utilities.py CHANGED
@@ -24,7 +24,7 @@ def set_source_secrets(con):
24
  if secret is None:
25
  secret = st.secrets["SOURCE_SECRET"]
26
 
27
- ket = os.getenv("SOURCE_KEY")
28
  if key is None:
29
  key = st.secrets["SOURCE_KEY"]
30
 
@@ -110,32 +110,6 @@ def HexagonLayer(data, v_scale = 1):
110
  get_fill_color="[255 - value, 255, value]",
111
  )
112
 
113
- def DeckGlobe(layer):
114
- view_state = pdk.ViewState(latitude=51.47, longitude=0.45, zoom=0)
115
- view = pdk.View(type="_GlobeView", controller=True, width=1000, height=600)
116
- COUNTRIES = "https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_scale_rank.geojson"
117
-
118
- layers = [
119
- pdk.Layer(
120
- "GeoJsonLayer",
121
- id="base-map",
122
- data=COUNTRIES,
123
- stroked=False,
124
- filled=True,
125
- get_fill_color=[200, 200, 200],
126
- ),
127
- layer,
128
- ]
129
- deck = pdk.Deck(
130
- views=[view],
131
- initial_view_state=view_state,
132
- layers=layers,
133
- map_provider=None,
134
- # Note that this must be set for the globe to be opaque
135
- parameters={"cull": True},
136
- )
137
- return deck
138
-
139
 
140
  def terrain_styling():
141
  maptiler_key = os.getenv("MAPTILER_KEY")
@@ -192,7 +166,6 @@ def get_city(name = "Oakland", con = ibis.duckdb.connect()):
192
  return gdf
193
 
194
 
195
- @st.cache_data
196
  def get_polygon(name = "New Haven",
197
  source = "City",
198
  _con = ibis.duckdb.connect()):
@@ -211,9 +184,10 @@ import hashlib
211
  import pandas as pd
212
  def unique_path(gdf_name, rank, taxa, zoom, distinct_taxa):
213
  #gdf_hash = str(pd.util.hash_pandas_object(gdf).sum())
214
- text = gdf_name + rank + taxa + str(zoom) + distinct_taxa
215
- hash_object = hashlib.sha1(text.encode())
216
- sig = hash_object.hexdigest()
 
217
  dest = "cache/gbif_" + sig + ".json"
218
  return dest
219
 
 
24
  if secret is None:
25
  secret = st.secrets["SOURCE_SECRET"]
26
 
27
+ key = os.getenv("SOURCE_KEY")
28
  if key is None:
29
  key = st.secrets["SOURCE_KEY"]
30
 
 
110
  get_fill_color="[255 - value, 255, value]",
111
  )
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
  def terrain_styling():
115
  maptiler_key = os.getenv("MAPTILER_KEY")
 
166
  return gdf
167
 
168
 
 
169
  def get_polygon(name = "New Haven",
170
  source = "City",
171
  _con = ibis.duckdb.connect()):
 
184
  import pandas as pd
185
  def unique_path(gdf_name, rank, taxa, zoom, distinct_taxa):
186
  #gdf_hash = str(pd.util.hash_pandas_object(gdf).sum())
187
+ text = [gdf_name, rank, taxa, str(zoom), distinct_taxa]
188
+ sig = "-".join(text)
189
+ print(sig)
190
+ sig = hashlib.sha1(sig.encode()).hexdigest()
191
  dest = "cache/gbif_" + sig + ".json"
192
  return dest
193