{ "cells": [ { "cell_type": "markdown", "source": [ "When deploying a Panel app or dashboard as a Bokeh application, it is rendered into a default template that serves the JS and CSS resources as well as the actual Panel object being shown. However, it is often desirable to customize the layout of the deployed app, or even to embed multiple separate panels into an app. The ``Template`` component in Panel allows customizing this default template, including the ability to rendering multiple components in a single document easily.\n", "\n", "## What is a template?\n", "\n", "A template is defined using the [Jinja2](http://jinja.pocoo.org/docs/) templating language, which makes it straightforward to extend the default template in various ways or even replace it entirely. However most users can avoid modifying the jinja2 template directly by using one of the default templates shipped with Panel itself." ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "import panel as pn\n", "import numpy as np\n", "import holoviews as hv\n", "\n", "pn.extension(sizing_mode='stretch_width')" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Using default templates\n", "\n", "For a large variety of use cases we do not need complete control over the exact layout of each individual component on the page, instead we just want to achieve a more polished look and feel. For these cases Panel ships with a number of default templates, which are defined by declaring four main content areas on the page, which can be populated as desired:\n", "\n", "* **`header`**: The header area of the HTML page\n", "* **`sidebar`**: A collapsible sidebar\n", "* **`main`**: The main area of the application\n", "* **`modal`**: A modal, i.e. a dialog box/popup window\n", "\n", "These four areas behave very similarly to other Panel layout components and have list-like semantics. This means we can easily append new components into these areas. Unlike other layout components however, the contents of the areas is fixed once rendered. If you need a dynamic layout you should therefore insert a regular Panel layout component (e.g. a `Column` or `Row`) and modify it in place once added to one of the content areas. \n", "\n", "" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "### Supported templates\n", "\n", "Panel ships with a number of these default themes built on different CSS frameworks:\n", " \n", "* **[``MaterialTemplate``](../reference/templates/Material.ipynb)**: Built on [Material Components for the web](https://material.io/develop/web/)\n", "* **[``BootstrapTemplate``](../reference/templates/Bootstrap.ipynb)**: Built on [Bootstrap v4](https://getbootstrap.com/docs/4.0/getting-started/introduction/)\n", "* **[``VanillaTemplate``](../reference/templates/Vanilla.ipynb)**: Built using pure CSS without relying on any specific framework\n", "* **[``FastListTemplate``](../reference/templates/FastListTemplate.ipynb)**: Built on the [Fast UI](https://fast.design/) framework using a list-like API\n", "* **[``FastGridTemplate``](../reference/templates/FastGridTemplate.ipynb)**: Built on the [Fast UI](https://fast.design/) framework using grid-like API\n", "* **[``GoldenTemplate``](../reference/templates/GoldenLayout.ipynb)**: Built on the [Golden Layout](https://golden-layout.com/) framework" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "### Using templates\n", "\n", "There are two ways of building an application using these templates either we explicitly construct the template or we change the global template.\n", "\n", "#### Explicit constructor\n", "\n", "The explicit way to use templates is to instantiate them directly and adding components to the different parts of the template directly. Let us construct a very simple app containing two plots in the `main` area and two widgets in the sidebar based on the `BootstrapTemplate` class:" ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "bootstrap = pn.template.BootstrapTemplate(title='Bootstrap Template')\n", "\n", "xs = np.linspace(0, np.pi)\n", "freq = pn.widgets.FloatSlider(name=\"Frequency\", start=0, end=10, value=2)\n", "phase = pn.widgets.FloatSlider(name=\"Phase\", start=0, end=np.pi)\n", "\n", "@pn.depends(freq=freq, phase=phase)\n", "def sine(freq, phase):\n", " return hv.Curve((xs, np.sin(xs*freq+phase))).opts(\n", " responsive=True, min_height=400)\n", "\n", "@pn.depends(freq=freq, phase=phase)\n", "def cosine(freq, phase):\n", " return hv.Curve((xs, np.cos(xs*freq+phase))).opts(\n", " responsive=True, min_height=400)\n", "\n", "bootstrap.sidebar.append(freq)\n", "bootstrap.sidebar.append(phase)\n", "\n", "bootstrap.main.append(\n", " pn.Row(\n", " pn.Card(hv.DynamicMap(sine), title='Sine'),\n", " pn.Card(hv.DynamicMap(cosine), title='Cosine')\n", " )\n", ")" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "
This is a Panel app with a custom template allowing us to compose multiple Panel objects into a single HTML document.
\n", "This is a Panel app with a custom template allowing us to compose multiple Panel objects into a single HTML document.
\n", "