8000 Implement dynamic clipping to axes box for 3D plots · matplotlib/matplotlib@be117e7 · GitHub
[go: up one dir, main page]

Skip to content

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit be117e7

Browse files
Implement dynamic clipping to axes box for 3D plots
WIP
1 parent 62a5ba4 commit be117e7

File tree

9 files changed

+384
-107
lines changed

9 files changed

+384
-107
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Data in 3D plots can now be dynamically clipped to the axes view limits
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
All 3D plotting functions now support the *axlim_clip* keyword argument, which
5+
will clip the data to the axes view limits, hiding all data outside those
6+
bounds. This clipping will be dynamically applied in real time while panning
7+
and zooming.
8+
9+
Please note that if one vertex of a line segment or 3D patch is clipped, the
10+
entire segment or patch will be hidden. Not being able to show partial lines
11+
or patches such that they are "smoothly" cut off at the boundaries of the view
12+
box is a limitation of the current renderer.
13+
14+
.. plot::
15+
:include-source: true
16+
:alt: Example of default behavior (left) and axlim_clip=True (right)
17+
18+
import matplotlib.pyplot as plt
19+
import numpy as np
20+
21+
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
22+
np.random.seed(1)
23+
xyz = np.random.rand(25, 3)
24+
25+
# Note that when a line has one vertex outside the view limits, the entire
26+
# line is hidden. The same is true for 3D patches (not shown).
27+
ax.plot(xyz[:, 0], xyz[:, 1], xyz[:, 2], '-o')
28+
ax.plot(xyz[:, 0], xyz[:, 1], xyz[:, 2], '--*', axlim_clip=True)
29+
ax.set(xlim=(0.25, 0.75), ylim=(0, 1), zlim=(0, 1))
30+
ax.legend(['axlim_clip=False (default)', 'axlim_clip=True'])
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
=====================================
3+
Clip the data to the axes view limits
4+
=====================================
5+
6+
Demonstrate clipping of line and marker data to the axes view limits. The
7+
``axlim_clip`` keyword argument can be used in any of the 3D plotting
8+
functions.
9+
"""
10+
11+
import matplotlib.pyplot as plt
12+
import numpy as np
13+
14+
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
15+
16+
# Generate the random data
17+
np.random.seed(1)
18+
xyz = np.random.rand(25, 3)
19+
20+
# Default behavior is axlim_clip=False
21+
ax.plot(xyz[:, 0], xyz[:, 1], xyz[:, 2], '-o')
22+
23+
# When axlim_clip=True, note that when a line has one vertex outside the view
24+
# limits, the entire line is hidden. The same is true for 3D patches (not
25+
# shown).
26+
ax.plot(xyz[:, 0], xyz[:, 1], xyz[:, 2], '--*', axlim_clip=True)
27+
28+
ax.set(xlim=(0.25, 0.75), ylim=(0, 1), zlim=(-1, 1))
29+
ax.legend(['axlim_clip=False (default)', 'axlim_clip=True'])
30+
31+
plt.show()

lib/matplotlib/collections.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ def _prepare_points(self):
336336
# This might have changed an ndarray into a masked array.
337337
offset_trf = offset_trf.get_affine()
338338

339-
if isinstance(offsets, np.ma.MaskedArray):
339+
if np.ma.isMaskedArray(offsets):
340340
offsets = offsets.filled(np.nan)
341341
# Changing from a masked array to nan-filled ndarray
342342
# is probably most efficient at this point.

lib/matplotlib/text.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -750,9 +750,16 @@ def draw(self, renderer):
750750

751751
# don't use self.get_position here, which refers to text
752752
# position in Text:
753-
posx = float(self.convert_xunits(self._x))
754-
posy = float(self.convert_yunits(self._y))
753+
x, y = self._x, self._y
754+
if np.ma.is_masked(x):
755+
x = np.nan
756+
if np.ma.is_masked(y):
757+
y = np.nan
758+
posx = float(self.convert_xunits(x))
759+
posy = float(self.convert_yunits(y))
755760
posx, posy = trans.transform((posx, posy))
761+
if np.isnan(posx) or np.isnan(posy):
762+
return # don't throw a warning here
756763
if not np.isfinite(posx) or not np.isfinite(posy):
757764
_log.warning("posx and posy should be finite values")
758765
return

0 commit comments

Comments
 (0)
0