Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Placeholder pane #6790

Merged
merged 3 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions examples/reference/panes/Placeholder.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import asyncio\n",
"import panel as pn\n",
"\n",
"pn.extension()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `Placeholder` pane serves as a placeholder for other Panel components. It can be used to display a message while a computation is running, for example.\n",
"\n",
"#### Parameters:\n",
"\n",
"For details on other options for customizing the component see the [layout](../../how_to/layout/index.md) and [styling](../../how_to/styling/index.md) how-to guides.\n",
"\n",
"* **`object`** (Any): The Panel object to display, if object is not already a Panel object it will be converted with the `panel(...)` function.\n",
"\n",
"___"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `Placeholder` pane can accept any Panel component as its argument, including other panes."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"placeholder = pn.pane.Placeholder(\"Hello\")\n",
"placeholder"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The benefit of using a `Placeholder` is that it allows you to replace the content of the pane without being restricted to a specific type of component. This means you can replace the placeholder with any other pane type, including plots, images, and widgets. You may either use the `update` method:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"placeholder.update(pn.widgets.TextInput(value=\"Hello again!\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"or set the `object` directly:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"placeholder.object = \"Hello once more!\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you'd like to temporarily replace the contents, you can use it as a context manager."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"placeholder = pn.pane.Placeholder(\"⏳ Idle\")\n",
"placeholder"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Upon execution of the cell below, the `Placeholder` pane will display `Starting...`, `Running...`, and `Complete!` in sequence, with a 1 second pause between each message, before finally displaying `Idle` again."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"with placeholder:\n",
" placeholder.update(\"🚀 Starting...\")\n",
" await asyncio.sleep(1)\n",
" placeholder.update(\"🏃 Running...\")\n",
" await asyncio.sleep(1)\n",
" placeholder.update(\"✅ Complete!\")\n",
" await asyncio.sleep(1)"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
2 changes: 2 additions & 0 deletions panel/pane/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
)
from .media import Audio, Video # noqa
from .perspective import Perspective # noqa
from .placeholder import Placeholder # noqa
from .plot import ( # noqa
YT, Bokeh, Matplotlib, RGGPlot,
)
Expand Down Expand Up @@ -84,6 +85,7 @@
"panel",
"PDF",
"Perspective",
"Placeholder",
"Plotly",
"PNG",
"ReactiveExpr",
Expand Down
58 changes: 58 additions & 0 deletions panel/pane/placeholder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""
Defines the Placeholder pane which serves as a placeholder for other Panel components.
"""

from __future__ import annotations

import param

from ..pane.base import ReplacementPane


class Placeholder(ReplacementPane):
"""
The `Placeholder` pane serves as a placeholder for other Panel components.
It can be used to display a message while a computation is running, for
example.

Reference: https://panel.holoviz.org/reference/panes/Placeholder.html

:Example:

>>> with Placeholder("⏳ Idle"):
... placeholder.object = "🏃 Running..."
"""

def __init__(self, object=None, **params):
super().__init__(object=object, **params)
self._past_object = object # used to restore object when Placeholder is exited
self._temporary = False
if object is not None:
self._replace_panel()

@param.depends("object", watch=True)
def _replace_panel(self):
if not self._temporary:
self._past_object = self.object
self._update_inner(self.object)

def __enter__(self):
self._temporary = True
return self

def __exit__(self, exc_type, exc_value, traceback):
try:
self.object = self._past_object
finally:
self._temporary = False
return False

def update(self, object):
"""
Updates the object on the Placeholder.

Arguments
---------
object: The object to update the Placeholder with.
"""
self.object = object
28 changes: 28 additions & 0 deletions panel/tests/pane/test_placeholder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import param

from panel.pane.placeholder import Placeholder
from panel.widgets import IntInput


class TestPlaceholder:

def test_update_object(self):
placeholder = Placeholder("Idle")
placeholder.object = "Running..."
assert placeholder.object == "Running..."
placeholder.object = "New"
assert placeholder.object == "New"

def test_enter_exit(self):
placeholder = Placeholder("⏳ Idle")
with placeholder:
placeholder.object = "🏃 Running..."
assert placeholder.object == "🏃 Running..."
placeholder.object = "🚶 Walking..."
assert placeholder.object == "🚶 Walking..."
assert placeholder.object == "⏳ Idle"

def test_param_ref(self):
int_input = IntInput(name="IntInput", start=1, end=10, value=5)
placeholder = Placeholder(int_input.param.value)
assert isinstance(placeholder.object, param.Integer)
Loading