cassiebuhler commited on
Commit
45a8c07
1 Parent(s): 36961ed

adding color shading options

Browse files
Files changed (1) hide show
  1. app.py +172 -180
app.py CHANGED
@@ -2,6 +2,10 @@ import ibis
2
  from ibis import _
3
  import streamlit as st
4
 
 
 
 
 
5
  st.set_page_config(layout="wide",
6
  page_title="TPL LandVote",
7
  page_icon=":globe:")
@@ -13,6 +17,14 @@ An experimental platform for visualizing data on ballot measures for conservatio
13
 
14
  '''
15
 
 
 
 
 
 
 
 
 
16
 
17
  ## Chatbot
18
  import os
@@ -34,6 +46,7 @@ agent = Agent(
34
 
35
  with st.sidebar:
36
 
 
37
  '''
38
  ## Data Assistant (experimental)
39
 
@@ -57,22 +70,14 @@ with st.sidebar:
57
 
58
 
59
 
 
60
  # year = st.slider("Select a year", min_value=1988, max_value=2024, value=2022, step=2)
61
  year = st.slider("Select a year", min_value=1988, max_value=2024, value=2022, step=1)
62
 
63
- import leafmap.maplibregl as leafmap
64
- m = leafmap.Map(style="positron", center=(-100, 40), zoom=3)
65
 
66
- # url = "https://huggingface.co/datasets/boettiger-lab/landvote/resolve/main/landvote_polygons.pmtiles"
67
  url = "https://huggingface.co/datasets/boettiger-lab/landvote/resolve/main/votes.pmtiles"
68
  parties = "https://huggingface.co/datasets/boettiger-lab/landvote/resolve/main/votes.parquet"
69
 
70
- dark_orange = 'rgba(171, 86, 1, 1)' # dark orange - min value
71
- light_orange = 'rgba(243, 211, 177, 1)' # light orange
72
- grey = 'rgba(211, 211, 211, 1)' # grey
73
- light_green = 'rgba(195, 219, 195, 1)' # light green
74
- dark_green = 'rgba(65, 125, 65, 1)' # dark green - max value
75
-
76
  con = ibis.duckdb.connect(extensions=["spatial"])
77
 
78
  party = (con
@@ -82,6 +87,7 @@ party = (con
82
 
83
  def get_passes(party):
84
  df = (party
 
85
  .group_by("year", "party")
86
  .aggregate(total=_.count(),
87
  passes = (_.Status.isin(["Pass", "Pass*"]).sum())
@@ -93,62 +99,13 @@ def get_passes(party):
93
  .else_(ibis.literal("#E81B23"))
94
  .end()
95
  )
96
- # # .select("year","party","percent_passed","color")
97
- )
98
-
99
- df = df.to_pandas()
100
- return df
101
-
102
- def get_summary(party, year):
103
- total_measures = party.filter(_.year == year).count().execute()
104
-
105
- df = (party
106
- .filter(_.year == year)
107
- .mutate(
108
- # Convert 'amount' from string with '$' and ',' to numeric
109
- # amount_numeric=_.amount.replace('$', '').replace(',', '').cast('float64')
110
- )
111
- .group_by("party")
112
- .aggregate(
113
- total = _.count(),
114
- percent_passed= (_.Status.isin(["Pass", "Pass*"]).sum() / _.count()).round(2),
115
- )
116
- .mutate(color=ibis.case()
117
- .when(_.party == "DEMOCRAT", ibis.literal("#92c7f5"))
118
- .else_(ibis.literal("#E81B23"))
119
- .end())
120
  )
121
 
122
  df = df.to_pandas()
123
  return df
124
-
125
- # def get_cumulative(party):
126
-
127
- # df = (party
128
- # .select("year","amount","Status")
129
- # # .mutate(
130
- # # # Convert 'amount' from string with '$' and ',' to numeric
131
- # # # amount_numeric=_.amount.replace('$', '').replace(',', '').cast('float64')
132
- # # )
133
- # # .group_by("party")
134
- # # .aggregate(
135
- # # total = _.count(),
136
- # # percent_passed= (_.Status.isin(["Pass", "Pass*"]).sum() / _.count()).round(2),
137
- # # )
138
- # # .mutate(color=ibis.case()
139
- # # .when(_.party == "DEMOCRAT", ibis.literal("#92c7f5"))
140
- # # .else_(ibis.literal("#E81B23"))
141
- # # .end())
142
- # )
143
-
144
- # df = df.to_pandas()
145
- # return df
146
-
147
 
148
- import altair as alt
149
- import streamlit as st
150
 
151
- def plot(df_passes):
152
  chart = alt.Chart(df_passes).mark_line(strokeWidth=3).encode(
153
  x=alt.X('year:N', title='Year'),
154
  y=alt.Y('percent_passed:Q', title='Percent Passed'),
@@ -164,23 +121,20 @@ def plot(df_passes):
164
  st.altair_chart(chart, use_container_width=True)
165
 
166
 
167
-
168
-
169
  def funding_chart(party):
170
-
171
  df = (party
172
  .mutate(amount=_.amount.replace('$', '').replace(',', '').cast('float64'))
173
  .filter(_.Status.isin(["Pass", "Pass*"]))
174
  .group_by("year")
175
  .aggregate(total_funding=_.amount.sum())
176
  .order_by("year")
177
- .mutate(cumulative_funding=_.total_funding.cumsum())
178
  .execute()
179
  )
180
 
181
  chart = alt.Chart(df).mark_line(strokeWidth=3).encode(
182
  x=alt.X('year:N', title='Year'),
183
- y=alt.Y('cumulative_funding:Q', title='Cumulative Funding'),
184
  ).properties(
185
  title='Cumulative Funding'
186
  )
@@ -188,21 +142,8 @@ def funding_chart(party):
188
  st.altair_chart(chart, use_container_width=True)
189
 
190
 
191
-
192
- style_municipals = {
193
- "layers": [
194
- {
195
- "id": "cities",
196
- "source": "municipal",
197
- "source-layer": "municipal",
198
- "type": "fill-extrusion",
199
- "filter": [
200
- "==",
201
- ["get", "year"],
202
- year,
203
- ],
204
- "paint": {
205
- "fill-extrusion-color": [
206
  "case",
207
  # if passed, color green
208
  ["==", ["get", "Status"], "Pass"],
@@ -225,26 +166,11 @@ style_municipals = {
225
  67, grey # 67 is the max of data.
226
  ],
227
  grey # if no match
228
- ],
229
- "fill-extrusion-height": ["*", ["get", "log_amount"], 5000],
230
  }
231
- },
232
- ],
233
- }
234
-
235
- style_counties = {
236
- "layers": [
237
- {
238
- "id": "counties",
239
- "source": "county",
240
- "source-layer": "county",
241
- "type": "fill-extrusion",
242
- "filter": [
243
- "==",
244
- ["get", "year"],
245
- year,
246
- ],
247
- "paint": {
248
  "fill-extrusion-color": [
249
  "case",
250
  # if passed, color green
@@ -271,100 +197,166 @@ style_counties = {
271
  ],
272
  "fill-extrusion-height": ["*", ["get", "log_amount"], 5000],
273
  }
274
- },
275
- ],
276
- }
277
-
278
- style_states = {
279
- "layers": [
280
- {
281
- "id": "states",
282
- "source": "state",
283
- "source-layer": "state",
284
- "type": "fill",
285
- "filter": [
286
- "==",
287
- ["get", "year"],
288
- year,
289
- ],
290
- "paint": {
291
- "fill-color": [
292
- "case",
293
- # if passed, color green
294
- ["==", ["get", "Status"], "Pass"],
295
- [
296
- "interpolate", ["linear"], [
297
- "to-number", ["slice", ["get", "yes"], 0, -1] # convert 'yes' string to number
298
- ],
299
- 50, grey,
300
- 55, light_green, # higher yes % -> darker green
301
- 100, dark_green # 100 is the max of data
302
- ],
303
- # if failed, color orange
304
- ["==", ["get", "Status"], "Fail"],
305
- [
306
- "interpolate", ["linear"], [
307
- "to-number", ["slice", ["get", "yes"], 0, -1] # convert 'yes' string to number
308
- ],
309
- 0, dark_orange, # higher yes % -> lighter orange
310
- 50, light_orange,
311
- 67, grey # 67 is the max of data.
312
- ],
313
- grey # if no match
314
- ]
315
- }
316
- },
317
- ],
318
- }
319
 
320
 
321
- #states are 2D and transparent, thus added separately.
322
- m.add_pmtiles(
323
- url,
324
- style=style_states,
325
- visible=True,
326
- opacity=0.6,
327
- tooltip=True,
328
- fit_bounds=False
329
- )
330
-
331
- #states are 2D and transparent, thus added separately.
332
- m.add_pmtiles(
333
- url,
334
- style=style_counties,
335
- visible=True,
336
- opacity=1.0,
337
- tooltip=True,
338
- fit_bounds=False
339
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
 
 
341
 
342
- m.add_pmtiles(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  url,
344
- style=style_municipals,
345
  visible=True,
346
- opacity=1.0,
347
  tooltip=True,
348
  fit_bounds=False
349
- )
350
-
351
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  m.add_layer_control()
 
353
  m.to_streamlit()
354
 
355
  df_passes = get_passes(party)
356
- # st.dataframe(df_passes)
357
- plot(df_passes)
358
-
359
-
360
- df = get_summary(party, year)
361
-
362
- # st.line_chart(df_passes, x= "year",y = "percent_passed",color="color")
363
-
364
- # st.bar_chart(df, x= "party",y = "percent_passed",color="color")
365
- # Assuming df is your dataframe with 'year', 'amount', and 'Status' columns
366
- # df_fund = get_cumulative(party)
367
- funding_chart(party)
368
 
369
 
370
  # st.divider()
 
2
  from ibis import _
3
  import streamlit as st
4
 
5
+ import altair as alt
6
+
7
+
8
+
9
  st.set_page_config(layout="wide",
10
  page_title="TPL LandVote",
11
  page_icon=":globe:")
 
17
 
18
  '''
19
 
20
+ dark_orange = 'rgba(171, 86, 1, 1)' # dark orange - min value
21
+ light_orange = 'rgba(243, 211, 177, 1)' # light orange
22
+ grey = 'rgba(211, 211, 211, 1)' # grey
23
+ light_green = 'rgba(195, 219, 195, 1)' # light green
24
+ dark_green = 'rgba(65, 125, 65, 1)' # dark green - max value
25
+
26
+ dem_blue = "#1b46c2"
27
+ rep_red = "#E81B23"
28
 
29
  ## Chatbot
30
  import os
 
46
 
47
  with st.sidebar:
48
 
49
+
50
  '''
51
  ## Data Assistant (experimental)
52
 
 
70
 
71
 
72
 
73
+
74
  # year = st.slider("Select a year", min_value=1988, max_value=2024, value=2022, step=2)
75
  year = st.slider("Select a year", min_value=1988, max_value=2024, value=2022, step=1)
76
 
 
 
77
 
 
78
  url = "https://huggingface.co/datasets/boettiger-lab/landvote/resolve/main/votes.pmtiles"
79
  parties = "https://huggingface.co/datasets/boettiger-lab/landvote/resolve/main/votes.parquet"
80
 
 
 
 
 
 
 
81
  con = ibis.duckdb.connect(extensions=["spatial"])
82
 
83
  party = (con
 
87
 
88
  def get_passes(party):
89
  df = (party
90
+ .filter(_.year >= 2000)
91
  .group_by("year", "party")
92
  .aggregate(total=_.count(),
93
  passes = (_.Status.isin(["Pass", "Pass*"]).sum())
 
99
  .else_(ibis.literal("#E81B23"))
100
  .end()
101
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  )
103
 
104
  df = df.to_pandas()
105
  return df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
 
 
107
 
108
+ def percent_chart(df_passes):
109
  chart = alt.Chart(df_passes).mark_line(strokeWidth=3).encode(
110
  x=alt.X('year:N', title='Year'),
111
  y=alt.Y('percent_passed:Q', title='Percent Passed'),
 
121
  st.altair_chart(chart, use_container_width=True)
122
 
123
 
 
 
124
  def funding_chart(party):
 
125
  df = (party
126
  .mutate(amount=_.amount.replace('$', '').replace(',', '').cast('float64'))
127
  .filter(_.Status.isin(["Pass", "Pass*"]))
128
  .group_by("year")
129
  .aggregate(total_funding=_.amount.sum())
130
  .order_by("year")
131
+ .mutate(cumulative_funding=_.total_funding.cumsum()/1e9)
132
  .execute()
133
  )
134
 
135
  chart = alt.Chart(df).mark_line(strokeWidth=3).encode(
136
  x=alt.X('year:N', title='Year'),
137
+ y=alt.Y('cumulative_funding:Q', title='Billions of Dollars'),
138
  ).properties(
139
  title='Cumulative Funding'
140
  )
 
142
  st.altair_chart(chart, use_container_width=True)
143
 
144
 
145
+ paint_fill = {
146
+ "fill-color": [
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  "case",
148
  # if passed, color green
149
  ["==", ["get", "Status"], "Pass"],
 
166
  67, grey # 67 is the max of data.
167
  ],
168
  grey # if no match
169
+ ]
 
170
  }
171
+
172
+
173
+ paint_extrusion = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  "fill-extrusion-color": [
175
  "case",
176
  # if passed, color green
 
197
  ],
198
  "fill-extrusion-height": ["*", ["get", "log_amount"], 5000],
199
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
 
201
 
202
+ def get_style_status(jurisdiction):
203
+ if jurisdiction == "State":
204
+ name = "state"
205
+ label = "states"
206
+ paint_type = paint_fill
207
+ layer_type = "fill"
208
+
209
+ elif jurisdiction == "County":
210
+ name = "county"
211
+ label = "counties"
212
+ paint_type = paint_extrusion
213
+ layer_type = "fill-extrusion"
214
+
215
+ else:
216
+ name = "municipal"
217
+ label = "cities"
218
+ paint_type = paint_extrusion
219
+ layer_type = "fill-extrusion"
220
+
221
+ print(paint_type)
222
+ style = {
223
+ "layers": [
224
+ {
225
+ "id": label,
226
+ "source": name,
227
+ "source-layer": name,
228
+ "type": layer_type,
229
+ "filter": [
230
+ "==",
231
+ ["get", "year"],
232
+ year,
233
+ ],
234
+ "paint": paint_type
235
+ },
236
+ ],
237
+ }
238
+ return style
239
+
240
+
241
+ def get_style_party(jurisdiction):
242
+ if jurisdiction == "State":
243
+ name = "state"
244
+ label = "states"
245
+ elif jurisdiction == "County":
246
+ name = "county"
247
+ label = "counties"
248
+
249
+ else:
250
+ name = "municipal"
251
+ label = "cities"
252
+
253
+
254
+ style_party = {
255
+ "layers": [
256
+ {
257
+ "id": label,
258
+ "source": name,
259
+ "source-layer": name,
260
+ "type": "fill",
261
+ "filter": [
262
+ "==",
263
+ ["get", "year"],
264
+ year,
265
+ ],
266
+ "paint": {
267
+ "fill-color":
268
+ {
269
+ 'property': 'party',
270
+ 'type': 'categorical',
271
+ 'stops': [
272
+ ["DEMOCRAT", dem_blue],
273
+ ["REPUBLICAN", rep_red],
274
+ ]
275
+ }
276
+ }
277
+ },
278
+ ],
279
+ }
280
+ return style_party
281
+
282
+
283
+
284
+ style_options= ["Measure Status", "Political Party"]
285
+
286
+ color_choice = st.radio("Color by:", style_options)
287
+
288
+ import leafmap.maplibregl as leafmap
289
+ m = leafmap.Map(style="positron", center=(-100, 40), zoom=3)
290
 
291
+ if color_choice == "Measure Status":
292
 
293
+ #states are 2D and transparent, thus added separately.
294
+ m.add_pmtiles(
295
+ url,
296
+ style=get_style_status("States"),
297
+ visible=True,
298
+ opacity=0.6,
299
+ tooltip=True,
300
+ fit_bounds=False
301
+ )
302
+
303
+ #states are 2D and transparent, thus added separately.
304
+ m.add_pmtiles(
305
+ url,
306
+ style=get_style_status("County"),
307
+ visible=True,
308
+ opacity=1.0,
309
+ tooltip=True,
310
+ fit_bounds=False
311
+ )
312
+
313
+
314
+ m.add_pmtiles(
315
+ url,
316
+ style=get_style_status("Municipal"),
317
+ visible=True,
318
+ opacity=1.0,
319
+ tooltip=True,
320
+ fit_bounds=False
321
+ )
322
+
323
+ else:
324
+ m.add_pmtiles(
325
  url,
326
+ style=get_style_party("States"),
327
  visible=True,
328
+ opacity=0.6,
329
  tooltip=True,
330
  fit_bounds=False
331
+ )
332
+
333
+ m.add_pmtiles(
334
+ url,
335
+ style=get_style_party("County"),
336
+ visible=True,
337
+ opacity=1.0,
338
+ tooltip=True,
339
+ fit_bounds=False
340
+ )
341
+
342
+
343
+ m.add_pmtiles(
344
+ url,
345
+ style=get_style_party("Municipal"),
346
+ visible=True,
347
+ opacity=1.0,
348
+ tooltip=True,
349
+ fit_bounds=False
350
+ )
351
+
352
+
353
  m.add_layer_control()
354
+
355
  m.to_streamlit()
356
 
357
  df_passes = get_passes(party)
358
+ percent_chart(df_passes)
359
+ funding_chart(party.filter(_.year >= 2000))
 
 
 
 
 
 
 
 
 
 
360
 
361
 
362
  # st.divider()