Make interactive data workflows#

This guide addresses how to bind interactive data pipelines to a component using the Reactive Expressions of Param.


The Param rx object allows you to treat any object as a reactive expression. This is done by replacing the constant parameters in your pipeline with widgets (e.g., a number slider) that will trigger an output update on changes. With this approach, all your pipeline parameters are available in one place, and you get complete interactive control over the pipeline. For convenience, we could use pn.rx instead of param.rx when you import panel as pn.

Let’s start by fetching some data:

import pandas as pd

df = pd.read_csv('https://datasets.holoviz.org/penguins/v1/penguins.csv')
df.head()
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
0 Adelie Torgersen 39.1 18.7 181.0 3750.0 male 2007
1 Adelie Torgersen 39.5 17.4 186.0 3800.0 female 2007
2 Adelie Torgersen 40.3 18.0 195.0 3250.0 female 2007
3 Adelie Torgersen NaN NaN NaN NaN NaN 2007
4 Adelie Torgersen 36.7 19.3 193.0 3450.0 female 2007

We now want to create select widgets for the column species and a slider for year. We can do this with Panel’s widgets:

import panel as pn

pn.extension('tabulator')

species_widget = pn.widgets.Select(name="species", options=["Adelie", "Gentoo", "Chinstrap"])
year_widget = pn.widgets.IntSlider(name="year", start=2007, end=2009)

Let’s then use these to filter the data. We first wrap the df in pn.rx as df_rx and pass the species_widget as the species parameter and the year_widget as the year parameter. In our case, we want the year always to be greater than or equal to the widget’s value.

import hvplot.pandas  # Enable interactive

df_rx = pn.rx(df)
df_rx = df_rx[(df_rx["species"] == species_widget) & (df_rx["year"] >= year_widget)]

df_rx.head()

Similarly we can use other pandas features in the same way.

head_widget = pn.widgets.IntSlider(name="Head", start=1, end=10)

df_rx.head(head_widget)

Because we’ve imported hvplot.pandas, we can utilize .hvplot() to render the widgets and plot the data easily:

idf.hvplot(kind="scatter", x="bill_length_mm", y="bill_depth_mm", by="sex")
Traceback (most recent call last):
  File "/Users/runner/work/panel/panel/panel/io/mime_render.py", line 183, in exec_with_return
    out = eval(compile(_convert_expr(last_ast.body[0]), "<ast>", "eval"), global_context)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<ast>", line 1, in <module>
NameError: name 'idf' is not defined

We can leverage panel.ReactiveExpr to assist in rendering df_rx. This allows us to include all widgets related to df_rx, while also offering the flexibility to customize the appearance of the widgets. For instance, we can specify pn.Column as the widget_layout parameter and top as the widget_location parameter, as shown below:

pn.ReactiveExpr(
    df_rx.head(),  # only show a few rows to save some space
    widget_layout=pn.Column,
    widget_location="top",
)

While panel.ReactiveExpr offers convenience, it’s also common practice to bind the interactive pipeline we’ve constructed to a Panel component, such as a Tabulator widget:

table = pn.widgets.Tabulator(df_rx, page_size=10, pagination="remote")
pn.Column(species_widget, year_widget, table)

Notably, with this approach, we need to handle the layout of widgets ourselves.

For complex expressions involving many widgets, the panel.ReactiveExpr pane offers a .widgets attribute, returning a ListPanel, which helps us retrieve all the related widgets. Once we have access to the widgets, it becomes possible to reposition them or add custom widgets in the final layout.

widgets = pn.ReactiveExpr(df_rx).widgets

pn.Column(
    pn.WidgetBox(*reversed(widgets)),
    pn.Spacer(height=30),
    table,
)

Finally, if performance is critical, you might want to consider using Reactive expressions as references. For instance, you can try replacing df_rx with df_rx.rx() in this tutorial.