Django Apps

In the Introduction , we showed how to use parambokeh in the Jupyter notebook. Then in Bokeh App , we showed how to use parambokeh in a bokeh server application. Here we show how parambokeh can be used in a Django application.

Note that currently, the first (and only) example here does not cover integration between param and django models.

To run the example app yourself, you will first need to install django 2 (e.g. conda install "django=2" ).

sliders app

Based on a standard django2 app template, the sliders app shows how to integrate parambokeh with a django view; there's no interaction between param and django models.

The sliders app is in examples/apps/django2/sliders , which is based on a standard django2 app template. We will cover the following additions/modifications to the django2 app template:

  • sliders/sinewave.py : a parameterized object (representing your pre-existing code)

  • sliders/bk_sliders.py : the parambokeh/bokeh app (based on https://github.com/bokeh/bokeh/blob/master/examples/app/sliders.py )

  • sliders/apps.py : how a django app can import and use bokeh server

  • sliders/views.py and templates/base.html : getting the bokeh app into a django view

You should be able to run this app yourself by changing to the examples/apps/django2 directory and then running: python manage.py runserver ; visit http://localhost:8000/sliders in your browser to try the app.

screenshot of sliders app

To start with, in sliders/sinewave.py we create a parameterized object to serve as a placeholder for your own, existing code:

In [1]:
import numpy as np
import param

class SineWave(param.ParameterizedFunction):
    offset = param.Number(default=0.0, bounds=(-5.0,5.0))
    amplitude = param.Number(default=1.0, bounds=(-5.0,5.0))
    phase = param.Number(default=0.0,bounds=(0.0,2*np.pi))
    frequency = param.Number(default=1.0, bounds=(0.1, 5.1))
    N = param.Integer(default=200, bounds=(0,None))
    
    def __call__(self,**params):
        p = param.ParamOverrides(self,params)
        x = np.linspace(0, 4*np.pi, p.N)
        y = p.amplitude*np.sin(p.frequency*x + p.phase) + p.offset
        return x,y

When called, SineWave will return a tuple of two arrays, representing a sine wave:

In [2]:
SineWave()[0][0:5]
Out[2]:
array([0.        , 0.06314759, 0.12629518, 0.18944277, 0.25259036])

We then take an existing bokeh example app, https://github.com/bokeh/bokeh/blob/master/examples/app/sliders.py , and modify it to use our parameterized SineWave class plus parambokeh to generate widgets automatically (as in previous tutorials):

from bokeh.layouts import row
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure

import parambokeh

from .sinewave import SineWave

def app(doc):
    x,y = SineWave()
    source = ColumnDataSource(data=dict(x=x, y=y))

    import numpy as np
    plot = figure(plot_height=400, plot_width=400,
                  tools="crosshair,pan,reset,save,wheel_zoom",
                  x_range=[0, 4*np.pi], y_range=[-2.5, 2.5])
    plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)

    def update_sinewave(sw,**kw):
        x,y = sw()
        source.data = dict(x=x, y=y)

    parambokeh.Widgets(SineWave, mode='server', doc=doc, callback=update_sinewave)
    doc.add_root(row(plot, width=800))

The first Django-specific aspect of our example is to show how a Django app can import and use bokeh server. This is based on https://github.com/bokeh/bokeh/blob/0.12.16/examples/howto/server_embed/flask_embed.py , which shows how to embed bokeh in a flask app.

from django.apps import AppConfig

from bokeh.server.server import Server

from tornado.ioloop import IOLoop

from . import bk_sliders
from . import bk_config

def bk_worker():
    # Note: num_procs must be 1; see e.g. flask_gunicorn_embed.py for num_procs>1
    server = Server({'/bk_sliders_app': bk_sliders.app},
                    io_loop=IOLoop(),
                    address=bk_config.server['address'],
                    port=bk_config.server['port'],
                    allow_websocket_origin=["localhost:8000"])
    server.start()
    server.io_loop.start()

class Sliders(AppConfig):
    name = 'sliders'
    def ready(self):
        from threading import Thread
        Thread(target=bk_worker).start()

Here, localhost:8000 is the address of the Django app. Note also we have made a simple config file, bk_config.py , for bokeh server settings:

server = dict(
    address = "localhost",
    port = 5006
)

Finally, in sliders/views.py we create a view to display the bokeh sliders app:

from django.shortcuts import render

from bokeh.embed import server_document

from . import bk_config

def sliders(request):
    return render(request, 'base.html', {
        "server_script": server_document('http://%s:%s/bk_sliders_app'%(bk_config.server['address'],
                                                                        bk_config.server['port']))})

The corresponding template is in templates/base.html:

{% block content %}
{{server_script|safe}}  
{% endblock %}