Templates#

Wenn ihr eine Panel-App oder ein Dashboard als Bokeh-Anwendung bereitstellen wollt, wird diese in einem Standard-Template gerendert, das auf die JS- und CSS-Ressourcen sowie das eigentliche Panel-Objekt verweist. Wenn ihr das Layout der bereitgestellten App anpassen wollt oder mehrere separate Panels in eine App bereitstellen wollt, ermöglicht euch die Template-Komponente von Panel das Anpassen dieses Standard-Templates.

Ein solches Template wird mithilfe von Jinja definiert, wobei ihr das Standard-Template erweitert oder sogar vollständig ersetzen könnt. Im Folgenden seht ihr ein Beispiel:

<!DOCTYPE html>
<html lang="en">
{% block head %}
<head>
    {% block inner_head %}
    <meta charset="utf-8">
    <title>{% block title %}{{ title | e if title else "Panel App" }}{% endblock %}</title>
    {% block preamble %}{% endblock %}
    {% block resources %}
        {% block css_resources %}
        {{ bokeh_css | indent(8) if bokeh_css }}
        {% endblock %}
        {% block js_resources %}
        {{ bokeh_js | indent(8) if bokeh_js }}
        {% endblock %}
    {% endblock %}
    {% block postamble %}{% endblock %}
    {% endblock %}
</head>
{% endblock %}
{% block body %}
<body>
    {% block inner_body %}
    {% block contents %}
        {% for doc in docs %}
        {{ embed(doc) if doc.elementid }}
        {% for root in doc.roots %}
            {{ embed(root) | indent(10) }}
        {% endfor %}
        {% endfor %}
    {% endblock %}
    {{ plot_script | indent(8) }}
    {% endblock %}
</body>
{% endblock %}
</html>

Das Template definiert eine Reihe von benutzerdefinierten Blöcken, die durch extends ergänzt oder überschrieben werden können:

Benutzerdefinierte Templates verwenden#

[1]:
import holoviews as hv
import panel as pn


pn.extension()

Sobald wir Panel geladen haben, können wir mit der Definition eines benutzerdefinierten Templates beginnen. Normalerweise ist es am einfachsten, ein vorhandenes Template durch Überschreiben bestimmter Blöcke anzupassen. Mit {% extends base %} erklären wir, dass wir lediglich eine vorhandene Vorlage erweitern und keine neue definieren.

Im folgenden Fall erweitern wir den postamble-Block des Headers, um eine zusätzliche Ressource zu laden, und den contents-Block, um die Anordnung der Komponenten neu zu definieren:

[2]:
template = """
{% extends base %}

<!-- head -->
{% block postamble %}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
{% endblock %}

<!-- body -->
{% block contents %}
<h1>Custom template for multiple apps</h1>
<p>This is a Panel app with a custom template allowing us to compose multiple Panel objects into a single HTML document.</p>
<br>
<div class="container">
  <div class="row">
    <div class="col-sm">
      {{ embed(roots.A) }}
    </div>
    <div class="col-sm">
      {{ embed(roots.B) }}
    </div>
  </div>
</div>
{% endblock %}
"""

Mithilfe des embed-Makros haben wir zwei verschiedene roots in der Vorlage definiert. Um die Vorlage rendern zu können, müssen wir nun zuerst das pn.Template-Objekt mit dem HTML-Template erstellen und dann die beiden roots-Objekte einbinden.

[3]:
tmpl = pn.Template(template)

tmpl.add_panel("A", hv.Curve([1, 2, 3]))
tmpl.add_panel("B", hv.Curve([1, 2, 3]))

tmpl.servable()
[3]:

Custom template for multiple apps

This is a Panel app with a custom template allowing us to compose multiple Panel objects into a single HTML document.


Im Notebook wird ein Button gerendert, mit dem ihr einen lokalen Server starten könnt um zu überprüfen, ob die Ausgabe euren Erwartungen entspricht.

Wenn das Template größer ist, ist es oft einfacher, es in einer separaten Datei zu erstellen. Ihr könnt den Lademechanismus für Jinja2-Vorlagen verwenden, indem ihr ein Environment zusammen mit einem loader definiert:

[4]:
from jinja2 import Environment, FileSystemLoader


env = Environment(loader=FileSystemLoader("."))
jinja_template = env.get_template("sample_template.html")

tmpl = pn.Template(jinja_template)

tmpl.add_panel("A", hv.Curve([1, 2, 3]))
tmpl.add_panel("B", hv.Curve([1, 2, 3]))

tmpl
[4]:

Custom template for multiple panels

This is a Panel app with a custom template allowing us to compose multiple Panel objects into a single HTML document.