Skip to content

Instantly share code, notes, and snippets.

@tmmsartor
Last active March 27, 2017 23:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tmmsartor/057ffb990f6f7fdb5221b789029b42ce to your computer and use it in GitHub Desktop.
Save tmmsartor/057ffb990f6f7fdb5221b789029b42ce to your computer and use it in GitHub Desktop.
Bokeh example about runtime events
#! /usr/bin/python3.6
# author: tmmsartor@gmail.com
import numpy as np
import time
from functools import partial
from bokeh.plotting import figure, curdoc
from bokeh.layouts import column, row
from bokeh.models.widgets import Button
from bokeh.models.glyphs import Line
from bokeh.models import ColumnDataSource
from bokeh.client import push_session
from threading import Thread
from tornado import gen
# server
from multiprocessing import Process
from bokeh.application import Application
from bokeh.server.server import Server
def bokeh_server():
server = Server({"/": Application()})
print("Start Server")
server.run_until_shutdown()
p = Process(target=bokeh_server)
p.start()
class StatefulPlot:
def __init__(self):
self.doc = curdoc()
self.session = push_session(self.doc)
# object connected
self.source1 = ColumnDataSource(
dict(time=[], line1=[], line2=[])
)
self.x1 = 0
self.x2 = 0
x = np.linspace(0, 200, 100)
x1 = np.linspace(-2*np.pi, 0, 100)
y = np.cos(x1)
self.tools = "xpan,xwheel_zoom,xbox_zoom,reset"
self.h = 300
self.w = 700
self.source1 = ColumnDataSource(dict(time=[], line1=[]))
self.source2 = ColumnDataSource(dict(time=x1, line2=y))
p1 = figure(plot_height=self.h, plot_width=self.w, tools=self.tools)
p1.line(x='time', y='line1', alpha=0.2, line_width=3,
color='navy', source=self.source1)
p1.line(x, y, alpha=0.2, line_width=3, color='orange')
p1.toolbar.logo = None
self.p2 = figure(plot_height=self.h, plot_width=self.w,
tools=self.tools)
self.p2.line(x, np.zeros(x.shape), alpha=0.2, color='navy')
self.p2.line(x='time', y='line2', alpha=0.8, line_width=2,
color='orange', source=self.source2)
p1.x_range.follow = "end"
p1.x_range.follow_interval = 100
self.p2.x_range.follow = "end"
self.p2.x_range.follow_interval = 100
button = Button(label='pause/play')
button.on_click(self.start_stop)
rewind = Button(label='rewind')
rewind.on_click(self.rewind)
add_fig = Button(label='add/del new fig')
add_fig.on_click(self.add_fig_f)
add_line = Button(label='add_line')
add_line.on_click(self.add_line_f)
self.thread = None
self.start = 0
self.rewind = 0
self.x = 0
self.new_fig = 0
self.buttons = row(add_line, button, rewind, add_fig)
self.plots = column(p1, self.p2)
self.doc.add_root(self.buttons)
self.doc.add_root(self.plots)
def start_stop(self):
if not self.start:
print("starting")
self.start = 1
self.doc.add_next_tick_callback(self._do_task)
else:
print("stopping")
self.start = 0
return
def add_fig_f(self):
self.doc.add_next_tick_callback(self._add_fig)
def add_line_f(self):
self.doc.add_next_tick_callback(self._add_line)
def rm_fig_f(self):
self.doc.add_next_tick_callback(self._rm_fig)
def rewind(self):
if not self.rewind:
print("rewind start")
self.rewind = 1
self.doc.add_next_tick_callback(self._do_rewind)
else:
print("rewind stopping")
self.rewind = 0
return
@gen.coroutine
def _add_line(self):
print("Adding line")
x = np.linspace(0, 100, 100)
self.source3 = ColumnDataSource(dict(time=x, line=np.sin(x)))
self.p2.add_glyph(self.source3, Line())
@gen.coroutine
def _add_fig(self):
if not self.new_fig:
f = figure(plot_height=self.h, plot_width=self.w,
tools=self.tools)
x = np.linspace(0, 100, 100)
f.line(x, np.zeros(x.shape), alpha=0.2, line_width=3, color='navy')
self.plots.children.append(f)
self.new_fig = 1
else:
self.new_fig = 0
self.plots.children.pop(2)
@gen.coroutine
def _do_rewind(self):
self.x -= 2
start = time.time()
self.source2.data.update({
"time": self.source2.data["time"][:-100],
"line2": self.source2.data["line2"][:-100]})
print(f"elapsed {time.time() - start}")
yield gen.sleep(0.1)
if self.rewind:
self.doc.add_next_tick_callback(self._do_rewind)
@gen.coroutine
def _do_task(self):
x = np.linspace(self.x*np.pi, (self.x+2)*np.pi, 100)
self.x += 2
new_data = dict(
time=x,
line2=np.cos(x)
)
self.source2.stream(new_data)
yield gen.sleep(0.1)
# Add callback again
if self.start:
self.doc.add_next_tick_callback(self._do_task)
fig = StatefulPlot()
# module wise work
@gen.coroutine
def plot_this(i):
x = np.linspace(i*0.5, (i+1)*0.5, 10)
new_data = dict(
time=x,
line1=np.sin(x))
fig.source1.stream(new_data)
def my_loop():
t = 0
while 1:
time.sleep(0.2)
# Add callback again
fig.doc.add_next_tick_callback(partial(plot_this, t))
t += 1
# show session
fig.session.show()
# run forever
thread = Thread(target=fig.session.loop_until_closed)
thread.start()
# do stuff
my_loop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment