Running sections of code conditionally

Hey Streamlit community:)

I’m building a Streamlit web app that allows users to create and edit geospatial data. The app takes various user inputs to load or generate data, which is then displayed on a map. Users can also manipulate this data by interacting with the map.

The issue I’m facing is performance-related:

  • Since Streamlit reruns the script on every interaction, interacting with the map causes the entire script to rerun.
  • This leads to slow and unresponsive behavior, especially when certain operations take time (e.g., loading data, processing polygons).
  • I simulated this delay using time.sleep(), in my real code it occurs due to computationally intensive operations.

I tried to use st.session_state to store values and prevent unnecessary reruns, but it doesn’t seem to help, since the map generation is the problem. I also came across st.fragment, which might help, but I’m not sure if it is the proper solution and how to integrate it properly into my code.

Does anyone have suggestions on how to Prevent unnecessary reruns of time intensive operations when interacting with the map?

Here’s a simplified version of my code that demonstrates the issue. Its very crude and patched together but shows the issues im having:

import streamlit as st
from streamlit_folium import st_folium
import folium
from folium.plugins import Draw
import geojson
import numpy as np
import time


bbox=None
start_y=None
end_y=None  
species=None
buffer=None
distance=None


def mapgeojson(poly_file):
##Upload the polygon file
        #Get the center of the Polygon for Map display
        def get_bounding_box(geom):
            coords = np.array(list(geojson.utils.coords(geom)))
            return [coords[:, 0].min(), coords[:, 1].min(), coords[:, 0].max(), coords[:, 1].max()]
        bbox=get_bounding_box(poly_file)
        #st.write (bbox)
        y=bbox[2]-(bbox[2]-bbox[0])/2
        x=bbox[3]-(bbox[3]-bbox[1])/2
        #st.write (x,y)

        #set Map center to the center of the polygon
        if "center" not in st.session_state:
            st.session_state["center"] = [x,y]  # Default center for the map
        #set Map zoom level
        if "zoom" not in st.session_state:
            st.session_state["zoom"] = 6 # Default zoom level

        # if poly_file != st.session_state.poly: #reset if new file is uploaded
        #     st.session_state.poly=poly_file
        #     st.session_state["center"] = [x,y]
        #     st.session_state["zoom"] = 6

##Create the map
        m = folium.Map(location=st.session_state["center"], zoom_start=st.session_state["zoom"])
        fg = folium.FeatureGroup(name="Markers")
        fg.add_child(folium.GeoJson(poly_file))

        ##Display the map
        st_folium(
                m,
                center=st.session_state["center"],
                zoom=st.session_state["zoom"],
                key="new",
                feature_group_to_add=fg,
                height=400,
                width=700,
                
            )
    


def mapbbox():
    #create the map
    m = folium.Map(location=[0,0], zoom_start=2)
    draw = Draw(export=False,   draw_options={
        'polyline': False,  # Disable polyline
        'polygon': False,    # Enable polygon
        'circle': False,    # Disable circle
        'rectangle': True,  # Enable rectangle
        'marker': False,     # Enable marker
        'circlemarker': False  # Disable circle marker
    },
    edit_options={
        'edit': False,   # Enable editing of drawn shapes
        'remove': True  # Enable deleting of drawn shapes
    })
    draw.add_to(m)
    
    def get_bounding_box(geom):
        coords = np.array(list(geojson.utils.coords(geom)))
        
        return [coords[:, 0].min(), coords[:, 1].min(), coords[:, 0].max(), coords[:, 1].max()]
    #display the map
    output = st_folium(m, width=700, height=500)
    #get the bounding box of the last clicked polygon
    if output["last_active_drawing"] is not None:
        geometry = output["last_active_drawing"]["geometry"]
        return get_bounding_box(geometry)




species=st.text_input("Species Name", placeholder="Example: Quercus sartorii")
st.write("You entered: ", species)
if species:
    start_y=st.number_input("Start year", value=None, step=1, min_value=1900, max_value=2021)
    st.write("You entered: ", start_y)
if start_y:
    end_y=st.number_input("End year", value=None, step=1, min_value=1900, max_value=2021)
    st.write("You entered: ", end_y)
    st.write("You entered: ", end_y)
    time.sleep(1)

if end_y:
    bbox = mapbbox()
    st.write("You entered: ", bbox)
    time.sleep(1)

if bbox:
    buffer=st.number_input("Buffer", value=None)
    distance=st.number_input("Distance", value=None)

if buffer and distance:
    polygon_file_path = "/Users/simonrabenmeister/Desktop/Genes_from_Space/Genes_from_Space_interface/Test files/population_polygons_switzerland.geojson"
    st.write("You entered: ", polygon_file_path)
    f = open(polygon_file_path)
    polygons=geojson.load(f)
    mapgeojson(polygons)