# Streaming Tabulator & Column Filter

**URL:** <https://discourse.holoviz.org/t/streaming-tabulator-column-filter/8426>\
**Category:** Panel\
**Tags:** streaming, tabulator\
**Created:** [November 26, 2024, 10:34pm UTC](https://discourse.holoviz.org/t/streaming-tabulator-column-filter/8426 "2024-11-26T22:34:51Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![killcoder](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/killcoder/32/3236_2.png) [@killcoder](https://discourse.holoviz.org/u/killcoder)\
**Post date:** [November 26, 2024, 10:34pm UTC](https://discourse.holoviz.org/t/streaming-tabulator-column-filter/8426/1 "2024-11-26T22:34:51Z")

</div>

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](https://panel.holoviz.org/how_to/callbacks/examples/streaming_tabulator.html#streaming-tabulator) example of the doc’s and adding in a filtering function as per [Tabulator — Panel v1.5.4](https://panel.holoviz.org/reference/widgets/Tabulator.html#function-based-filtering) 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

```auto
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?

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [December 6, 2024, 1:55am UTC](https://discourse.holoviz.org/t/streaming-tabulator-column-filter/8426/2 "2024-12-06T01:55:10Z")

</div>

Could you post a video showing the performance?

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

---

<div class="post-metadata">

**Author:** ![killcoder](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/killcoder/32/3236_2.png) [@killcoder](https://discourse.holoviz.org/u/killcoder)\
**Post date:** [December 6, 2024, 2:35am UTC](https://discourse.holoviz.org/t/streaming-tabulator-column-filter/8426/3 "2024-12-06T02:35:07Z")

</div>

@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.

---

<div class="post-metadata">

**Author:** ![coderambling](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/coderambling/32/6347_2.png) [@coderambling](https://discourse.holoviz.org/u/coderambling)\
**Post date:** [February 8, 2025, 4:01pm UTC](https://discourse.holoviz.org/t/streaming-tabulator-column-filter/8426/4 "2025-02-08T16:01:39Z")

</div>

When you say under the hood, do you mean under the hood of the Panel Tabulator component?

Currently the .stream method of the Tabulator component appears to use the updateOrAddData method of Tabulator. [Updating Data | Tabulator](https://tabulator.info/docs/6.3/update)

> <https://github.com/holoviz/panel/blob/8463ff8ab902c6cb3ffed021d57e274052474a3a/panel/models/tabulator.ts#L480-L492>

Would the way forward be to make the .stream method async?

Or would that not fix the issue? I feels i.portant streaming should function for at least the Tabulator component, as it is the recommended way to display dataframes in Panel.

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [February 10, 2025, 6:12pm UTC](https://discourse.holoviz.org/t/streaming-tabulator-column-filter/8426/5 "2025-02-10T18:12:55Z")

</div>

The python method isn’t async AFAIK.
