Skip to content

Commit e68ce6d

Browse files
Multiview support now fully working, new
test for it.
1 parent 058ae26 commit e68ce6d

File tree

3 files changed

+86
-25
lines changed

3 files changed

+86
-25
lines changed

matplotview/__init__.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
from matplotlib.axes import Axes
44
from matplotview._view_axes import view_wrapper, ViewSpecification, DEFAULT_RENDER_DEPTH
55

6-
__all__ = ["view", "inset_zoom_axes"]
6+
__all__ = ["view", "inset_zoom_axes", "ViewSpecification"]
77

88
def view(
99
axes: Axes,
1010
axes_to_view: Axes,
1111
image_interpolation: str = "nearest",
12-
render_depth: int = DEFAULT_RENDER_DEPTH,
12+
render_depth: Optional[int] = None,
1313
filter_set: Optional[Iterable[Union[Type[Artist], Artist]]] = None,
1414
scale_lines: bool = True
1515
) -> Axes:
@@ -34,14 +34,17 @@ def view(
3434
'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos',
3535
or 'none'
3636
37-
render_depth: int, positive, defaults to 5
37+
render_depth: optional int, positive, defaults to None
3838
The number of recursive draws allowed for this view, this can happen
3939
if the view is a child of the axes (such as an inset axes) or if
40-
two views point at each other. Defaults to 5.
40+
two views point at each other. If None, uses the default render depth
41+
of 5, unless the axes passed is already a view axes, in which case the
42+
render depth the view already has will be used.
4143
4244
filter_set: Iterable[Union[Type[Artist], Artist]] or None
4345
An optional filter set, which can be used to select what artists
44-
are drawn by the view. Any artists types in the set are not drawn.
46+
are drawn by the view. Any artists or artist types in the set are not
47+
drawn.
4548
4649
scale_lines: bool, defaults to True
4750
Specifies if lines should be drawn thicker based on scaling in the
@@ -60,12 +63,12 @@ def inset_zoom_axes(
6063
axes: Axes,
6164
bounds: Iterable,
6265
*,
63-
image_interpolation="nearest",
64-
render_depth: int = DEFAULT_RENDER_DEPTH,
66+
image_interpolation: str = "nearest",
67+
render_depth: Optional[int] = None,
6568
filter_set: Optional[Iterable[Union[Type[Artist], Artist]]] = None,
6669
scale_lines: bool = True,
67-
transform=None,
68-
zorder=5,
70+
transform = None,
71+
zorder: int = 5,
6972
**kwargs
7073
) -> Axes:
7174
"""
@@ -97,10 +100,12 @@ def inset_zoom_axes(
97100
determines the interpolation used when attempting to render a
98101
zoomed version of an image.
99102
100-
render_depth: int, positive, defaults to 5
103+
render_depth: optional int, positive, defaults to None
101104
The number of recursive draws allowed for this view, this can happen
102105
if the view is a child of the axes (such as an inset axes) or if
103-
two views point at each other. Defaults to 5.
106+
two views point at each other. If None, uses the default render depth
107+
of 5, unless the axes passed is already a view axes, in which case the
108+
render depth the view already has will be used.
104109
105110
filter_set: Iterable[Union[Type[Artist], Artist]] or None
106111
An optional filter set, which can be used to select what artists

matplotview/_view_axes.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ def __post_init__(self):
106106
self.filter_set = set(self.filter_set)
107107
self.scale_lines = bool(self.scale_lines)
108108

109+
class __ViewType:
110+
"""
111+
PRIVATE: A simple identifier class for identifying view types, a view
112+
will inherit from the axes class it is wrapping and this type...
113+
"""
114+
...
109115

110116
# Cache classes so grabbing the same type twice leads to actually getting the
111117
# same type (and type comparisons work).
@@ -127,8 +133,11 @@ def view_wrapper(axes_class: Type[Axes]) -> Type[Axes]:
127133
The view axes wrapper for a given axes class, capable of displaying
128134
another axes contents...
129135
"""
136+
if(issubclass(axes_class, Axes) and issubclass(axes_class, __ViewType)):
137+
return axes_class
138+
130139
@docstring.interpd
131-
class View(axes_class):
140+
class View(axes_class, __ViewType):
132141
"""
133142
An axes which automatically displays elements of another axes. Does not
134143
require Artists to be plotted twice.
@@ -151,10 +160,10 @@ def __init__(
151160
Additional arguments to be passed to the Axes class this
152161
ViewAxes wraps.
153162
154-
render_depth: int, positive, defaults to 10
163+
render_depth: int, positive, defaults to 5
155164
The number of recursive draws allowed for this view, this can
156165
happen if the view is a child of the axes (such as an inset
157-
axes) or if two views point at each other. Defaults to 10.
166+
axes) or if two views point at each other. Defaults to 5.
158167
159168
**kwargs
160169
Other optional keyword arguments supported by the Axes
@@ -171,10 +180,12 @@ def __init__(
171180
self._init_vars(render_depth)
172181

173182
def _init_vars(self, render_depth: int = DEFAULT_RENDER_DEPTH):
174-
# Initialize the view specs set...
175-
self.__view_specs = {}
183+
# Initialize the view specs dict...
184+
self.__view_specs = getattr(self, "__view_specs", {})
176185
self.__renderer = None
177-
self.__max_render_depth = DEFAULT_RENDER_DEPTH
186+
self.__max_render_depth = getattr(
187+
self, "__max_render_depth", DEFAULT_RENDER_DEPTH
188+
)
178189
self.set_max_render_depth(render_depth)
179190
# The current render depth is stored in the figure, so the number
180191
# of recursive draws is even in the case of multiple axes drawing
@@ -297,11 +308,14 @@ def view_specifications(self) -> Dict[Axes, ViewSpecification]:
297308
"""
298309
return self.__view_specs
299310

311+
# Shortcut for easier access...
312+
view_specs = view_specifications
313+
300314
@classmethod
301315
def from_axes(
302316
cls,
303317
axes: Axes,
304-
render_depth: int = DEFAULT_RENDER_DEPTH
318+
render_depth: Optional[int] = None
305319
) -> Axes:
306320
"""
307321
Convert an Axes into a View in-place. This is used by public
@@ -314,10 +328,11 @@ def from_axes(
314328
axes: Axes
315329
The axes to convert to a view wrapping the same axes type.
316330
317-
render_depth: int, positive, defaults to 10
331+
render_depth: optional int, positive, defaults to None
318332
The number of recursive draws allowed for this view, this can
319333
happen if the view is a child of the axes (such as an inset
320-
axes) or if two views point at each other. Defaults to 10.
334+
axes) or if two views point at each other. If none, use the
335+
default value (5) if the render depth is not already set.
321336
322337
Returns
323338
-------
@@ -329,18 +344,24 @@ def from_axes(
329344
------
330345
TypeError
331346
If the provided axes to convert has an Axes type which does
332-
not match the axes class this view type wraps.ss
347+
not match the axes class this view type wraps.
333348
"""
349+
if(isinstance(axes, cls)):
350+
if(render_depth is not None):
351+
axes.set_max_render_depth(render_depth)
352+
return axes
353+
334354
if(type(axes) != axes_class):
335355
raise TypeError(
336356
f"Can't convert {type(axes).__name__} to {cls.__name__}"
337357
)
338358

339-
if(isinstance(axes, cls)):
340-
return axes
341-
342359
axes.__class__ = cls
343-
axes._init_vars(render_depth)
360+
axes._init_vars(
361+
DEFAULT_RENDER_DEPTH
362+
if(render_depth is None)
363+
else render_depth
364+
)
344365
return axes
345366

346367
View.__name__ = f"{View.__name__}[{axes_class.__name__}]"

matplotview/tests/test_view_rendering.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,38 @@ def test_map_projection_view(fig_test, fig_ref):
181181
ax_r1.add_patch(circ_gen())
182182
ax_r2.plot(x, y)
183183
ax_r2.add_patch(circ_gen())
184+
185+
186+
@check_figures_equal()
187+
def test_double_view(fig_test, fig_ref):
188+
# Test case...
189+
ax_test1, ax_test2, ax_test3 = fig_test.subplots(1, 3)
190+
191+
ax_test1.add_patch(plt.Circle((1, 1), 1.5, ec="black", fc=(0, 0, 1, 0.5)))
192+
ax_test3.add_patch(plt.Circle((3, 1), 1.5, ec="black", fc=(1, 0, 0, 0.5)))
193+
194+
ax_test2 = view(
195+
view(ax_test2, ax_test1, scale_lines=False),
196+
ax_test3, scale_lines=False
197+
)
198+
199+
ax_test2.set_aspect(1)
200+
ax_test2.set_xlim(-0.5, 4.5)
201+
ax_test2.set_ylim(-0.5, 2.5)
202+
203+
# Reference...
204+
ax_ref1, ax_ref2, ax_ref3 = fig_ref.subplots(1, 3)
205+
206+
ax_ref1.add_patch(plt.Circle((1, 1), 1.5, ec="black", fc=(0, 0, 1, 0.5)))
207+
ax_ref3.add_patch(plt.Circle((3, 1), 1.5, ec="black", fc=(1, 0, 0, 0.5)))
208+
209+
ax_ref2.add_patch(plt.Circle((1, 1), 1.5, ec="black", fc=(0, 0, 1, 0.5)))
210+
ax_ref2.add_patch(plt.Circle((3, 1), 1.5, ec="black", fc=(1, 0, 0, 0.5)))
211+
ax_ref2.set_aspect(1)
212+
ax_ref2.set_xlim(-0.5, 4.5)
213+
ax_ref2.set_ylim(-0.5, 2.5)
214+
215+
for ax in (ax_test1, ax_test3, ax_ref1, ax_ref3):
216+
ax.set_aspect(1)
217+
ax.relim()
218+
ax.autoscale_view()

0 commit comments

Comments
 (0)