more protoyping
This commit is contained in:
203
caplot.py
Executable file
203
caplot.py
Executable file
@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import warnings
|
||||
warnings.filterwarnings("error")
|
||||
|
||||
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("pvname")
|
||||
clargs = parser.parse_args()
|
||||
|
||||
|
||||
import numpy as np
|
||||
from collections import deque
|
||||
from time import sleep
|
||||
from functools import wraps
|
||||
from types import SimpleNamespace
|
||||
from matplotlib import pyplot as plt
|
||||
from epics import PV
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class PVCollection:
|
||||
|
||||
def __init__(self, name, **kwargs):
|
||||
self.name = name
|
||||
# self.pvnames = SimpleNamespace(**kwargs)
|
||||
pvs = {k: PV(v) for k, v in kwargs.items()}
|
||||
for pv in pvs.values():
|
||||
pv.wait_for_connection()
|
||||
self.pvs = SimpleNamespace(**pvs)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
|
||||
class Camera(PVCollection):
|
||||
|
||||
def __init__(self, pvname):
|
||||
base = pvname.rsplit(":", 1)[0]
|
||||
super().__init__(
|
||||
base,
|
||||
image = pvname,
|
||||
width = base + ":WIDTH",
|
||||
height = base + ":HEIGHT"
|
||||
)
|
||||
|
||||
def get(self):
|
||||
data = self.pvs.image.get()
|
||||
data.shape = self.get_shape()
|
||||
return data
|
||||
|
||||
def get_shape(self):
|
||||
width = self.pvs.width.get()
|
||||
height = self.pvs.height.get()
|
||||
shape = (width, height)
|
||||
return shape
|
||||
|
||||
def add_callback(self, callback, **kwargs):
|
||||
@wraps(callback)
|
||||
def wrapper(*args, value=None, **kwargs):
|
||||
value.shape = self.get_shape()
|
||||
return callback(*args, value=value, **kwargs)
|
||||
return self.pvs.image.add_callback(callback=wrapper, with_ctrlvars=False, **kwargs)
|
||||
|
||||
def disconnect(self):
|
||||
for pv in self.pvs.__dict__.values(): #TODO
|
||||
pv.disconnect()
|
||||
|
||||
|
||||
|
||||
class Source(PV):
|
||||
|
||||
def __init__(self, pvname, *args, **kwargs):
|
||||
self.name = pvname
|
||||
super().__init__(pvname, *args, **kwargs)
|
||||
self.wait_for_connection()
|
||||
|
||||
|
||||
|
||||
class Animation:
|
||||
|
||||
def __init__(self, source, plot_func):
|
||||
value = source.get()
|
||||
self.plot = plot_func(value)
|
||||
plt.suptitle(source.name)
|
||||
source.add_callback(self.update)
|
||||
plt.show()
|
||||
source.disconnect()
|
||||
|
||||
def update(self, value=None, **kwargs):
|
||||
self.plot.set(value)
|
||||
plt.draw()
|
||||
|
||||
|
||||
|
||||
class PlotScalar:
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.fig, axs = plt.subplots(1, 2)
|
||||
self.ax_time, self.ax_hist = ax_time, ax_hist = axs
|
||||
|
||||
length = 100
|
||||
# init = [0] + [np.nan] * (length-2) + [0]
|
||||
# self.cache = cache = deque(init, maxlen=length)
|
||||
self.cache = cache = deque(maxlen=length)
|
||||
self.x = x = range(length)
|
||||
|
||||
# lines = ax_time.plot(x, cache)
|
||||
lines = ax_time.plot([0], [0])
|
||||
self.plot_time = lines[0] #TODO: wtf?
|
||||
|
||||
# plot_hist = ax_hist.bar(np.arange(0, 1, 100), [0] * 100)
|
||||
# self.plot_hist = plot_hist
|
||||
|
||||
|
||||
def set(self, value):
|
||||
cache = self.cache
|
||||
cache.append(value)
|
||||
|
||||
x = range(len(cache))
|
||||
self.plot_time.set_data(x, cache)
|
||||
nums = np.nan_to_num(cache)
|
||||
# print(nums)
|
||||
if min(nums) != max(nums):
|
||||
self.ax_time.set_ylim(min(nums), max(nums))
|
||||
|
||||
self.ax_time.relim()
|
||||
self.ax_time.autoscale_view()
|
||||
|
||||
|
||||
nums = np.array(cache)
|
||||
nums = nums[np.isfinite(nums)]
|
||||
ys, xs = np.histogram(nums, bins="auto")
|
||||
# print(ys)
|
||||
# for rect, x, y in zip(self.plot_hist, xs, ys):
|
||||
# rect.set_x(x)
|
||||
# rect.set_height(y)
|
||||
width = (xs[1:] - xs[:-1]).mean()
|
||||
try:
|
||||
self.plot_hist.remove()
|
||||
color = self.plot_hist.patches[0].get_facecolor()
|
||||
except:
|
||||
color = None
|
||||
|
||||
plot_hist = self.ax_hist.bar(xs[:-1], ys, color=color,align="edge", width=width)
|
||||
self.plot_hist = plot_hist
|
||||
|
||||
n = len(xs)
|
||||
self.ax_hist.set_title(f"#bins: {n}")
|
||||
|
||||
self.ax_hist.relim()
|
||||
self.ax_hist.autoscale_view()
|
||||
|
||||
|
||||
class Plot1D:
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
lines = plt.plot(*args, **kwargs)
|
||||
self.plot = lines[0] #TODO: wtf?
|
||||
|
||||
def set(self, value):
|
||||
self.plot.set_ydata(value)
|
||||
|
||||
|
||||
class Plot2D:
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.plot = plt.imshow(*args, **kwargs)
|
||||
|
||||
def set(self, value):
|
||||
self.plot.set_data(value)
|
||||
|
||||
|
||||
|
||||
pvname = clargs.pvname
|
||||
if pvname.endswith(":FPICTURE"):
|
||||
print("Camera", pvname)
|
||||
src = Camera(pvname)
|
||||
fun = Plot2D
|
||||
else:
|
||||
print("Source", pvname)
|
||||
src = Source(pvname)
|
||||
print(src.nelm)
|
||||
if src.nelm == 0:
|
||||
raise SystemExit(f"{src}: {src.value}")
|
||||
if src.nelm == 1:
|
||||
print("Scalar")
|
||||
fun = PlotScalar
|
||||
else:
|
||||
print("1D")
|
||||
fun = Plot1D
|
||||
|
||||
Animation(src, fun)
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user