Panel 1.4.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.4.0 release of Panel! This release packs many exciting new features, specifically:
- Add
EditableTemplate
to support dashboard builder UI in Jupyter (#5802) - Add
ChatAreaInput
as default text input widget forChatInterface
(#6379) - Add
NestedSelect
widget (#5791, #6011) - Improve
--autoreload
by using watchfiles and selectively reloading packages (#5894, #6459) - Add Panel tutorials (#5525, #6208, #6212, #6388, #6425, #6466, #6491)
- Add
DateRangePicker
widget (#6027) - Add
Feed
layout and use it as a layout forChatFeed
(#6031, #6296) - Add
WebP
pane (#6035) - Add
ButtonIcon
(#6138) - Add
Textual
pane (#6181)
We really appreciate all the work that went into this release and especially want to call out @MarcSkovMadsen’s effort in putting together the new tutorial materials. There’s more work to do but it’s a huge step forward and we’re excited to hear your feedback. We want to extend a special thanks to our amazing new crop of new contributors including @atisor73, @OSuwaidi, @suryako, @Davide-sd, @doraaki, @mayonnaisecolouredbenz7, @CTPassion, @j01024, @l3ender and @Coderambling. Next we want to recognize our returning contributors @vaniisgh, @cdeil, @limx0m, and @TheoMaturin, and finally the dedicated crew of core contributors which include @maximlt, @Hoxbro, @MarcSkovMadsen, @ahuang11, @mattpap and @philippjfr.
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
.
Tutorials
Last year we decided to embark on a project to completely re-architect our documentation leaning heavily on the Diataxis framework. In doing so we got rid of the long form user guides and migrated most of the material into How-to guides. Overall the feedback about this change was very positive as it became easier to find what you were looking for, but it also made it more difficult for new users to learn about Panel.
The new tutorials aim to address this gap by providing a guided set of lessons that aim to get you from a complete novice to an advanced user. The tutorial is split into Basic, Intermediate and Advanced sections and is structured as a series of lessons culminating in topic focused guides on building specific applications, e.g. a chat app, monitoring dashboard or a to-do app.
Designing meaningful and engaging lessons is a huge undertaking so we hope to gather your feedback to continue refining the material. We want to especially thank Marc Skov Madsen for putting such a tremendous amount of effort into these materials.
Dashboard Builder UI
The biggest new feature in this release is the addition of a dashboard builder UI that allows building a dashboard layout entirely using a drag and drop interface. Our aim has always been to empower users to quickly share their analyses and results with others and the dashboard builder UI allows building applications without even importing Panel at all. The UI is built on top of a new template component - the EditableTemplate
. This template leverages interact.js and Muuri to provide a smooth user experience when laying out components on the page. Let us see it in action:
As the video demonstrates the dashboard builder allows us to take a notebook with or without Panel components re-arrange, delete and move around cell outputs and markdown cells to build a dashboard.
Autoreload
In previous versions, Panel’s autoreload feature was a handy tool for developers, allowing them to see changes in their applications in real time without the need for manual refreshes. In this release we have outsourced the detection of changes to the watchfiles, not only have we improved the speed of file detection changes, but we have also enhanced the reliability and responsiveness of the autoreload process. To get the benefits of this improved autoreload experience install watchfiles with pip
or conda
.
As part of the improvements we have already improved the handling around of reloading of local modules and entire packages. The improved autoreload mechanism now offers more robust support for detecting changes within your project’s modules and packages, ensuring that any update, no matter how small or where it occurs, will trigger a reload.
Chat Improvements
As the world of LLMs and chat bots built around them continues to advance we are working hard on building the simplest and most feature rich Chat interface with out-of-the-box support for multi-modal outputs and much more.
The two main enhancements of the ChatInterface
in this release were the addition of two new base components:
Feed
The Feed
layout added to Panel makes it possible to build a (near) infinitely scrollable layout making it possible for us to support chats with huge message histories containing 100s or 1000s of messages without having to render it all at once.
ChatAreaInput
The old TextInput
and TextArea
used as the text entry widget for the ChatInterface
were providing a sub-optimal user experience. Therefore we introduced the ChatAreaInput
with behavior closer to what you’re used to from familar chat interfaces like OpenAI including send on <Enter>
and multi-line input using <Shift>+<Enter>
key combinations. We aim to continue refining this component over time:
='Start a chat...') pn.chat.ChatAreaInput(placeholder
Other enhancements
There are a whole host of other improvements for the chat components in this release:
- Every part of a
ChatMessage
can now be styled - Addition of more default avatars
- The ability to add custom objects to the header and footer of a
ChatMessage
pn.Row(f'```css\n{stylesheet}```', margin=0, height=300, styles={'overflow-y': 'scroll'}),
pn.pane.Markdown(
pn.chat.ChatMessage("Style me up!",
=True,
show_activity_dot=['I am a custom header'],
header_objects=['I am a custom footer'],
footer_objects=[stylesheet], width=600
stylesheets
) )
Reactive Expressions & References
In Panel 1.3.0 we introduced new concepts around reactive expressions using the param.rx
API and the ability to bind reactive references to parameters. This release continues to build on this support in a number of ways:
(Asynchronous) Generator Expressions
Streaming in Panel has long been possible by registering periodic callbacks, but as we are moving more and more towards a more reactive approach to writing applications we have been improving the support for building applications with (asynchronous) generators. If you upgrade to Param 2.1 you can now use rx
expressions that are driven by a generator.
To provide a simple demonstration of this approach let us build a generator that emits a value every 0.1 seconds. By wrapping the generator in pn.rx
we can now perform standard arithmetic on this dynamic value, e.g. by adding an offset derived from a widget value:
def gen():
while True:
0.1)
time.sleep(yield np.random.randn()
= pn.widgets.FloatSlider(value=0, end=5, name='Offset')
offset
pn.Column(
offset,=pn.rx(gen)+offset, format='{value:.3f}', width=250, font_size='36pt')
pn.widgets.Number(value; )
The ability to perform operations on dynamic values derived from generators, parameter values and widgets in this way provides a concise way to express complex data pipelines in a declarative way and thanks to support for binding the reactive references you can easily tie these dynamic values to visual outputs. To discover more about this read some of the new explanation materials on reactivity in Panel and references in Param.
Skipping updates
One sticking point when working with reactive functions created using the pn.bind
API was that there was no way to signal that you did not want to update the output until some condition was met. In Param 2.1 and Panel 1.4 it is now possible to Skip
updates by raising a param.Skip
exception.
A good example of this is a form that gathers some inputs but should not run until a button is clicked. In our add
callback we return Skip
until the button triggers a calculate event at which point we yield a message to say we are Calculating and then yield the result:
= pn.widgets.FloatSlider()
a_slider = pn.widgets.FloatSlider()
b_slider = pn.widgets.Button(name='Calculate')
button
def add(a, b, calculate):
if not calculate:
return pn.param.Skip
yield '**Calculating...**'
1)
time.sleep(yield f'**{a} + {b} = {a+b:.1f}**'
; pn.Column(a_slider, b_slider, button, pn.bind(add, a_slider, b_slider, button))
New Components
No new Panel release would be complete without the addition of at least a few new components. In addition to some of the new Chat components we also have a few new panes and widgets for you.
Textual
Textual is a Rapid Application Development framework for Python allowing users to build so called TUIs. As the popularity of this framework has grown and more and a growing number of tools offer Textual UIs we decided to explore whether it would be possible to embed these apps inside Panel, and quickly the Textual
pane was born - wrap any Textual application in Panel and use it from within a notebook or in your standalone application:
New widgets
Every new Panel release must come with at least a few new widgets, in this release we have three main new additions for you the NestedSelect
widget to simplify selection of values with a hierarchical relationship, the DateRangePicker
, a simplified version of the DatetimeRangePicker
without the time selection and the ButtonIcon
.
NestedSelect
The NestedSelect
widget makes it possible to express hierarchical relationship either using a static definition or by providing a callback to generate the valid values:
= pn.widgets.NestedSelect(
nested_select ={
options"Africa": {
"Ghana": ["Accra", "Kumasi", "Tamale"],
"Nigeria": ["Abuja", "Kano", "Ibadan", "Lagos"],
},"Asia": {
"Thailand": ["Bangkok", "Chiang Mai", "Nakhon Ratchasima"],
"Vietnam": ["Da Nang", "Hanoi", "Ho Chi Minh City"],
},
},=["Continent", "Country", "City"],
levels
)
; pn.Row(nested_select, pn.pane.ParamRef(nested_select.param.value))
DateRangePicker
The DateRangePicker
widget provides a simple but welcome addition to the widget pantheon as the smaller brother of the DatetimeRangePicker
.
=(dt.date(2023, 11, 17), dt.date(2024, 3, 27)), name='DateRangePicker'); pn.widgets.DateRangePicker(value
Roadmap
The Panel 1.4.0 release was quite feature packed but we already have a number of major new features in the pipline.
ESM Components
In Panel 1.5.0 we plan to finally provide a more robust replacement for ReactiveHTML
based on ESM modules with a modern development experience including hotreloading, ability to import JS modules and React based components.
Session Handling & Scaling
Recently we found various opportunities for optimizing and parallelizing session creation and session handling including moving the session creation to threads and opening up the ability to re-connect to a session if the websocket is closed.
Changelog
Features
- Add
EditableTemplate
to support dashboard builder UI in Jupyter (#5802) - Add
ChatAreaInput
as default text input widget forChatInterface
(#6379) - Add
NestedSelect
widget (#5791, #6011) - Add Panel tutorials (#5525, #6208, #6212, #6388, #6425, #6466, #6491)
- Add
DateRangePicker
widget (#6027) - Add
Feed
layout and use it as layout forChatFeed
(#6031, #6296) - Add
WebP
pane (#6035) - Add
ButtonIcon
(#6138) - Add
Textual
pane (#6181)
Enhancements
- Improve
--autoreload
by using watchfiles and selectively reloading packages (#5894, #6459) Load loading indicator from file instead of inlining (#6112) - Allow providing additional stylesheets in
card_params
(#6242) - Add
scroll
options to permanently toggle on layouts (#6266) - Allow choosing position of frozen columns on
Tabulator
(#6309) - Add help message on
ChatFeed
(#6311) - Ensure CSS can be applied to every aspect of
ChatMessage
(#6346) - Add HoloViz logos as
ChatMessage
avatars (#6348) - Add
gap
parameter toFlexBox
(#6354) - Set default
step
ofDatetimeRangeSlider
to 1 minute (#6373) - Add support for passing objects reference to
FlexBox
(#6387) - Allow editable sliders to be embedded (#6391)
- Add
message
intocss_classes
toChatMessage
markup (#6407) - Allow appending objects to the
ChatMessage
header & footer (#6410) - Add ability to declare icon label (#6411)
- Add title and settings and fix datetime to
Perspective
(#6482) - Warn user if loading extension in VSCode or Colab without
jupyter_bokeh
(#6485) - Throttle updates to Boolean indicators (#6481)
- Add
ParamRef
baseclass forParamFunction
andParamMethod
(#6392) - Add ability to Skip
Param<Ref|Function|Method>
updates (#6396) - Add
Param<Ref|Method|Function>
andReactiveExpr
to panes module (#6432) - Set up
param.rx
display accessor on import (#6470) - Allow using Carto tiles in
DeckGL
(#6531) - Improve
VTKJS
binary serialization (#6559) - Ensure component CSS is pre-loaded if possible, avoiding flicker on load (#6563)
Styling
- Ensure navbar toggle icon is correct color in
BootstrapTemplate
(#6111) - Change
loading
background filters to work better in dark themes (#6112) - Improve styling of
FileInput
widget (#6479) - Improve Jupyter Preview error handling and error template (#6496)
- Add scale animation to icons on hover and click (#6376)
- Redesign index pages (#6497)
- Improve
Tabulator
editor text color inFast
design (#6512) - Ensure
BootstrapTemplate
hamburger icon is white (#6562)
Compatibility & Version Updates
Bug fixes
- Add resize handler for
FloatPanel
(#6201) - Fix serving of global template in notebook (#6210)
- Ensure
Tabulator
renders in collapsedCard
(#6223) - Fix issues with
VTK
,VTKVolume
andVTKJS
due to webgpu renderer (#6244) - Ensure
HTML
and other markup panes can be emptied (#6303) - Ensure collapsed
Card
does not cause stretching (#6305) - Ensure notebook preview always uses server resources (#6317)
- Remove animation from loading spinner without spin (#6324)
- Ensure model is only added/removed from Document once (#6342)
- Ensure
loading_indicator
resets when configured with context manager (#6343) - Fix modal overflow and resizing issues (#6355)
- Ensure that ripple matches notification size (#6360)
- Fully re-render
CodeEditor
on render calls ensuring it displays correctly (#6361) - Ensure
FileDownload
button has correct height (#6362) - Ensure
HTML
model is redrawn ifstylesheets
is emptied (#6365) - Allow providing custom template (#6383)
- Ensure
Debugger
renders without error (#6423) - Ensure pending writes are dispatched in order and only from correct thread (#6443)
- Ensure layout reuses model if available (#6446)
- Improved exception handler in unlocked message dispatch (#6447)
- Fix display of interactive
Matplotlib
(#6450) - Ensure
Plotly
pane renders and hides correctly inCard
(#6468) - Fix issues rendering widget components with
Fast
design (#6474) - Fix binary serialization from JS -> Pyodide (#6490)
- Avoid overeager garbage collection (#6518)
- Fix floating point error in
IntRangeSlider
(#6516) - Load JS modules from relative path (#6526)
- Ensure no events are dispatched before the websocket is open (#6528)
- Ensure
Markdown
parsing does not choke on partial links (#6535) - Fixes to ensure larger
PDF
s can be rendered (#6538) - Ensure
IPywidget
comms are only opened once (#6542) - Fixes for message handling in Jupyter Preview context (#6547)
- Fix unnecessary loading of
ReactiveHTML
resources (#6552) - Ensure
Template.raw_css
has higher precedence than default template CSS (#6554) - Avoid asyncio event loop startup issues in some contexts (#6555)
- Ensure column subset is retained on
Tabulator.style
(#6560) - Ensure bokeh mathjax bundle when mathjax extension is loaded in notebook (#6564)
Chat Components
- Ensure
ChatInterface
respect supplied default user (#6290) - Ensure
ChatMessage
internals correctly respectDesign
(#6304) - Fix
ChatInterface
stop
button for synchronous functions (#6312) - Include
stylesheets
downstream, including layouts in ChatMessage (#6405) - Ensure
ChatMessage
header
updates dynamically (#6441) - Ensure streaming
ChatMessage
onChatInterface
and mentionserialize
(#6452) - Ensure ChatInterface supports chat input without
value_input
parameter (#6505) - Ensure word breaks to avoid overflow in
ChatMessage
(#6187, #6509) - Ensure nested disabled state stays disabled on
ChatFeed
(#6507) - Allow streaming
None
as the initialChatMessage
value (#6522)
Documentation
- Add Roadmap to documentation (#5443)
- Refactor
ReactiveHTML
docs (#5448, #6358) - Improve
HoloViews
reference guide (#6065) - Improve the user experience for resetting Jupyterlite (#6198)
- Add explanation docs about APIs (#6289, #6469)
- Add section headers to Chat reference documentation (#6370)
- Migrate gallery to new Anaconda DSP instance (#6413)
- Improve home page (#6422)
- Adding AWS deployment to documentation (#6434)
- Update Streamlit comparison (#6467)
- Add logging how-to guide (#6511)
- Document pygments dependency for code syntax highlighting (#6519)
- Add how-to guide on configuring PyCharm (#6525)
Deprecations & Removals
- Remove
Ace
alias forCodeEditor
- Remove
ChatBox
which has been replaced bypanel.chat
components - Remove
HTML.style
which is now replaced withHTML.styles
- Remove
Trend.title
which is now replaced byTrend.name
- Remove
Viewable.app
which is now replaced withpn.io.notebook.show_server
- Remove
Viewable.background
which is now replaced withViewable(styles={'background': ...})
- Remove
Viewable.pprint
which is now replaced withprint(Viewable(...))