Panel 1.3.0 Release

What is Panel?
Panel is an open-source Python library that lets you easily build powerful tools, dashboards and complex applications entirely in Python. It has a batteries-included philosophy, putting the PyData ecosystem, powerful data tables and much more at your fingertips. High-level reactive APIs and lower-level callback based APIs ensure you can quickly build exploratory applications, but you aren’t limited if you build complex, multi-page apps with rich interactivity. Panel is a member of the HoloViz ecosystem, your gateway into a connected ecosystem of data exploration tools.
New release!
We are very pleased to announce the 1.3.0 release of Panel! This release packs many exciting new features, specifically:
- A new
panel.chatsubpackage containing components with powerful capabilities for interacting with LLM whether local or remote. - Compatibility with Param 2.0 bringing powerful new features including the ability to leverage reactive expressions using the
rxwrapper and deeper support for reactively linking parameters, expressions and bound functions on Panel components.
Special thanks to our first time contributors @aktech, @meson800 and @monodera and returning contributors @cdeil, @pierrotsmnrd and @TheoMartin. We also want to highlight the contribution of our new core contributor @ahuang11 for developing the chat components and recognize @MarcSkovMadsen and @philippjfr for their efforts on testing and improving these new components. Finally we thank the entire core team including @sophiamyang, @Hoxbro, @MarcSkovMadsen, @maximlt, @ahuang11 and @philippjfr for their continued efforts.
If you are using Anaconda, you can get latest Panel with conda install panel , and using pip you can install it with pip install panel.
Chat Components
With the huge amount of popularity of LLMs it is way overdue for Panel to add components that make it easy to interact with them. See the following trailer as a quick introduction:
and find a variety of examples demonstrating the cabilities of these new features at Panel Chat Examples page, including examples using LangChain, OpenAI, Mistral, Llama, and RAG.
In Panel we want to focus on building general components that let you achieve what you need but also provide the flexibility to compose components as needed. Therefore the panel.chat subpackage consists of a number of components which are composable incudling the:
These components build on each other as shown in the diagram below:

At the core is a ChatMessage which can encapsulate any other output and associates this with a user, a timestamp and reaction icons:
msg = pn.chat.ChatMessage('When did Panel add support for Chat components?', user='User')
msgThe ChatFeed adds support for composing multiple ChatMessages and a simply API for sending new messages:
feed = pn.chat.ChatFeed(msg)
feed.send('Chat components were added in v1.3.0!', user='Developer', avatar='👩')
feedLastly the ChatInterface extends the ChatFeed by adding a UI for interacting with the ChatFeed:
pn.chat.ChatInterface(*feed, width=600)Finally we have added basic support for integrating with LangChain via the PanelCallbackHandler, which we hope will eventually be merged into Langchain itself (if you’re a Langchain dev, call us 😊).
Reactive Expressions & References
Panel 1.3.0 now requires Param 2.0 which we are releasing simultaneously. Not only does the new Param release clean up the namespace of all Panel objects but it also adds support for two major new capabilities:
- Allow passing parameters, widgets, expressions and bound functions as references to Panel components
- Integrating support for reactive expressions using the
param.rxAPI
To unpack this a little bit let’s play around with rx a little bit:
slider = pn.widgets.IntSlider(start=0, end=7, value=3)
slider.rx() ** 2This very simple example demonstrates the core idea behind reactive expressions. It allows you to treat a dynamic reference, e.g. a widget value, as if it was the actual object, in this case an int. This allows you to build reactive pipelines using natural syntax. To discover more about reactive expressions, see the Param documentation.
Of course this extends well beyond this simple example and when combined with the ability for Panel components to resolve references makes it possible to write complex interactive components using natural syntax:
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 = pn.bind(pd.read_csv, dataset).rx().sample(n=nrows)
# Bind the current value of the `df` expression to the Tabulator widget
table = pn.widgets.Tabulator(df, page_size=5, pagination='remote')
pn.Row(pn.Column(dataset, nrows), table)
Using pn.bind we can dynamically load various datasets and then apply transformations by turning the result into a reactive expression, e.g. to sample a variable number of rows from the dataset. Lastly we can pass the resulting reactive expression to Tabulator which will automatically reflect the result of the expression.
Not only can Panel now resolve such expressions but it can even resolve references nested inside another object:
font_size = pn.widgets.FloatSlider(start=6, end=24, value=12, name='Font Size')
color = pn.widgets.ColorPicker(name='Color')
pn.Row(
pn.Column(font_size, color),
pn.pane.HTML('Hello World!', styles={'color': color, 'font-size': pn.rx('{}pt').format(font_size)})
)
Enhancements & Components
OAuth improvements
Panel has shipped with OAuth integration for a very long time. In this release we finally spent some time rationalizing the code and adding support for:
- Authorization code and password based OAuth grant workflows for when you don’t want to issue a client secret for your Panel application
- Adding the ability to automatically refresh
access_tokens whenever they expire using the--oauth-refresh-tokens(discover more here)
Colormap Widget
The new ColorMap widget makes it easy to let users pick between multiple color palettes.
from matplotlib.cm import Reds, Greens, Blues, viridis
cmaps = {'Reds': Reds, 'Greens': Greens, 'Blues': Blues, 'viridis': viridis}
pn.widgets.ColorMap(options=cmaps, ncols=2)Changelog
Feature
Enhancement
- Add unit to widget in
HoloViewspane if provided (#5535) - Allow registering global
on_session_destroyedcallback (#5585) - Implement
auto_growonTextAreaInput(#5592) - Add ability to redirect users from authorization callback (#5594)
- Add support for
Pathobject inFileDownload(#5607) - Add authorization_code and password based OAuth login handlers (#5547)
- Add format to
EditableFloatSliderandEditableIntSlider(#5631) - Add support for decorating async functions with
pn.io.cache(#5649) - Map
param.BytestoFileInputwidget (#5665)
Bug fixes
- Fixes for
Columninvisiblescroll_buttontaking space (#5532) - Guard undefined values from being set on
BrowserInfo(#5588) - Fix thumbnails and use Panel design on index page (#5595)
- Fix regressions in
TextEditorcaused by migration to shadow DOM (#5609) - Sync
locationstate from request (#5581) - Fix
Selectwidget label offset in Material Design (#5639) - Override token contents when reusing sessions (#5640)
- Fix patching a table with a
DataFramewith a custom index (#5645) - Set
FloatPanelstatus correctly on initialization (#5651) - Fix patching table with
pd.Timestampvalues (#5650) - Ensure
notificationsandbrowser_infoare loaded whenHoloViewsis loaded - Gracefully handle resolution of invalid paths in
_stylesheets(#5666) - Handle patching tables with
NaTvalues (#5675)
Compatibility
- Upgrade to Param 2.0
- Compatibility with Bokeh 3.3.0