Skip to content
Snippets Groups Projects

Add live_view module to qutil.plotting.

Merged Tobias Hangleiter requested to merge feat/live_data_view into master
Compare and Show latest version
1 file
+ 3
118
Compare changes
  • Side-by-side
  • Inline
+ 3
118
@@ -1732,124 +1732,6 @@ class IncrementalLiveView2D(LiveView2DBase):
self._cdata[ix] = c
LiveViewT = TypeVar('LiveViewT', bound=LiveViewBase)
class MultiLiveView(dict[str, LiveViewT]):
def __init__(self,
views: dict[str, tuple[type[LiveViewT], DataSourceProtocol, dict[str, Any]]],
update_interval_ms: int = int(1e3 / 60), useblit: bool = True,
share_axes: bool = True, xlabel: str = '', ylabel: str = '',
xlim: tuple[float, float] | None = None, ylim: tuple[float, float] | None = None,
xscale: str | ScaleT = 'linear', yscale: str | ScaleT = 'linear',
subplot_kw: Mapping[str, Any] | None = None,
gridspec_kw: Mapping[str, Any] | None = None,
fig_kw: Mapping[str, Any] | None = None):
self.fig = plt.figure(**(fig_kw or {}))
shared = self._setup_axes(views, share_axes, subplot_kw, gridspec_kw)
# views add callbacks and set the interval
event_source = self.fig.canvas.new_timer()
view_objs: list[LiveViewT] = []
for i, [label, (cls, data_source, kwargs)] in enumerate(views.items()):
view = cls(
data_source, update_interval_ms=update_interval_ms, useblit=useblit,
event_source=event_source, fig=self.fig, ax=self.axes[label],
**self._update_kwargs(
i, kwargs, shared, views, xlabel, xlim, xscale, ylabel, ylim, yscale
)
)
view._disconnect_buttons()
# close_event is handled by views
cid_pause_resume = view.buttons['pause_resume'].on_clicked(self.toggle_pause_resume)
cid_rescale = view.buttons['rescale'].on_clicked(self.rescale)
self.cids = {'pause_resume': cid_pause_resume, 'rescale': cid_rescale}
view_objs.append(view)
super().__init__(zip(views.keys(), view_objs))
@staticmethod
def _update_kwargs(i, kwargs, shared, views, xlabel, xlim, xscale, ylabel, ylim, yscale):
if shared is not None:
if shared == 'x':
kwargs.setdefault('ylabel', ylabel)
kwargs.setdefault('ylim', ylim)
kwargs.setdefault('yscale', yscale)
if i == len(views) - 1:
# All axes share x, so just set stuff on bottom one
kwargs |= dict(xlabel=xlabel, xlim=xlim, xscale=xscale)
elif shared == 'y':
kwargs.setdefault('xlabel', xlabel)
kwargs.setdefault('xlim', xlim)
kwargs.setdefault('xscale', xscale)
if i == 0:
# All axes share y, so just set stuff on leftmost one
kwargs |= dict(ylabel=ylabel, ylim=ylim, yscale=yscale)
else:
kwargs.setdefault('xlabel', xlabel)
kwargs.setdefault('ylabel', ylabel)
kwargs.setdefault('xlim', xlim)
kwargs.setdefault('ylim', ylim)
kwargs.setdefault('xscale', xscale)
kwargs.setdefault('yscale', yscale)
return kwargs
def _setup_axes(
self,
views: dict[str, tuple[type[LiveViewT], DataSourceProtocol, Mapping[str, Any]]],
share_axes: bool = True,
subplot_kw: Mapping[str, Any] | None = None,
gridspec_kw: Mapping[str, Any] | None = None
) -> Literal['x', 'y'] | None:
if plot_2d := any(issubclass(typ, LiveView2DBase) for typ, *_ in views.values()):
nrows = 1
ncols = len(views)
sharex = False
sharey = True and share_axes
shared = 'y' if share_axes else None
else:
nrows = len(views)
ncols = 1
sharex = True and share_axes
sharey = False
shared = 'x' if share_axes else None
axes = self.fig.subplots(nrows=nrows, ncols=ncols, sharex=sharex, sharey=sharey,
subplot_kw=subplot_kw, gridspec_kw=gridspec_kw)
if plot_2d:
# There is a 2d live view which will make room for a color bar.
# Resize all the other axes such that their width is the same
# as the 2d plot's.
for ax, (typ, *_) in zip(axes, views.values()):
if not issubclass(typ, LiveView2DBase):
_make_subgridspec(ax, height_ratios=[1])
self.axes = dict(zip(views.keys(), axes))
return shared
def start(self):
for view in self.values():
view.start()
def stop(self):
for view in self.values():
view.stop()
def toggle_pause_resume(self, event=None):
for view in self.values():
view.toggle_pause_resume(event)
def rescale(self, event=None, axis='both'):
for view in self.values():
view.rescale(event, axis)
def _make_subgridspec(ax: Axes, height_ratios: Sequence[float], pad: float = 0.05,
fraction: float = 0.15, hspace: float = 0.1) -> GridSpecFromSubplotSpec:
# Copied from matplotlib.colorbar.make_axes_gridspec()
@@ -1996,3 +1878,6 @@ def _setup_logging(level: int):
handler.setFormatter(formatter)
logger.addHandler(handler)
LiveViewT = TypeVar('LiveViewT', bound=LiveViewBase)
Loading