11import streamlit as st
22import streamlit .components .v1 as components
33import base64
4- import leafmap . maplibregl as leafmap
4+ import importlib
55import altair as alt
66import ibis
77from ibis import _
124124
125125st .divider ()
126126
127-
128- m = leafmap . Map ( style = "positron " )
129- #############
130-
127+ # initialize map
128+ leafmap = importlib . import_module ( "leafmap.maplibregl " )
129+ m = leafmap . Map ( center = ( - 120 , 36 ), style = "positron" , zoom = 5 ,
130+ controls = controls , attribution_control = False , use_message_queue = True )
131131
132+ #############
132133
133134chatbot_container = st .container ()
134135with chatbot_container :
@@ -193,7 +194,7 @@ class SQLResponse(BaseModel):
193194 'svi' ,
194195]}
195196
196- def run_sql (query ,color_choice ):
197+ def run_sql (query , color_choice ):
197198 """
198199 Filter data based on an LLM-generated SQL query and return matching IDs.
199200
@@ -203,43 +204,39 @@ def run_sql(query,color_choice):
203204 """
204205 output = few_shot_structured_llm .invoke (query )
205206 sql_query = output .sql_query
206- explanation = output .explanation
207+ explanation = output .explanation
207208 if not sql_query : # if the chatbot can't generate a SQL query.
208209 st .success (explanation )
209210 return pd .DataFrame ({'id' : []}), [], []
210211
211212 result = ca .sql (sql_query ).execute ()
212- if result .empty :
213+ if result .empty :
213214 explanation = "This query did not return any results. Please try again with a different query."
214215 st .warning (explanation , icon = "⚠️" )
215216 st .caption ("SQL Query:" )
216- st .code (sql_query ,language = "sql" )
217+ st .code (sql_query , language = "sql" )
217218 if 'geom' in result .columns :
218- return result .drop ('geom' ,axis = 1 ), sql_query , explanation
219+ return result .drop ('geom' , axis = 1 ), sql_query , explanation
219220 else :
220221 return result , sql_query , explanation
221222
222223 elif ("id" and "geom" in result .columns ):
223224 style = get_pmtiles_style_llm (style_options [color_choice ], result ["id" ].tolist ())
224- legend , position , bg_color , fontsize = get_legend (style_options ,color_choice )
225-
226- m .add_legend (legend_dict = legend , position = position , bg_color = bg_color , fontsize = fontsize )
227- m .add_pmtiles (ca_pmtiles , style = style , opacity = alpha , tooltip = True , fit_bounds = True )
225+ m .add_pmtiles (ca_pmtiles , style = style , name = "30x30 Conserved Areas (Terrestrial)" ,
226+ attribution = "CA Nature (2024)" , tooltip = True )
228227 m .fit_bounds (result .total_bounds .tolist ())
229- result = result .drop ('geom' ,axis = 1 ) #printing to streamlit so I need to drop geom
228+ result = result .drop ('geom' , axis = 1 ) #printing to streamlit so I need to drop geom
230229 else :
231230 st .write (result ) # if we aren't mapping, just print out the data
232231
233232 with st .popover ("Explanation" ):
234233 st .write (explanation )
235234 st .caption ("SQL Query:" )
236- st .code (sql_query ,language = "sql" )
235+ st .code (sql_query , language = "sql" )
237236
238237 return result , sql_query , explanation
239238
240239
241-
242-
243240#############
244241
245242filters = {}
@@ -252,7 +249,6 @@ def run_sql(query,color_choice):
252249 - 💬 For a more tailored experience, query our dataset of protected areas and their precomputed mean values for each of the displayed layers, using the experimental chatbot. The language model tries to answer natural language questions by drawing only from curated datasets (listed below).
253250 '''
254251
255-
256252 st .divider ()
257253 color_choice = st .radio ("Group by:" , style_options , key = "color" , help = "Select a category to change map colors and chart groupings." )
258254 colorby_vals = get_color_vals (style_options , color_choice ) #get options for selected color_by column
@@ -267,9 +263,9 @@ def run_sql(query,color_choice):
267263 prompt = st .chat_input (example_query , key = "chain" , max_chars = 300 )
268264
269265with chatbot_container :
270- _ ,log_query_col , _ = st .columns ([.001 , 5 ,1 ], vertical_alignment = "top" )
271- with log_query_col :
272- log_queries = st .checkbox ("Save query" , value = True , help = "Saving your queries helps improve this tool and guide conservation efforts. Your data is stored in a private location. For more details, see 'Why save your queries?' at the bottom of this page." )
266+ _ ,log_query_col , _ = st .columns ([.001 , 5 ,1 ], vertical_alignment = "top" )
267+ with log_query_col :
268+ log_queries = st .checkbox ("Save query" , value = True , help = "Saving your queries helps improve this tool and guide conservation efforts. Your data is stored in a private location. For more details, see 'Why save your queries?' at the bottom of this page." )
273269
274270
275271with st .container ():
@@ -279,7 +275,7 @@ def run_sql(query,color_choice):
279275 with st .chat_message ("assistant" ):
280276 with st .spinner ("Invoking query..." ):
281277
282- out , sql_query , llm_explanation = run_sql (prompt ,color_choice )
278+ out , sql_query , llm_explanation = run_sql (prompt , color_choice )
283279 minio_logger (log_queries , prompt , sql_query , llm_explanation , llm_choice , 'query_log_prototype.csv' , "shared-ca30x30-app" )
284280
285281 if ("id" in out .columns ) and (not out .empty ):
@@ -308,52 +304,25 @@ def run_sql(query,color_choice):
308304 a_bio = st .slider ("transparency" , 0.0 , 1.0 , 0.1 , key = "biodiversity" )
309305 show_richness = st .toggle ("Species Richness" , key = "richness" , value = chatbot_toggles ['richness' ])
310306 show_rsr = st .toggle ("Range-Size Rarity" , key = "rsr" , value = chatbot_toggles ['rsr' ])
311-
312- if show_richness :
313- m .add_tile_layer (url_sr , name = "MOBI Species Richness" ,opacity = a_bio )
314- if show_rsr :
315- m .add_tile_layer (url_rsr , name = "MOBI Range-Size Rarity" , opacity = a_bio )
316307
317308 #Carbon Section
318309 with st .expander ("⛅ Carbon & Climate" ):
319310 a_climate = st .slider ("transparency" , 0.0 , 1.0 , 0.15 , key = "climate" )
320311 show_irrecoverable_carbon = st .toggle ("Irrecoverable Carbon" , key = "irrecoverable_carbon" , value = chatbot_toggles ['irrecoverable_carbon' ])
321312 show_manageable_carbon = st .toggle ("Manageable Carbon" , key = "manageable_carbon" , value = chatbot_toggles ['manageable_carbon' ])
322-
323- if show_irrecoverable_carbon :
324- m .add_cog_layer (url_irr_carbon , palette = "reds" , name = "Irrecoverable Carbon" , opacity = a_climate , fit_bounds = False )
325-
326- if show_manageable_carbon :
327- m .add_cog_layer (url_man_carbon , palette = "purples" , name = "Manageable Carbon" , opacity = a_climate , fit_bounds = False )
328-
329313
330314 # People Section
331315 with st .expander ("👤 People" ):
332316 a_people = st .slider ("transparency" , 0.0 , 1.0 , 0.1 , key = "SVI" )
333317 show_justice40 = st .toggle ("Disadvantaged Communities (Justice40)" , key = "disadvantaged_communities" , value = chatbot_toggles ['disadvantaged_communities' ])
334318 show_sv = st .toggle ("Social Vulnerability Index (SVI)" , key = "svi" , value = chatbot_toggles ['svi' ])
335319
336- if show_justice40 :
337- m .add_pmtiles (url_justice40 , style = justice40_style , name = "Justice40" , opacity = a_people , tooltip = False , fit_bounds = False )
338-
339- if show_sv :
340- m .add_pmtiles (url_svi , style = svi_style , opacity = a_people , tooltip = False , fit_bounds = False )
341-
342320 # Fire Section
343321 with st .expander ("🔥 Fire" ):
344322 a_fire = st .slider ("transparency" , 0.0 , 1.0 , 0.15 , key = "calfire" )
345323 show_fire = st .toggle ("Fires (2013-2023)" , key = "fire" , value = chatbot_toggles ['fire' ])
346-
347324 show_rxburn = st .toggle ("Prescribed Burns (2013-2023)" , key = "rxburn" , value = chatbot_toggles ['rxburn' ])
348325
349-
350- if show_fire :
351- m .add_pmtiles (url_calfire , style = fire_style , name = "CALFIRE Fire Polygons (2013-2023)" , opacity = a_fire , tooltip = False , fit_bounds = False )
352-
353- if show_rxburn :
354- m .add_pmtiles (url_rxburn , style = rx_style , name = "CAL FIRE Prescribed Burns (2013-2023)" , opacity = a_fire , tooltip = False , fit_bounds = False )
355-
356-
357326 st .divider ()
358327 st .markdown ('<p class = "medium-font-sidebar"> Filters:</p>' , help = "Apply filters to adjust what data is shown on the map." , unsafe_allow_html = True )
359328
@@ -377,26 +346,10 @@ def run_sql(query,color_choice):
377346
378347 # adding github logo
379348 st .markdown (f"<div class='spacer'>{ github_html } </div>" , unsafe_allow_html = True )
380-
381- # st.markdown("""
382- # <p class='medium-font-sidebar'>
383- # :left_speech_bubble: <a href='https://github.com/boettiger-lab/ca-30x30/issues' target='_blank'>Report an issue</a>
384- # </p>
385- # """, unsafe_allow_html=True)
386-
387349 st .markdown (":left_speech_bubble: [Get in touch or report an issue](https://github.com/boettiger-lab/ca-30x30/issues)" )
388350
389351
390-
391-
392-
393- # Display CA 30x30 Data
394- if 'out' not in locals ():
395- style = get_pmtiles_style (style_options [color_choice ], alpha , filter_cols , filter_vals )
396- legend , position , bg_color , fontsize = get_legend (style_options , color_choice )
397- m .add_legend (legend_dict = legend , position = position , bg_color = bg_color , fontsize = fontsize )
398- m .add_pmtiles (ca_pmtiles , style = style , name = "CA" , opacity = alpha , tooltip = True , fit_bounds = True )
399-
352+ ## filter data and get map styling
400353column = select_column [color_choice ]
401354
402355select_colors = {
@@ -409,31 +362,56 @@ def run_sql(query,color_choice):
409362 "Access Type" : access ["stops" ],
410363}
411364
412- colors = (
413- ibis
414- .memtable (select_colors [color_choice ], columns = [column , "color" ])
415- .to_pandas ()
416- )
365+ colors = color_table (select_colors , color_choice , column )
417366
418367
419368# get summary tables used for charts + printed table
420- # df - charts; df_tab - printed table (omits colors)
421369if 'out' not in locals ():
422- df , df_tab , df_percent , df_bar_30x30 = get_summary_table (ca , column , select_colors , color_choice , filter_cols , filter_vals ,colorby_vals )
370+ df , df_tab , df_percent , df_bar_30x30 = get_summary_table (ca , column , select_colors , color_choice , filter_cols , filter_vals , colorby_vals )
423371 total_percent = (100 * df_percent .percent_CA .sum ()).round (2 )
424-
425372else :
426373 df = get_summary_table_sql (ca , column , colors , ids )
427374 total_percent = (100 * df .percent_CA .sum ()).round (2 )
428375
376+ # build map style and legend
377+ if 'out' not in locals ():
378+ style = get_pmtiles_style (style_options [color_choice ], alpha , filter_cols , filter_vals )
379+
380+ legend ,fontsize = get_legend (style_options , color_choice , df , column )
381+
382+ # add tile/cog/pmtiles layers
383+ if show_richness :
384+ m .add_tile_layer (url_sr , name = "MOBI Species Richness" , opacity = a_bio )
385+ if show_rsr :
386+ m .add_tile_layer (url_rsr , name = "MOBI Range-Size Rarity" , opacity = a_bio )
387+ if show_irrecoverable_carbon :
388+ m .add_cog_layer (url_irr_carbon , palette = "reds" , name = "Irrecoverable Carbon" , opacity = a_climate , fit_bounds = False )
389+ if show_manageable_carbon :
390+ m .add_cog_layer (url_man_carbon , palette = "purples" , name = "Manageable Carbon" , opacity = a_climate , fit_bounds = False )
391+ if show_justice40 :
392+ m .add_pmtiles (url_justice40 , style = justice40_style , name = "Justice40" , opacity = a_people , tooltip = False , fit_bounds = False )
393+ if show_sv :
394+ m .add_pmtiles (url_svi , style = svi_style , opacity = a_people , tooltip = False , fit_bounds = False )
395+ if show_fire :
396+ m .add_pmtiles (url_calfire , style = fire_style , name = "CALFIRE Fire Polygons (2013-2023)" , opacity = a_fire , tooltip = False , fit_bounds = False )
397+ if show_rxburn :
398+ m .add_pmtiles (url_rxburn , style = rx_style , name = "CAL FIRE Prescribed Burns (2013-2023)" , opacity = a_fire , tooltip = False , fit_bounds = False )
399+
400+ # add main CA pmtiles layer and legend
401+ if 'out' not in locals ():
402+ m .add_pmtiles (ca_pmtiles , style = style , name = "30x30 Conserved Areas (Terrestrial)" ,
403+ attribution = "CA Nature (2024)" , tooltip = True )
404+ m .fit_bounds ([- 124.42174575 , 32.53428607 , - 114.13077782 , 42.00950367 ])
405+ m .add_legend (title = '' , legend_dict = legend , fontsize = fontsize ,
406+ bg_color = bg_color , position = position , shape_type = shape_type )
429407
430408# charts displayed based on color_by variable
431409richness_chart = bar_chart (df , column , 'mean_richness' , "Species Richness (2022)" )
432410rsr_chart = bar_chart (df , column , 'mean_rsr' , "Range-Size Rarity (2022)" )
433411irr_carbon_chart = bar_chart (df , column , 'mean_irrecoverable_carbon' , "Irrecoverable Carbon (2018)" )
434412man_carbon_chart = bar_chart (df , column , 'mean_manageable_carbon' , "Manageable Carbon (2018)" )
435413fire_10_chart = bar_chart (df , column , 'mean_fire' , "Fires (2013-2023)" )
436- rx_10_chart = bar_chart (df , column , 'mean_rxburn' ,"Prescribed Burns (2013-2023)" )
414+ rx_10_chart = bar_chart (df , column , 'mean_rxburn' , "Prescribed Burns (2013-2023)" )
437415justice40_chart = bar_chart (df , column , 'mean_disadvantaged' , "Disadvantaged Communities (2021)" )
438416svi_chart = bar_chart (df , column , 'mean_svi' , "Social Vulnerability Index (2022)" )
439417
@@ -446,9 +424,9 @@ def run_sql(query,color_choice):
446424 m .to_streamlit (height = 650 )
447425 with st .expander ("🔍 View/download data" ):
448426 if 'out' not in locals ():
449- st .dataframe (df_tab , use_container_width = True )
427+ st .dataframe (df_tab , use_container_width = True )
450428 else :
451- st .dataframe (out , use_container_width = True )
429+ st .dataframe (out , use_container_width = True )
452430
453431 with stats_col :
454432 with st .container ():
@@ -462,38 +440,27 @@ def run_sql(query,color_choice):
462440
463441 if show_richness :
464442 st .altair_chart (richness_chart , use_container_width = True )
465-
466443 if show_rsr :
467444 st .altair_chart (rsr_chart , use_container_width = True )
468-
469445 if show_irrecoverable_carbon :
470446 st .altair_chart (irr_carbon_chart , use_container_width = True )
471-
472447 if show_manageable_carbon :
473448 st .altair_chart (man_carbon_chart , use_container_width = True )
474-
475449 if show_justice40 :
476450 st .altair_chart (justice40_chart , use_container_width = True )
477-
478451 if show_sv :
479452 st .altair_chart (svi_chart , use_container_width = True )
480-
481453 if show_fire :
482454 st .altair_chart (fire_10_chart , use_container_width = True )
483-
484455 if show_rxburn :
485456 st .altair_chart (rx_10_chart , use_container_width = True )
486457
487458
488459st .caption ("***The label 'established' is inferred from the California Protected Areas Database, which may introduce artifacts. For details on our methodology, please refer to our <a href='https://github.com/boettiger-lab/ca-30x30' target='_blank'>our source code</a>." , unsafe_allow_html = True )
489-
490-
491- st .caption ("***Under California’s 30x30 framework, only GAP codes 1 and 2 are counted toward the conservation goal." )
460+ st .caption ("***Under California's 30x30 framework, only GAP codes 1 and 2 are counted toward the conservation goal." )
492461
493462st .divider ()
494463
495464with open ('app/footer.md' , 'r' ) as file :
496465 footer = file .read ()
497- st .markdown (footer )
498-
499-
466+ st .markdown (footer )
0 commit comments