ReactiveExpr#

Open this notebook in Jupyterlite | Download this notebook from GitHub (right-click to download).


import panel as pn

pn.extension('tabulator', design="material")

The panel.ReactiveExpr pane renders a Param rx object which represents a reactive expression, displaying both the widgets that are part of the expression and the final output of the expression. The position of the widgets relative to the output can be set, or widgets can be removed entirely.

Please note that you can use use pn.rx instead of param.rx when you import panel as pn.

See the param.rx documentation for details on using rx.

Parameters:#

The basic parameters are:

The more advanced parameters which give you more control are:

  • center (bool): Whether to center the output horizontally.

  • show_widgets (bool): Whether to show the widgets.

  • widget_layout (ListPanel): The layout object to display the widgets in. For example pn.WidgetBox (default), pn.Column or pn.Row.

  • widget_location (str): The location of the widgets relative to the output of the reactive expression. One of ‘left’, ‘right’, ‘top’, ‘bottom’, ‘top_left’, ‘top_right’, ‘bottom_left’, ‘bottom_right’, ‘left_top’ (default), ‘right_top’,right_bottom’.

Properties#

  • widgets (ListPanel): Returns the widgets in a widget_layout.

For more layout and styling related parameters see the customization user guide.


The param.rx API is a powerful tool for building declarative and reactive UIs.

Lets take a few examples

def model(n):
    return f"🤖 {n}x2 is {n*2}"

n = pn.widgets.IntSlider(value=2, start=0, end=10)
pn.rx(model)(n=n)

Behind the scenes panel has made sure the reactive expression above is rendered in a pn.ReactiveExpr pane. You can also do this explicitly

n = pn.widgets.IntSlider(value=2, start=0, end=10)
pn.ReactiveExpr(pn.rx(model)(n=n))

A reactive expression is never a dead end. You can always update and change a reactive expression.

n = pn.widgets.IntSlider(value=2, start=0, end=10)

pn.rx(model)(n=n) + "\n\n🧑 Thanks"

You can also combine reactive expressions

x = pn.widgets.IntSlider(value=2, start=0, end=10, name="x")
y = pn.widgets.IntSlider(value=2, start=0, end=10, name="y")

expr = x.rx()*"⭐" + y.rx()*"⭐"
expr

Layouts#

You can change the widget_location.

x = pn.widgets.IntSlider(value=2, start=0, end=10, name="x")
y = pn.widgets.IntSlider(value=2, start=0, end=10, name="y")

expr = x.rx()*"⭐" + "\n\n" + y.rx()*"❤️"

pn.ReactiveExpr(expr, widget_location="top")

You can change the widget_layout to Row

pn.ReactiveExpr(expr, widget_layout=pn.Row)

You can center the output horizontally

pn.ReactiveExpr(expr, center=True)

You can hide the widgets by setting show_widgets=False

pn.ReactiveExpr(expr, show_widgets=False)

You can access the .widgets in a widget_layout and lay them out as you please

pn.ReactiveExpr(expr).widgets

Reactive expressions as references#

Using the pn.ReactiveExpr pane implicitly or explicitly is great for exploration in a notebook. But its not very performant because every time the reactive expression rerenders, Panel has to create a new pane to render your output in.

Instead you can and should pass the reactive expression as a reference to a specific Panel component. The Panel component can resolve the value of the expression dynamically:

x = pn.widgets.IntSlider(value=2, start=0, end=10, name="x")
y = pn.widgets.IntSlider(value=2, start=0, end=10, name="y")

ref = x.rx() + y.rx()
pn.pane.Str(ref)
pn.indicators.Progress(name='Progress', value=ref, max=20)

Try changing the x and y values using the widgets below!

pn.ReactiveExpr(ref).widgets

The reference approach should generally be preferred as it is more declarative and explicit, allowing Panel to efficiently update the existing view(s) rather than completely re-rendering the output.

Styled DataFrame Example#

Let us work through this in a slightly more complex example, and build an expression to dynamically load some data and sample N rows from it:

import pandas as pd

dataset = pn.widgets.Select(name='Pick a dataset', options={
    'penguins': 'https://datasets.holoviz.org/penguins/v1/penguins.csv',
    'stocks': 'https://datasets.holoviz.org/stocks/v1/stocks.csv'
})
nrows = pn.widgets.IntSlider(value=5, start=0, end=20, name='N rows')

# Load the currently selected dataset and sample nrows from it
df_rx = pn.rx(pd.read_csv)(dataset).sample(n=nrows)

df_rx

Now that we have an expression that does what we want we can use it as a reference to reactive update the value of a Tabulator widget:

table = pn.widgets.Tabulator(df_rx, page_size=5, pagination='remote')

table.style.bar(cmap='RdYlGn_r')

pn.Row(pn.Column(dataset, nrows), table)

However, particularly for complex expressions with tons of inputs it may still be useful to use the ReactiveExpr object to render all the widget inputs:

pn.Row(pn.ReactiveExpr(df_rx).widgets, table)

Open this notebook in Jupyterlite | Download this notebook from GitHub (right-click to download).