Skip to content

Commit

Permalink
Add GridBox layout [doc-build] (#608)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored Aug 21, 2019
1 parent 8a879b9 commit 7484636
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 1 deletion.
117 changes: 117 additions & 0 deletions examples/reference/layouts/GridBox.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import panel as pn\n",
"pn.extension()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The ``GridBox`` is a list-like layout (unlike ``GridSpec``) that wraps objects into a grid according to the specified ``nrows`` and ``ncols`` paraameters. It has a list-like API with methods to ``append``, ``extend``, ``clear``, ``insert``, ``pop``, ``remove`` and ``__setitem__``, which make it possible to interactively update and modify the layout.\n",
"\n",
"#### Parameters:\n",
"\n",
"For layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\n",
"\n",
"\n",
"* **``ncols``** (int): Number of columns after which to wrap\n",
"* **``nrows``** (int): Number of rows after which to wrap\n",
"* **``objects``** (list): The list of objects to display in the WidgetBox. Should not generally be modified directly except when replaced in its entirety.\n",
"\n",
"___"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A ``GridBox`` layout can either be instantiated as empty and populated after the fact or using a list of objects provided as positional arguments. If the objects are not already panel components they will each be converted to one using the ``pn.panel`` conversion method. Depending on the number of items and the specified ``ncols``/``nrows`` the layout will reflow the content:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import random\n",
"\n",
"rcolor = lambda: \"#%06x\" % random.randint(0, 0xFFFFFF)\n",
"\n",
"box = pn.GridBox(*[pn.pane.HTML(background=rcolor(), width=50, height=50) for i in range(24)], ncols=6)\n",
"box"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In general it is preferred to modify layouts only through the provided methods and avoid modifying the ``objects`` parameter directly. The one exception is when replacing the list of ``objects`` entirely, otherwise it is recommended to use the methods on the ``WidgetBox`` itself to ensure that the rendered views of the ``GridBox`` are rerendered in response to the change. As a simple example we might add an additional widget to the ``box`` using the append method:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"color = pn.pane.HTML(background=rcolor(), width=50, height=50)\n",
"box[5] = color"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In addition to modifying the ``GridBox`` through methods and ``__setitem__`` syntax we can also dynamically reflow the contents by changing the ``ncols`` or ``nrows`` parameters:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"box.ncols = 4"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To see the effect in a statically rendered page, we will display the box a second time:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"box"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In general a ``GridBox`` does not have to be given a ``width``, ``height`` or ``sizing_mode``, allowing it to adapt to the size of its contents."
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
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, WidgetBox, Tabs, Spacer, GridSpec # noqa
from .layout import Row, Column, WidgetBox, Tabs, Spacer, GridSpec, GridBox # noqa
from .pane import panel, Pane # noqa
from .param import Param # noqa
from .template import Template # noqa
Expand Down
58 changes: 58 additions & 0 deletions panel/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import param
import numpy as np

from bokeh.layouts import grid as _bk_grid
from bokeh.models import (Column as BkColumn, Row as BkRow,
Spacer as BkSpacer, GridBox as BkGridBox,
Box as BkBox, Markup as BkMarkup)
Expand Down Expand Up @@ -353,6 +354,63 @@ class Column(ListPanel):
_bokeh_model = BkColumn



class GridBox(ListPanel):
"""
List-like Grid which wraps depending on the specified number of
rows or columns.
"""

nrows = param.Integer(default=None, bounds=(0, None), doc="""
Number of rows to reflow the layout into.""")

ncols = param.Integer(default=None, bounds=(0, None), doc="""
Number of columns to reflow the layout into.""")

_bokeh_model = BkGridBox

def _get_model(self, doc, root=None, parent=None, comm=None):
model = self._bokeh_model()
if root is None:
root = model
objects = self._get_objects(model, [], doc, root, comm)
grid = _bk_grid(objects, nrows=self.nrows, ncols=self.ncols,
sizing_mode=self.sizing_mode)
model.children = grid.children
props = {k: v for k, v in self._init_properties().items()
if k not in ('nrows', 'ncols')}
model.update(**self._process_param_change(props))
self._models[root.ref['id']] = (model, parent)
self._link_props(model, self._linked_props, doc, root, comm)
return model

def _update_model(self, events, msg, root, model, doc, comm=None):
if self._rename['objects'] in msg or 'ncols' in msg or 'nrows' in msg:
if 'objects' in events:
old = events['objects'].old
else:
old = self.objects
objects = self._get_objects(model, old, doc, root, comm)
grid = _bk_grid(objects, nrows=self.nrows, ncols=self.ncols,
sizing_mode=self.sizing_mode)
children = grid.children
msg[self._rename['objects']] = children

held = doc._hold
if comm is None and not held:
doc.hold()
model.update(**{k: v for k, v in msg.items() if k not in ('nrows', 'ncols')})

from .io import state
ref = root.ref['id']
if ref in state._views:
state._views[ref][0]._preprocess(root)

if comm is None and not held:
doc.unhold()



class WidgetBox(ListPanel):
"""
Vertical layout of widgets.
Expand Down

0 comments on commit 7484636

Please sign in to comment.