Component for bi-directional communication with bokeh

@cwerner , well yes you do need to change it to refresh_on_update=True and it will be a little more complex than this.
I tried to create a simple example to see if this is what you are trying to achieve. Let me know if it does or doesnt work for you.

import streamlit as st
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.plotting import figure
import pandas as pd
import numpy as np
from streamlit_bokeh_events import streamlit_bokeh_events
from state import provide_state
from collections import defaultdict

@st.cache
def data():
    df = pd.DataFrame({"x": np.random.rand(500), "y": np.random.rand(500), "z": np.random.rand(500), "size": np.random.rand(500) * 10})
    return df


@provide_state
def main(state):
    # create a map to hold selected points state across different plots
    state.selected_points_map = state.selected_points_map or defaultdict(list)

    x_field = st.selectbox("Select X", ["x", "y", "z"])
    y_field = st.selectbox("Select Y", ["x", "y", "z"])
    df = data()
    source = ColumnDataSource(df)

    # assign selected indices based on the current x_field, y_field 
    # to avoid carrying selected indices between different plots
    source.selected.indices = state.selected_points_map[(x_field, y_field)]

    st.subheader("Select Points From Map")

    plot = figure( tools="lasso_select,reset", width=250, height=250)
    plot.circle(x=x_field, y=y_field, size="size", source=source, alpha=0.6)
    
    source.selected.js_on_change(
        "indices",
        CustomJS(
            args=dict(source=source, x_field=x_field, y_field=y_field),
            code="""
            document.dispatchEvent(
                new CustomEvent("TestSelectEvent", {detail: {indices: cb_obj.indices, fields: [x_field, y_field]}})
            )
        """,
        ),
    )

    event_result = streamlit_bokeh_events(
        events="TestSelectEvent",
        bokeh_plot=plot,
        key="foo",
        debounce_time=100,
        refresh_on_update=True
    )

    # some event was thrown
    if event_result is not None:
        # TestSelectEvent was thrown
        if "TestSelectEvent" in event_result:
            st.subheader("Selected Points' Pandas Stat summary")
            # save selected indeces corresponding to current x_field, y_field in map
            key = tuple(event_result["TestSelectEvent"].get("fields"))
            value = event_result["TestSelectEvent"].get("indices", [])
            state.selected_points_map[key] = value 
    
    # show summary of current fields
    st.table(df.iloc[state.selected_points_map[(x_field, y_field)]].describe())

    st.subheader("Raw Event Data")
    st.write(event_result)
main()

Hope it helps ! :slight_smile: