{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Panel provides a wide range of components for easily composing panels, apps, and dashboards both in the notebook and as standalone apps. The components can be broken down into three broad classes of objects:\n", "\n", "* ``Pane`` objects allow wrapping external viewable items like Bokeh, Plotly, Vega, or HoloViews plots, so they can be embedded in a panel.\n", "* ``Widget`` objects provide controls that can trigger Python or JavaScript events.\n", "* ``Panel`` layout objects allow combining plots into a ``Row``, ``Column``, ``Tabs`` or a ``Grid``.\n", "\n", "All objects share an API that makes it easy to [customize their layout behavior and visual appearance](./Customization.ipynb), [link](./Links.ipynb) and [display and export](./Deploy_and_Export.ipynb) them. To display any panel objects in a notebook environment ensure you load the extension first:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import panel as pn\n", "pn.extension()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that to use certain components such as Vega, LaTeX, and Plotly plots in a notebook, the models must be loaded using the extension. E.g.:\n", "\n", " pn.extension('vega', 'katex')\n", " \n", "will ensure that the Vega and LaTeX JS dependencies are loaded. Once the extension is loaded, Panel objects will display themselves in the notebook, outside the notebook objects can be displayed in a server using the show method or run from the commandline by appending ``.serveable()`` to the objects to be displayed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Parameterized Components\n", "\n", "All components in Panel are built on the [Param](https://param.holoviz.org/) library. Each component declares a set of parameters that control the behavior and output of the component. See the [Param documentation](https://param.holoviz.org/) for more details on how to use Param. The basic idea however is that the parameter values can be controlled both at the class-level:\n", "\n", "```python\n", "pn.widgets.Select.sizing_mode = 'stretch_both'\n", "```\n", "\n", "or on each instance:\n", "\n", "```python\n", "pn.widgets.Select(sizing_mode='stretch_both')\n", "```\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Panes\n", "\n", "``Pane`` objects makes it possible to display and arrange a wide range of plots and other media on a page, including plots (e.g. Matplotlib, Bokeh, Vega/Altair, HoloViews, Plotly), images (e.g. PNGs, SVGs, GIFs, JPEGs), and various markup languages (e.g. Markdown, HTML, LaTeX).\n", "\n", "There are two main ways to construct panes. The first is to explicitly construct a pane:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pn.pane.Markdown('''\n", "# H1\n", "## H2\n", "### H3\n", "''')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Panel also provides a convenient helper function that will convert objects into a Pane or Panel. This utility is also used internally when passing external objects to a Row, Column, or other Panel. The utility resolves the appropriate representation for an object using by checking all Pane object types available and then ranking them by priority. When passing a string (for instance) there are many representations, but the PNG pane takes precedence if the string is a valid URL or local file path ending in \".png\"." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "png = pn.panel('https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png', width=500)\n", "\n", "png" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To see the type of the pane use the ``pprint`` method, which works with any Widget, Pane, or (perhaps most usefully) Panel:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "png.pprint()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All Panel objects store the object they are wrapping on the ``object`` parameter. By setting that parameter, existing views of this object (whether in other notebook cells or on a server instance) will update:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "png.object = 'https://upload.wikimedia.org/wikipedia/commons/3/39/PNG_demo_heatmap_Banana.png'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition to the ``object`` parameter, each pane type may have additional parameters that modify how the ``object`` is rendered." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Widgets\n", "\n", "``Widget`` components, like all objects in Panel, sync their parameter state between all views of the object. Widget objects have a ``value`` parameter, layout parameters, and other parameters specific to each widget. In the notebook we can display widgets just like other Panel objects:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "widget = pn.widgets.TextInput(name='A widget', value='A string')\n", "widget" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this way the widget values can easily be accessed and set:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "widget.value = '3'\n", "widget.width = 100" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As well as linked to other objects:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "string = pn.pane.Str()\n", "\n", "widget.jslink(string, value='object')\n", "\n", "pn.Row(widget, string)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "See the [Links user guide](./Links.ipynb) for more details about linking widgets to other objects, using either Python or JavaScript.\n", "\n", "## Panels\n", "\n", "Panels allow arranging widget and pane objects into fixed-size or responsively resizing layouts, building simple apps or complex dashboards. The whole Panel library is designed to make it easy to create such objects, which is why it takes its name from them.\n", "\n", "There are four main types of ``Panel``s:\n", "\n", "* **``Row``**: A ``Row`` arranges a list of components horizontally.\n", "* **``Column``**: A ``Column`` arranges a list of components vertically.\n", "* **``Tabs``**: A ``Tabs`` object lays out a list of components as selectable tabs. \n", "* **``GridSpec``**: A ``GridSpec`` lays out components on a grid.\n", "\n", "``Spacer`` components are also provided, to control spacing between other components.\n", "\n", "### Row & Column\n", "\n", "The ``Row``, ``Column``, and ``Tabs`` Panels all behave very similarly. All of them are list-like, which means they have many of the same methods as a simple Python list, making it easy to add, replace, and remove components interactively using ``append``, ``extend``, ``clear``, ``insert``, ``pop``, ``remove`` and ``__setitem__``. These methods make it possible to interactively configure and modify an arrangement of plots, making them an extremely powerful tool for building apps or dashboards.\n", "\n", "``Row`` and ``Column`` can be initialized as empty or with the objects to be displayed as arguments. If each of the object(s) provided is not already a ``Widget``, ``Pane``, or ``Panel``, the panel will internaly call the ``pn.panel`` function to convert it to a displayable representation (typically a Pane).\n", "\n", "To start with, we will declare a ``Column`` and populate it with a title and a widget:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "column = pn.Column('# A title', pn.widgets.FloatSlider())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next we add another bit of markdown:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "column.append('* Item 1\\n* Item 2')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we add a few more widgets:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "column.extend([pn.widgets.TextInput(), pn.widgets.Checkbox(name='Tick this!')])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and finally we change our mind and replace the ``Checkbox`` with a button:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "column[3] = pn.widgets.Button(name='Click here')\n", "\n", "column" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ability to add, remove, and replace items opens up the possibility of building rich and responsive GUIs with the ease of manipulating a list." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tabs\n", "\n", "The ``Tabs`` layout allows displaying multiple objects as individually toggleable tabs. Just like ``Column`` and ``Row``, the tabs object can be used like a list. However, when adding or replacing items, it is also possible to pass a tuple providing a custom title for the tab:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from bokeh.plotting import figure\n", "\n", "p1 = figure(width=300, height=300)\n", "p1.line([1, 2, 3], [1, 2, 3])\n", "\n", "tabs = pn.Tabs(p1)\n", "\n", "# Add a tab\n", "tabs.append(('Slider', pn.widgets.FloatSlider()))\n", "\n", "# Add multiple tabs\n", "tabs.extend([\n", " ('Text', pn.widgets.TextInput()),\n", " ('Color', pn.widgets.ColorPicker())\n", "])\n", "\n", "tabs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### GridSpec\n", "\n", "A ``GridSpec`` is quite different from the other ``Panel`` layout types in that it isn't list-like. Instead it behaves more like a 2D array that automatically expands when assigned to. This property makes it a very powerful means of declaring a dashboard layout with either a fixed size or with responsive sizing, i.e. one that will rescale with the browser window. **Note**: A GridSpec modifies the layout parameters of the objects that are assigned to the grid, so that it can support both fixed and responsive sizing modes.\n", "\n", "To create a ``GridSpec`` we first declare it, either with a responsive ``sizing_mode`` or a fixed width and height. Once declared we can use 2D assignment to specify the index or span on indices the object in the grid should occupy. Just like a Python array, the indexing is zero-based and specifies the rows first and the columns second, i.e. ``gspec[0, 1]`` would assign an object to the first row and second column.\n", "\n", "Like the other Panel types, any object can be assigned to a grid location. However, responsive sizing modes will only work well if each object being assigned supports interactive rescaling. To demonstrate the abilities, let us declare a grid with a wide range of different objects, including Spacers, Bokeh figures, HoloViews objects, images, and widgets:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import holoviews as hv\n", "import holoviews.plotting.bokeh\n", "\n", "from bokeh.plotting import figure\n", "\n", "fig = figure()\n", "fig.scatter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 2, 1, 0, -1, -2, -3])\n", "\n", "gspec = pn.GridSpec(sizing_mode='stretch_both', max_height=800)\n", "\n", "gspec[0, :3] = pn.Spacer(background='#FF0000')\n", "gspec[1:3, 0] = pn.Spacer(background='#0000FF')\n", "gspec[1:3, 1:3] = fig\n", "gspec[3:5, 0] = hv.Curve([1, 2, 3])\n", "gspec[3:5, 1] = 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png'\n", "gspec[4:5, 2] = pn.Column(\n", " pn.widgets.FloatSlider(),\n", " pn.widgets.ColorPicker(),\n", " pn.widgets.Toggle(name='Toggle Me!'))\n", "\n", "gspec" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When assigning to a grid cell that is already occupied, the ``GridSpec`` will generate a helpful warning that highlights which objects are overlapping and where. Even so, it will still replace any overlapping items by default. To control this behavior to either error or replace the objects silently, set the ``GridSpec`` mode to 'error' or 'override'." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "gspec[0:3, :2] = 'Some text'\n", "```\n", "\n", "```bash\n", "---------------------------------------------------------------------------\n", "WARNING:param.GridSpec01316: Specified region overlaps with the following existing object(s) in the grid:\n", " (0, 0): Spacer(background='#FF0000', sizing_mode='stretch_both')\n", " (1, 0): Spacer(background='#0000FF', sizing_mode='stretch_both')\n", " (1, 1): Bokeh(Figure, sizing_mode='stretch_both')\n", "\n", "The following shows a view of the grid (empty: 0, occupied: 1, overlapping: 2):\n", "\n", "[[2 2 1]\n", " [2 2 1]\n", " [2 2 1]\n", " [1 1 0]\n", " [1 1 1]]\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition to assignment, we can also slice and index the ``GridSpec`` to access an individual object or a subregion of the grid, returning another GridSpec. Here we will access the last row and everything except the first column:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "gspec[-1, 1:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more detail about `GridSpec` Panels, see the [reference gallery](../reference/layouts/GridSpec.ipynb)." ] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 2 }