first try on dynamic adding/removing plots

This commit is contained in:
2021-05-26 11:58:31 +02:00
parent b81f855ac9
commit 2815956d42
3 changed files with 128 additions and 38 deletions

63
actor.py Normal file
View File

@ -0,0 +1,63 @@
from cacher import cacher
from plots import Plot0D, Plot1D, Plot2D
from sources import Camera, Source
def update_all(plt, cache):
plt.set(*cache.xy)
def update_latest(plt, cache):
plt.set(cache.latest)
def decide_src_plt_cache(pvname):
pvname = pvname.upper()
if pvname.endswith(":FPICTURE"):
print("Camera", pvname)
src = Camera(pvname)
plt = Plot2D
cache_size = 1
update = update_latest
if not src.is_connected:
raise RuntimeError(f"{pvname} is not connected")
else:
print("Source", pvname)
src = Source(pvname)
if not src.is_connected:
raise RuntimeError(f"{pvname} is not connected")
print(src.nelm)
if src.nelm == 0:
raise RuntimeError(f"{src}: {src.value}")
if src.nelm == 1:
print("Scalar")
plt = Plot0D
cache_size = 100
update = update_all
else:
print("Curve")
plt = Plot1D
cache_size = 1
update = update_latest
plt = plt()
plt.name = plt.fig.name = pvname #TODO this needs to be done in Plot*
cache = cacher.add_source(src, size=cache_size)
return src, plt, cache, update
class Actor:
def __init__(self, pvname, cache_size=100):
self.src, self.plt, self.cache, self._update = decide_src_plt_cache(pvname)
def update(self):
self._update(self.plt, self.cache)

61
director.py Normal file
View File

@ -0,0 +1,61 @@
from random import choice
from bokeh.layouts import column, row
from bokeh.models import Button, Div, Spacer, TextInput
from bokeh.plotting import curdoc
from actor import Actor
class Director:
def __init__(self):
self.doc = doc = curdoc()
doc.title = choice("👺👹") + " kabuki"
ti_add_pv = TextInput(value="", title="Add PV:")
ti_add_pv.on_change("value", self.on_add_pv)
self.layout = layout = column(ti_add_pv)
doc.add_root(layout)
def add_pvs(self, *pvnames):
for n in pvnames:
self.add_pv(n)
def on_add_pv(self, attr, old, new):
print("CB Add PV:", attr, old, new)
self.add_pv(new)
def add_pv(self, pvname):
print("Add PV:", pvname)
try:
a = Actor(pvname)
except Exception as e:
print("caught:", type(e), e)
return
def add_header_widgets(fig):
btn = Button(label="🗙", button_type="light", width=35)
lbl = Div(text=fig.name, align="center", style={"font-size": "150%"})
res = column(row(btn, lbl), fig, Spacer(height=35))
btn.on_click(lambda: self.remove_plot(res))
return res
fig = a.plt.fig
fig = add_header_widgets(fig)
# self.layout.children.append(fig)
self.layout.children.insert(1, fig) # 1 to skip TextInput
self.doc.add_periodic_callback(a.update, 1000)
def remove_plot(self, which):
print("Remove plot:", which)
self.layout.children.remove(which)

View File

@ -1,44 +1,10 @@
#!/usr/bin/env python
from random import choice
from bokeh.plotting import curdoc
from bokeh.layouts import column
from cacher import cacher
from plots import Plot0D, Plot1D, Plot2D
from sources import Camera, Source
from director import Director
src0 = Source("MTEST:RAND0")
src1 = Source("MTEST:ARR")
src2 = Camera("MTEST:CHAN-IMAGE:FPICTURE")
cache0 = cacher.add_source(src0)
cache1 = cacher.add_source(src1, size=1) #TODO: statistics on the curves would need larger cache
cache2 = cacher.add_source(src2, size=1)
p0 = Plot0D()
p1 = Plot1D()
p2 = Plot2D()
def update():
p0.set(*cache0.xy)
p1.set(cache1.latest)
p2.set(cache2.latest)
doc = curdoc()
doc.title = choice("👺👹") + " kabuki"
doc.add_periodic_callback(update, 1000)
plt = column(
p0.fig,
p1.fig,
p2.fig
)
doc.add_root(plt)
app = Director()
app.doc.add_periodic_callback(lambda: print(cacher), 10000)
app.add_pvs("MTEST:RAND0", "MTEST:ARR", "MTEST:CHAN-IMAGE:FPICTURE")