Usage¶
Note
This is a plugin for the SPADE agent platform. Please visit the SPADE’s documentation to know more about this platform.
Plotting figures in html usually involves too much javascript code. To solve this there is a great python library called Bokeh that helps us to plot our own figures with python code and dinamycally thanks to a server embedded with bokeh.
This plugin provides a mixin to include a bokeh server in an agent and to register plots to be then rendered in your jinja2 templates of your agent’s web interface.
To use SPADE Bokeh Server in a project:
import getpass
import spade
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
import spade_bokeh
class MyBokehAgent(spade_bokeh.BokehServerMixin, spade.agent.Agent):
async def controller(self, request):
script = self.bokeh_server.get_plot_script("/my_plot")
return {"script": script}
async def setup(self):
self.web.add_get("/plot", self.controller, "plot.html")
self.web.start(port=10000)
self.bokeh_server.start()
self.bokeh_server.add_plot("/my_plot", self.modify_doc)
def modify_doc(self, 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 = 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))
async def main(jid, passwd):
a = MyBokehAgent(jid, passwd)
await a.start()
await spade.wait_until_finished(a)
if __name__ == "__main__":
jid = input("Agent JID> ")
passwd = getpass.getpass()
spade.run(main(jid, passwd))
In the example below there are 3 different blocks: the agent setup, the web controller and the bokeh plot creation.
Agent setup¶
- To activate the spade_bokeh plugin in your agent you must follow some steps:
First of all your agent needs to inherit from spade_bokeh.BokehServerMixin.
Warning
All the mixins MUST be included before the spade.agent.Agent class, to respect the method resolution order (e.g.
class MyAgent(MyMixin1, MyMixin2, ..., Agent)
).Next you need to start your bokeh_server with the following order:
self.bokeh_server.start()
. This method may accept two arguments: the hostname and the port of the bokeh_server. By default they are “localhost” and 5006.Warning
Two agents can not share a same bokeh_server, so they must use different ports!
Finally, you can add new plots to your server using the
add_plot
function of bokeh_server. It accepts two arguments: the path for the plot in the bokeh server and the callback to build the plot.Note
You can add as many plots as you need.
Bokeh plot creation¶
The method that you give to the add_plot
call is the callback that will create the plot when the url path
is queried. Inside this method you can create your plot following the Bokeh guidelines. As in the example, the
method receives a doc
argument, where the plots of your application will be rendered.
Hint
To learn more about how to create Bokeh plots please visit the Bokeh User Guide
Web controller¶
The final step to render your bokeh plots inside an agent view is to render the plot in a template managed by the SPADE’s web interface system.
Hint
Please, visit the SPADE’s documentation to know more about how to create a SPADE web interface for your agents.
The spade_bokeh plugin provides you a helper function to easily render your plots inside a jinja2 template.
As in the example below, you can use the get_plot_script
method with the path of the plot you want to render
and it will return you the necessary javascript to render the plot (this javascript contains the URL and necessary
code to connect to the bokeh server dinamycally).
Then you only need to render that script in your template as in the example:
<html lang="en">
<head>
<title>Bokeh Example</title>
</head>
<body>
{{ script | safe}}
</body>
</html>
Note
Note that you must safe escape the script with the safe
jinja2 filter to avoid escaping the html tags.