diff --git a/data_prototype/patches.py b/data_prototype/patches.py new file mode 100644 index 0000000..94a50af --- /dev/null +++ b/data_prototype/patches.py @@ -0,0 +1,90 @@ +import numpy as np + +from .wrappers import ProxyWrapper, _stale_wrapper +from .containers import DataContainer + +from matplotlib.patches import Patch as _Patch, Rectangle as _Rectangle + + +class PatchWrapper(ProxyWrapper): + _wrapped_class = _Patch + _privtized_methods = ( + "get_edgecolor", + "get_facecolor", + "get_linewidth", + "get_linestyle", + "get_antialiased", + "get_hatch", + "get_fill", + "get_capstyle", + "get_joinstyle", + "get_path", + "set_edgecolor", + "set_facecolor", + "set_linewidth", + "set_linestyle", + "set_antialiased", + "set_hatch", + "set_fill", + "set_capstyle", + "set_joinstyle", + "set_path", + ) + _xunits = () + _yunits = () + required_keys = { + "edgecolor", + "facecolor", + "linewidth", + "linestyle", + "antialiased", + "hatch", + "fill", + "capstyle", + "joinstyle", + } + + def __init__(self, data: DataContainer, nus=None, /, **kwargs): + super().__init__(data, nus) + self._wrapped_instance = self._wrapped_class([0, 0], 0, 0, **kwargs) + + @_stale_wrapper + def draw(self, renderer): + self._update_wrapped(self._query_and_transform(renderer, xunits=self._xunits, yunits=self._yunits)) + return self._wrapped_instance.draw(renderer) + + def _update_wrapped(self, data): + for k, v in data.items(): + getattr(self._wrapped_instance, f"set_{k}")(v) + + +class RectangleWrapper(PatchWrapper): + _wrapped_class = _Rectangle + _privtized_methods = PatchWrapper._privtized_methods + ( + "get_x", + "get_y", + "get_width", + "get_height", + "get_angle", + "get_rotation_point" "set_x", + "set_y", + "set_width", + "set_height", + "set_angle", + "set_rotation_point", + ) + _xunits = ("x", "width") + _yunits = ("y", "height") + required_keys = PatchWrapper.required_keys | {"x", "y", "width", "height", "angle", "rotation_point"} + + def _update_wrapped(self, data): + for k, v in data.items(): + if k == "rotation_point": + self._wrapped_instance.rotation_point = v + continue + # linestyle and hatch do not work as arrays, + # but ArrayContainer requires arrays, so index into an array if needed + elif k in ("linestyle", "hatch"): + if isinstance(v, np.ndarray): + v = v[0] + getattr(self._wrapped_instance, f"set_{k}")(v) diff --git a/examples/simple_patch.py b/examples/simple_patch.py new file mode 100644 index 0000000..53f0fb8 --- /dev/null +++ b/examples/simple_patch.py @@ -0,0 +1,59 @@ +""" +==================== +Simple patch artists +==================== + +""" +import numpy as np + +import matplotlib.pyplot as plt + +from data_prototype.containers import ArrayContainer + +from data_prototype.patches import RectangleWrapper + +cont1 = ArrayContainer( + x=np.array([-3]), + y=np.array([0]), + width=np.array([2]), + height=np.array([3]), + angle=np.array([0]), + rotation_point=np.array(["center"]), + edgecolor=np.array([0, 0, 0]), + facecolor=np.array([0.0, 0.7, 0, 0.5]), + linewidth=np.array([3]), + linestyle=np.array(["-"]), + antialiased=np.array([True]), + hatch=np.array(["*"]), + fill=np.array([True]), + capstyle=np.array(["round"]), + joinstyle=np.array(["miter"]), +) + +cont2 = ArrayContainer( + x=np.array([0]), + y=np.array([1]), + width=np.array([2]), + height=np.array([3]), + angle=np.array([30]), + rotation_point=np.array(["center"]), + edgecolor=np.array([0, 0, 0]), + facecolor=np.array([0.7, 0, 0]), + linewidth=np.array([6]), + linestyle=np.array(["-"]), + antialiased=np.array([True]), + hatch=np.array([""]), + fill=np.array([True]), + capstyle=np.array(["butt"]), + joinstyle=np.array(["round"]), +) + +fig, ax = plt.subplots() +ax.set_xlim(-5, 5) +ax.set_ylim(0, 5) +rect1 = RectangleWrapper(cont1, {}) +rect2 = RectangleWrapper(cont2, {}) +ax.add_artist(rect1) +ax.add_artist(rect2) +ax.set_aspect(1) +plt.show()