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

Add GridSpec layout [doc-build] #338

Merged
merged 13 commits into from
Mar 28, 2019
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ jobs:
install:
- doit env_create $CHANS_DEV --python=$PYENV_VERSION
- source activate test-environment
- conda install -c conda-forge mesalib
- doit develop_install -o recommended -o tests -o build $CHANS_DEV
- python setup.py develop --no-deps
- doit env_capture
Expand Down
1 change: 1 addition & 0 deletions doc/user_guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Supplementary guides
:maxdepth: 2

Introduction <Introduction>
Components <Components>
Deploy & Export <Deploy_and_Export>
Interact <Interact>
Panes <Panes>
Expand Down
351 changes: 351 additions & 0 deletions examples/user_guide/Components.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,351 @@
{
"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 objects such as Bokeh, Plotly, Vega or HoloViews plots to embed them in a panel.\n",
"* ``Widget`` objects provide controls which can trigger events either in Python or Javascript.\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 [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": [
"## 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 (matplotlib, bokeh, vega/altair, holoviews, and plotly), images (pngs, svgs, gifs, jpegs), and various Markup languages including Markdown, HTML and 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 which will convert objects into a Pane or Panel layout. This utility is also used internally when passing external objects to a Panel layout such as a Row or Column. The utility resolves the appropriate representation for an object using by checking all pane objects and then taking ranking them by priority. When passing a string for instance there are many representations, however the PNG pane takes precedence if the string is a valid URL or local file path."
]
},
{
"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=300)\n",
"\n",
"png"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To see the type of the pane use the ``pprint`` method:"
]
},
{
"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 it existing views (both in the notebook and on server instances) of this object 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 which can 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 share a ``value`` parameter, layout parameters and other parameters specific to each widget. In the notebook we can display it 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 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": [
"For more details about linking widgets to other objects either in Python or in Javascript see the [Links user guide](./Links.ipynb).\n",
"\n",
"## Panel layouts\n",
"\n",
"The third type of component is are the Panel layout objects which allow arranging widget and pane objects into everything from a simple app to a complex dashboard. There are four main types of Layout containers:\n",
"\n",
"* **``Row``**: A ``Row`` arranges a list of components horizontally.\n",
"* **``Column``**: A ``Column`` arranges a list of components vertically.\n",
"* **``Tabs``**: ``Tabs`` lay out components in a list of selectable tabs. \n",
"* **``GridSpec``**: A ``GridSpec`` lays out components on a grid.\n",
"\n",
"In addition to these layout containers ``Spacer`` components allow controlling the spacing between components.\n",
"\n",
"### Row & Column\n",
"\n",
"The ``Row``, ``Column`` and ``Tabs`` layouts behave very similarly, they 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 using ``append``, ``extend``, ``clear``, ``insert``, ``pop``, ``remove`` and ``__setitem__``."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"column = pn.Column()\n",
"\n",
"# Add an item\n",
"column.append('# A title')\n",
"\n",
"# Add multiple items\n",
"column.extend([pn.widgets.FloatSlider(), pn.widgets.TextInput()])\n",
"\n",
"# Replace the third item\n",
"column[2] = pn.widgets.Button(name='Click here')\n",
"\n",
"column"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Tabs\n",
"\n",
"The ``Tabs`` object shares all the same methods however, when adding or replacing items it is also possible to pass a tuple providing a custom title:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from bokeh.plotting import figure\n",
"\n",
"tabs = pn.Tabs()\n",
"\n",
"p1 = figure(width=300, height=300)\n",
"p1.line([1, 2, 3], [1, 2, 3])\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",
"# Replace a tab\n",
"tabs[0] = ('Line Plot', p1)\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, which expands when assigned to. This makes it a very powerful means of declaring a dashboard layout with a fixed size or with responsive sizing, i.e. one that will rescale with the browser window.\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 an array the indexing 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 layout types any object can be assigned to a grid, however responsive sizing modes will only work well if the object being assigned supports interactive rescaling.\n",
"\n",
"**Note**: A GridSpec modifies the layout parameters of the objects that are assigned to the grid to support both fixed and responsive sizing modes.\n",
"\n",
"To demonstrate the abilities let us declare a grid with a wide range of different objects, e.g. HTML panes, bokeh figures, HoloViews objects, images and widgets:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"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.pane.HTML(\"A\", background='#FF0000')\n",
"gspec[1:3, 0] = pn.pane.HTML(\"B\", background='#00FF00')\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(pn.widgets.FloatSlider(), pn.widgets.ColorPicker(), pn.widgets.Toggle(name='Toggle me'))\n",
"\n",
"gspec"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"When assigning to a grid cell that is already occupied ``GridSpec`` will generate a helpful warning which highlights which objects are overlapping an where:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"gspec[0:3, :2] = 'Some text'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In addition to assignment we can also slice and index the ``GridSpec`` to access an individual objects or a subregion of the grid, e.g. here we will access the last row and the last two columns:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"gspec[-1, 1:]"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
2 changes: 1 addition & 1 deletion panel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .config import config, panel_extension as extension # noqa
from .interact import interact # noqa
from .io import state # noqa
from .layout import Row, Column, Tabs, Spacer # noqa
from .layout import Row, Column, Tabs, Spacer, GridSpec # noqa
from .pane import panel, Pane # noqa
from .param import Param # noqa

Expand Down
Loading