Bokeh-Plots in Flask einbinden ============================== Exemplarisch betten wir Bokeh-Plots in das `Flask `_-Framework ein. #. Erstellen der virtuellen Umgebung: .. code-block:: sh $ mkdir embed $ cd !$ $ pipenv install flask bokeh pandas #. Einbinden von Bokeh-Plots in Flask: #. Dabei wird zunächst in der Datei :file:`flask_embed.py` eine Methode für ein Bokeh-Dokument erstellt: .. code-block:: python from bokeh.layouts import column from bokeh.models import ColumnDataSource, Slider from bokeh.plotting import figure from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature from bokeh.server.server import Server from bokeh.themes import Theme def modify_doc(doc): df = sea_surface_temperature.copy() source = ColumnDataSource(data=df) plot = figure( x_axis_type="datetime", y_range=(0, 25), y_axis_label="Temperature (Celsius)", title="Sea Surface Temperature at 43.18, -70.43", ) plot.line("time", "temperature", source=source) def callback(attr, old, new): if new == 0: data = df else: data = df.rolling("{0}D".format(new)).mean() source.data = ColumnDataSource(data=data).data slider = Slider( start=0, end=30, value=0, step=1, title="Smoothing by N Days" ) slider.on_change("value", callback) doc.add_root(column(slider, plot)) doc.theme = Theme(filename="theme.yaml") #. Mit ``bokeh.sampledata.sea_surface_temperature`` werden Beispieldaten verwendet, die aufgrund ihrer Größe nicht im Bokeh-Paket enthalten sind. Nach der Installation von Bokeh können diese jedoch mit folgendem Befehl heruntergeladen werden: .. code-block:: sh $ pipenv run bokeh sampledata #. Anschließend erstellen wir folgende :file:`theme.yaml`-Datei für die Gestaltung von ``Figure`` und ``Grid``: .. code-block:: yaml attrs: Figure: background_fill_color: "gainsboro" outline_line_color: white toolbar_location: above height: 500 width: 800 Grid: grid_line_dash: [6, 4] grid_line_color: white #. Nun fügen wir in :file:`flask_embed.py` eine Route von der Bokeh-App zum Flask-Server-Konfigurationsobjekt hinzu: .. code-block:: python from bokeh.embed import server_document from flask import render_template ... @app.route("/", methods=["GET"]) def bkapp_page(): script = server_document("http://localhost:5006/bkapp") return render_template("embed.html", script=script, framework="Flask") #. ``script`` und ``framework`` werden anschließend in ein `Jinja2 `_-Template :file:`templates/embed.html` eingebunden, das den Plot anzeigen soll: .. code-block:: html Embedding a Bokeh Server in {{framework}}
This Bokeh app below served by a Bokeh server that has been embedded in the web app framework {{framework}}. For more information see the section Embedding Bokeh Server as a Library in the User’s Guide.
{{script|safe}} #. Nun wird ein Bokeh-Worker in :file:`flask_embed.py` definiert: .. code-block:: python from flask import Flask from tornado.ioloop import IOLoop ... def bk_worker(): server = Server( {"/bkapp": modify_doc}, io_loop=IOLoop(), allow_websocket_origin=["localhost:8000"], ) server.start() server.io_loop.start() #. Schließlich wird noch die Flask-App definiert: .. code-block:: python app = Flask(__name__) ... if __name__ == "__main__": print( "Opening single process Flask app with embedded Bokeh application on http://localhost:8000/" ) print() print( "Multiple connections may block the Bokeh app in this configuration!" ) print('See "flask_gunicorn_embed.py" for one way to run multi-process') app.run(port=8000) #. Falls der Bokeh-Service noch nicht über WebSocket mit Flask kommunizieren kann, sollte dies explizit erlaubt werden mit: .. code-block:: sh $ export BOKEH_ALLOW_WS_ORIGIN=127.0.0.1:5000 #. Schließlich kann Flask gestartet werden mit: .. code-block:: sh $ export FLASK_APP=flask_embed.py $ pipenv run flask run oder, falls mehrere Bokeh-Worker gestartet werden sollen: .. code-block:: sh $ export FLASK_APP=flask_gunicorn_embed.py $ pipenv run flask run .. seealso:: * `User Guide/Embedding Plots and Apps/App Sessions `_ * `GnuCash-Expenses-Vis `_