{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import holoviews as hv\n", "import panel as pn\n", "from bokeh.themes.theme import Theme\n", "\n", "hv.extension(\"bokeh\")\n", "hv.renderer('bokeh').theme = Theme(json={}) # Reset Theme\n", "pn.extension()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Material Template for Panel\n", "\n", "[Panel](https://panel.holoviz.org/index.html) is a framework for creating awesome analytics apps in Python.\n", "\n", "**In Panel you are able to customize the layout and style using a [Custom Template](https://panel.holoviz.org/user_guide/Templates.html).**\n", "\n", "One popular design specification is [Material Design](https://material.io/design/). The following frameworks aims to implement the Material Design specification\n", "\n", "- [Material Design Lite](https://getmdl.io/) (`mdl`) (simple components)\n", "- [Material Design Components for the Web](https://material.io/develop/web/) (`mdc`) (advanced components)\n", "- [Material Web Components](https://github.com/material-components/material-components-web-components) (`mwc`) (web components on top of mdc)\n", "\n", "The `mwc` components should be the easiest to integrate with Panel, so we will base the following on `mwc` with a fall back to `mdc` when needed.\n", "\n", "\"Girl \n", "\"Girl " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Material Introduction\n", "\n", "### Fonts\n", "\n", "Material Design uses the **Roboto** Font and **Material Icons**. Lets import them." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fonts_html = \"\"\"\n", "\n", "\n", "\"\"\"\n", "pn.pane.HTML(fonts_html, height=0, width=0, sizing_mode=\"fixed\", margin=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### MWC Components\n", "\n", "We start by importing the **components**. \n", "\n", "We will be using the `mwc-button`, `mwc-drawer`, `mwc-icon-button`, `mwc-slider`, `mwc-top-app-bar-fixed` in our examples." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "modules_html = \"\"\"\n", "\n", "\n", "\n", "\n", "\n", "\n", "\"\"\"\n", "pn.pane.HTML(modules_html, height=0, width=0, sizing_mode=\"fixed\", margin=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then the app **layout**, **contents** and some code to enable **toggling** of the `mwcdrawer` as well as displaying the app in a note book cell." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "example_html = \"\"\"\n", "
\n", "\n", " Material App\n", "
\n", " \n", " \n", " \n", "
\n", "
\n", " \n", " \n", "
Panel App using Custom Template
\n", " \n", " \n", " \n", "
\n", "
\n", "

Main Content!

\n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "\n", "
\n", "\"\"\"\n", "pn.pane.HTML(example_html, sizing_mode=\"stretch_width\", height=300)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## MDC Grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `mwc` framework does not contain a **grid system**. But the `mdc` framework does.\n", "\n", "It uses a a system of columns to create responsiveness and layout across mobile, tablet and desktop.\n", "\n", "- Desktop: 12 Columns\n", "- Tables: 8 Columns\n", "- Mobile: 4 Columns" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "grid_import_html = \"\"\"\n", "\n", "\"\"\"\n", "pn.pane.HTML(grid_import_html, height=0, width=0, sizing_mode=\"fixed\", margin=0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "grid_example_html = \"\"\"\n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "\n", "\"\"\"\n", "pn.pane.Markdown(grid_example_html, sizing_mode=\"stretch_width\", height=500)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Try **resizing the window** from large to small and back and see how the grid responds." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Material Template for Panel with grid layout\n", "\n", "Using the above we are now able to construct an example Material Template for Panel with a grid layout." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template = \"\"\"\n", "{% extends base %}\n", "\n", "\n", "{% block postamble %}\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "{% endblock %}\n", "\n", "\n", "{% block contents %}\n", "\n", " {{ app_title }}\n", " subtitle\n", "
\n", " \n", " \n", " \n", "
\n", "
\n", " \n", " \n", "
{{ app_title }}
\n", " \n", " \n", "
\n", "
\n", " {{ embed(roots.Styles) }}\n", "

Content!

\n", "

This is a Panel app using a custom template based on Material Design. It works both in the Notebook and as a web app.


\n", " \n", " \n", " \n", "
\n", "
\n", "
{{ embed(roots.G) }}
\n", "
{{ embed(roots.A) }}
\n", "
{{ embed(roots.B) }}
\n", "
{{ embed(roots.C) }}
\n", "
{{ embed(roots.D) }}
\n", "
{{ embed(roots.E) }}
\n", "
{{ embed(roots.F) }}
\n", "
\n", "
\n", "\n", "\n", "{% endblock %}\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's use the template" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The style_panel supports incrementally adding css in cells below for educational reasons\n", "style_panel = pn.pane.HTML(\"\", height=0, width=0, sizing_mode=\"fixed\", margin=0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tmpl = pn.Template(template=template)\n", "\n", "tmpl.add_variable('app_title', 'Panel App using Custom Template')\n", "material_green = \"rgb(0, 128, 0)\"\n", "material_purple= \"#9C27B0\"\n", "color = material_green\n", "line_width=4\n", "\n", "tmpl.add_panel('A', hv.Curve([1, 2, 3]).opts(height=200,color=color, line_width=line_width, responsive=True))\n", "tmpl.add_panel('B', hv.Curve([1, 2, 3]).opts(height=200,color=color, line_width=line_width, responsive=True))\n", "tmpl.add_panel('C', hv.Curve([1, 2, 3]).opts(height=200,color=color, line_width=line_width, responsive=True))\n", "tmpl.add_panel('D', hv.Curve([1, 2, 3]).opts(height=200,color=color, line_width=line_width, responsive=True))\n", "tmpl.add_panel('E', hv.Curve([1, 2, 3]).opts(height=200,color=color, line_width=line_width, responsive=True))\n", "tmpl.add_panel('F', hv.Curve([1, 2, 3]).opts(height=200,color=color, line_width=line_width, responsive=True))\n", "tmpl.add_panel('G', hv.Curve([1, 2, 3]).opts(height=200,color=color, line_width=line_width, responsive=True))\n", "tmpl.add_panel('Styles', style_panel)\n", "tmpl" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lets take a look in the server" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def show_in_server(event):\n", " tmpl.show()\n", "show_in_server_button = pn.widgets.Button(name=\"Show in server\")\n", "show_in_server_button.on_click(show_in_server)\n", "show_in_server_button" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lets update the theme in the notebook." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dark_theme_style = \"\"\"\n", "