From e8c4630ffa769c949324a0bf3e9dbdb89244549f Mon Sep 17 00:00:00 2001 From: Sven Augustin Date: Wed, 15 Sep 2021 15:29:10 +0200 Subject: [PATCH] first prototype --- run.py | 48 +++++++++++++++++ zoetrope/__init__.py | 4 ++ zoetrope/aniplot.py | 125 +++++++++++++++++++++++++++++++++++++++++++ zoetrope/contaxes.py | 24 +++++++++ zoetrope/contplot.py | 27 ++++++++++ zoetrope/mpltypes.py | 15 ++++++ zoetrope/utils.py | 33 ++++++++++++ zoetrope/zoetrope.py | 7 +++ 8 files changed, 283 insertions(+) create mode 100755 run.py create mode 100644 zoetrope/__init__.py create mode 100644 zoetrope/aniplot.py create mode 100644 zoetrope/contaxes.py create mode 100644 zoetrope/contplot.py create mode 100644 zoetrope/mpltypes.py create mode 100644 zoetrope/utils.py create mode 100644 zoetrope/zoetrope.py diff --git a/run.py b/run.py new file mode 100755 index 0000000..3e6b029 --- /dev/null +++ b/run.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +from time import sleep +import numpy as np + +from zoetrope import aniplot as plt + + +def noise(arr): + rand = np.random.random(arr.shape) - 0.5 + return arr * rand + +x = np.arange(0.0, 2.0, 0.01) +y = 1 + np.sin(2 * np.pi * x) + +xdim = ydim = 10 +img = np.arange(0, xdim *ydim, 1).reshape(xdim, ydim) + + +plt.subplot(121) +pln1 = plt.plot(x, noise(y)+1) +pln2 = plt.plot(x, noise(y)+2) +pln3, pln4 = plt.plot(x, noise(y)+3, x, noise(y)+4) + +plt.subplot(122) +pimg = plt.imshow(noise(img)) + +plt.show() + + +for i in plt.show(): + print(i) + + pln1.set(x, noise(y)+1) + pln2.set(x, noise(y)+2) + pln3.set(x, noise(y)+3) + pln4.set(x, noise(y)+4) + pimg.set(noise(img)) + +# if i % 500 == 250: +# plt.disable_blit() +# if i % 500 == 350: +# plt.enable_blit() + + + + + diff --git a/zoetrope/__init__.py b/zoetrope/__init__.py new file mode 100644 index 0000000..927d5f7 --- /dev/null +++ b/zoetrope/__init__.py @@ -0,0 +1,4 @@ + +from .zoetrope import * + + diff --git a/zoetrope/aniplot.py b/zoetrope/aniplot.py new file mode 100644 index 0000000..46208d9 --- /dev/null +++ b/zoetrope/aniplot.py @@ -0,0 +1,125 @@ +from functools import wraps +from itertools import count + +from matplotlib import pyplot as plt + +from .contaxes import AxesContainer +from .contplot import PlotContainer + +from .mpltypes import is_plot_artist +from .utils import iflatten, unseq + + +class AniPlot: + + def __init__(self, blit=True): + self.blit = blit + self.plots = set() + self.axes = set() + + # handle resizing the window + fig = plt.gcf() + fig.canvas.mpl_connect("draw_event", self.on_resize) + + + def on_resize(self, event): + self._save_bkgs() + + + def __getattr__(self, name): + attr = getattr(plt, name) + + if not callable(attr): + return attr + + @wraps(attr) + def wrapper(*args, **kwargs): + res = attr(*args, **kwargs) + + plots = set() + for obj in iflatten(res): + if is_plot_artist(obj): + plots.add(obj) + else: + print(f"ignoring: {name}() -> {obj}") + + if not plots: + return res + + ax = plt.gca() + plots = [PlotContainer(i, ax) for i in plots] + + fig = plt.gcf() + ax = AxesContainer(ax, fig) + + self.plots.update(plots) + self.axes.add(ax) + + return unseq(plots) + + return wrapper + + + def show(self): + fig = plt.gcf() + canvas = fig.canvas + canvas.draw() + + if self.blit: + self._enable_animated_all() + self._save_bkgs() + + plt.show(block=False) + + for i in count(): + yield i + if self.blit: + self._update_with_blit() + else: + canvas.draw() + canvas.flush_events() + + + def _update_with_blit(self): + self._restore_bkgs() + self._draw_all() + self._blit_all() + + + def _save_bkgs(self): + for a in self.axes: + a._save_bkg() + + def _restore_bkgs(self): + for a in self.axes: + a._restore_bkg() + + + def _draw_all(self): + for p in self.plots: + p._draw() + + def _blit_all(self): + for a in self.axes: + a._blit() + + + def _enable_animated_all(self): + for p in self.plots: + p._enable_animated() + + def _disable_animated_all(self): + for p in self.plots: + p._disable_animated() + + + def enable_blit(self): + self.blit = True + self._enable_animated_all() + + def disable_blit(self): + self.blit = False + self._disable_animated_all() + + + diff --git a/zoetrope/contaxes.py b/zoetrope/contaxes.py new file mode 100644 index 0000000..bf61327 --- /dev/null +++ b/zoetrope/contaxes.py @@ -0,0 +1,24 @@ + +class AxesContainer: + + def __init__(self, ax, fig): + self.ax = ax + self.fig = fig + self._bkg = None + + def __repr__(self): + return repr(self.ax) + + + def _save_bkg(self): + self._bkg = self.fig.canvas.copy_from_bbox(self.ax.bbox) + + def _restore_bkg(self): + if self._bkg: + self.fig.canvas.restore_region(self._bkg) + + def _blit(self): + self.fig.canvas.blit(self.ax.bbox) + + + diff --git a/zoetrope/contplot.py b/zoetrope/contplot.py new file mode 100644 index 0000000..f61ba77 --- /dev/null +++ b/zoetrope/contplot.py @@ -0,0 +1,27 @@ + +class PlotContainer: + + def __init__(self, artist, ax): + self.artist = artist + self.ax = ax + + def __repr__(self): + return repr(self.artist) + + + def set(self, *args): + self.artist.set_data(*args) + + + def _draw(self): + self.ax.draw_artist(self.artist) + + + def _enable_animated(self): + self.artist.set_animated(True) + + def _disable_animated(self): + self.artist.set_animated(False) + + + diff --git a/zoetrope/mpltypes.py b/zoetrope/mpltypes.py new file mode 100644 index 0000000..16d9b2a --- /dev/null +++ b/zoetrope/mpltypes.py @@ -0,0 +1,15 @@ +from matplotlib.artist import Artist +from matplotlib.axes import Axes + + +def is_plot_artist(obj): + return is_artist(obj) and not is_axis_artist(obj) + +def is_artist(obj): + return isinstance(obj, Artist) + +def is_axis_artist(obj): + return isinstance(obj, Axes) + + + diff --git a/zoetrope/utils.py b/zoetrope/utils.py new file mode 100644 index 0000000..dc935a6 --- /dev/null +++ b/zoetrope/utils.py @@ -0,0 +1,33 @@ + +def unseq(seq): + return seq[0] if len(seq) == 1 else seq + + + +#def flatten(obj): +# try: +# iter(obj) +# except TypeError: +# return [obj] +# else: +# res = [] +# for i in obj: +# res.extend(flatten(i)) +# return res + + + +def flatten(obj): + return list(iflatten(obj)) + +def iflatten(obj): + try: + iterator = iter(obj) + except TypeError: + yield obj + else: + for item in iterator: + yield from iflatten(item) + + + diff --git a/zoetrope/zoetrope.py b/zoetrope/zoetrope.py new file mode 100644 index 0000000..f7947de --- /dev/null +++ b/zoetrope/zoetrope.py @@ -0,0 +1,7 @@ +from .aniplot import AniPlot + + +aniplot = AniPlot() + + +