Component for bi-directional communication with bokeh

Hey @apex_yu,

You can pass the column name in TableColumn object something like this,

columns = [
TableColumn(field=ā€œxā€, title=ā€œthis is column name xā€)
]

The reason why I havenā€™t given it in docs thoroughly is because itā€™s not really a feature of streamlit-bokeh-events itā€™s more on Bokehā€™s side, You can lookup Bokeh DataTables documentation for more options.

Also I love the idea of having already available functions for the common tasks in the library itself but the streamlit-bokeh-events is a little lower level, so that you can create your own utility functions by wrapping these event handlers as event handling varies widely user to user.

Hope it helps ! :slight_smile:

thanks! @ash2shukla

Hi @ash2shukla

May I ask if you can please add use_container_width parameter support.
without it Iā€™m having an issue to maintain the table aspect ratio on small screens.

Thanks

1 Like

Hey @erezrot,

Surely will look into it. Thanks for pointing out the issue!

Thank you @ash2shukla
One more thing I observed.
If I set refresh_on_update to true and give it another input, the table is changed but the selected rows are not initialized and the results are still related to the previous data table.
Do you have any idea how can I handle this scenario?
Thanks

Hi @erezrot,

A little late but check this topic, I tried to create a wrapper that should be able to resolve your queries,

Regards,
Ashish.

Many thanks @ash2shukla for this awesome data table exampleā€¦
But how could it be possible to display the whole dataframe without the scroll bar (in your example) ?
And how to rename columns ā€¦ instead of ā€œnullā€ ?

@ash2shukla, sorry for this question, but by any means would it be possible to be able to move manually one dot in the scatter plot and get eventually the dataframe values changed accordingly ??

I have fixed this in the latest datatable example, Complete Bokeh DataTable Example using streamlit-bokeh-events please check this.
In order to show the whole dataframe just adjust the viewport height accordingly.

Never say sorry for asking a question ! :slight_smile:
Can you elaborate more on it ?
If you mean that selecting one dot in scatter plot and getting the corresponding values then you can definitely get this done by binding the ā€œtapā€ event in bokeh.

I was rather thinking of moving one dot in the scatter plot in order to change its coordinates (x, y)ā€¦

@ash2shukla, any thoughts about this ?

I acknowledge this is tricky.

Hi @blob123 ,

Sorry for late reply.
You can look into PointDrawTool in Bokeh for this. This is one link that I had come across earlier when I was searching for something similar, python - Bokeh - How to Click and Drag? - Stack Overflow. Though finding the x, y for a certain glyph can be a little challenging.
I am not sure what your usecase is but try looking into drawable canvas component of @andfanilo GitHub - andfanilo/streamlit-drawable-canvas: Do you like Quick, Draw? Well what if you could train/predict doodles drawn inside Streamlit? Also draws lines, circles and boxes over background images for annotation., that might do the job for you.

Hope it helps!

Huh, thatā€™s a really interesting idea! but I think youā€™ll need to build a proper component for this (I donā€™t think DrawableCanvas will fit the job either)

I donā€™t have a proper easy high-level solution for this unfortunately :frowning: whenever thereā€™s interactivity involved it does go into JS territoryā€¦

Iā€™ll check later this month if I can do a thing :wink:

Fanilo

Many thanks @andfanilo .

Hey @blob123,

I whipped up something based on my previous answer.
Got it working working with some bokeh magic. Is it what youā€™re looking for ?

from streamlit_bokeh_events import streamlit_bokeh_events
from bokeh.plotting import figure
from bokeh.models import PointDrawTool, ColumnDataSource, CustomJS
import pandas as pd
import streamlit as st


def plot_and_move(df):
    p = figure(x_range=(0, 10), y_range=(0, 10), tools=[],
            title='Point Draw Tool')

    source = ColumnDataSource(df)

    renderer = p.scatter(x='x', y='y', source=source, size=10)

    draw_tool = PointDrawTool(renderers=[renderer])
    p.add_tools(draw_tool)
    p.toolbar.active_tap = draw_tool

    source.js_on_change("data", CustomJS(
        code="""
            document.dispatchEvent(
                new CustomEvent("DATA_CHANGED", {detail: cb_obj.data})
            )
        """
    ))

    event_result = streamlit_bokeh_events(p, key="foo", events="DATA_CHANGED", refresh_on_update=False, debounce_time=0)

    if event_result:
        df_values = event_result.get("DATA_CHANGED")
        return pd.DataFrame(df_values, index=df_values.pop("index"))
    else:
        return df


df = pd.DataFrame({
        'x': [1, 5, 9], 'y': [1, 5, 9]
})

st.write(plot_and_move(df))

Hope it helps !

2 Likes

Youā€™re becoming quite the Bokeh master there :stuck_out_tongue_winking_eye:

2 Likes

@ash2shukla, this is just awesome !

Many thanks !!

1 Like

Sorry @ash2shukla, by any chance is it possible to prevent the figure from creating new dots when clicking everywhere on the scatter plot ?

Sure, just pass add=False in the PointDrawTool constructor like this,

Change this

draw_tool = PointDrawTool(renderers=[renderer])

To this

draw_tool = PointDrawTool(renderers=[renderer], add=False)

Also check this for more customizations, eg custom icon in toolbar etc. bokeh.models.tools ā€” Bokeh 2.2.3 Documentation

Hope it helps ! :slight_smile: