Streaming Tabulator & Column Filter

Hello All,

I’m trying to build a streaming tabulator app which allows the user to filter the displayed columns.

Following the Streaming Tabulator — Panel v1.5.4 example of the doc’s and adding in a filtering function as per Tabulator — Panel v1.5.4 I’m able to get the async function updating the tabulator table and the contains_filter to hide columns not selected.

However, the app very quickly becomes unresponsive (on my laptop) when interacting with the widgets.

MRE

import numpy as np
import pandas as pd
import panel as pn
from asyncio import sleep
import string


pn.extension("tabulator", sizing_mode="stretch_width")


columns = list(string.ascii_lowercase + string.ascii_uppercase + string.digits)

df = pd.DataFrame(
    np.random.randn(10, 62),
    columns=list(string.ascii_lowercase + string.ascii_uppercase + string.digits),
).cumsum()

rollover = pn.widgets.IntInput(name="Rollover", value=15)
follow = pn.widgets.Checkbox(name="Follow", value=True, align="end")


tabulator = pn.widgets.Tabulator(
    df,
    height=550,
    hidden_columns=[x for x in columns if x != "a"],
    disabled=True,
)
column_filter = pn.widgets.MultiSelect(name="Column Filter", options=columns, value=["a"])


@pn.depends(column_filter, watch=True)
def contains_filter(column_filter):
    tabulator.hidden_columns = [x for x in columns if x not in column_filter]


# tabulator.add_filter(pn.bind(contains_filter, pattern=column_filter, column="A"))


def color_negative_red(val):
    """
    Takes a scalar and returns a string with
    the css property `'color: red'` for negative
    strings, black otherwise.
    """
    color = "red" if val < 0 else "green"
    return "color: %s" % color


tabulator.style.map(color_negative_red)


def stream():
    data = df.iloc[-1] + np.random.randn(62)
    tabulator.stream(data, rollover=rollover.value, follow=follow.value)


update_rate = 5


template = pn.template.VanillaTemplate(
    title="Real Time Display",
    theme="dark",
    sidebar=pn.Column(
        column_filter,
        rollover,
        follow,
        width=320,
        sizing_mode="fixed",
    ),
    main=tabulator,
).servable()


async def run():
    while True:
        await sleep(1 / update_rate)
        stream()


pn.state.onload(run)

Now I don’t plan to allow the user to select more than a certain number of columns at once but even in this streaming example it’s very easy to overload the app and make widgets / updates become unresponsive.

Is there a better way to work streaming tabulator?

1 Like

Could you post a video showing the performance?

I wonder if tabulator.stream can be made async under the hood.

1 Like

@ahuang11 as requested, I had to cut it short & crop the size to be able to upload the video, but you’ll get the picture.

1 Like