Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3277b9d

Browse files
authored
Merge pull request #20725 from tomneep/polygon-nan-removal
`Axes3D.plot_surface`: Allow masked arrays and `NaN` values
2 parents 586fcff + a25e666 commit 3277b9d

File tree

4 files changed

+61
-5
lines changed

4 files changed

+61
-5
lines changed

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,12 +1574,8 @@ def plot_surface(self, X, Y, Z, *args, norm=None, vmin=None,
15741574

15751575
if Z.ndim != 2:
15761576
raise ValueError("Argument Z must be 2-dimensional.")
1577-
if np.any(np.isnan(Z)):
1578-
_api.warn_external(
1579-
"Z contains NaN values. This may result in rendering "
1580-
"artifacts.")
15811577

1582-
# TODO: Support masked arrays
1578+
Z = cbook._to_unmasked_float_array(Z)
15831579
X, Y, Z = np.broadcast_arrays(X, Y, Z)
15841580
rows, cols = Z.shape
15851581

@@ -1655,6 +1651,27 @@ def plot_surface(self, X, Y, Z, *args, norm=None, vmin=None,
16551651
if fcolors is not None:
16561652
colset.append(fcolors[rs][cs])
16571653

1654+
# In cases where there are NaNs in the data (possibly from masked
1655+
# arrays), artifacts can be introduced. Here check whether NaNs exist
1656+
# and remove the entries if so
1657+
if not isinstance(polys, np.ndarray) or np.isnan(polys).any():
1658+
new_polys = []
1659+
new_colset = []
1660+
1661+
# Depending on fcolors, colset is either an empty list or has as
1662+
# many elements as polys. In the former case new_colset results in
1663+
# a list with None entries, that is discarded later.
1664+
for p, col in itertools.zip_longest(polys, colset):
1665+
new_poly = np.array(p)[~np.isnan(p).any(axis=1)]
1666+
if len(new_poly):
1667+
new_polys.append(new_poly)
1668+
new_colset.append(col)
1669+
1670+
# Replace previous polys and, if fcolors is not None, colset
1671+
polys = new_polys
1672+
if fcolors is not None:
1673+
colset = new_colset
1674+
16581675
# note that the striding causes some polygons to have more coordinates
16591676
# than others
16601677
polyc = art3d.Poly3DCollection(polys, *args, **kwargs)

lib/mpl_toolkits/tests/test_mplot3d.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,45 @@ def test_surface3d_shaded():
420420
ax.set_zlim(-1.01, 1.01)
421421

422422

423+
@mpl3d_image_comparison(['surface3d_masked.png'])
424+
def test_surface3d_masked():
425+
fig = plt.figure()
426+
ax = fig.add_subplot(projection='3d')
427+
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
428+
y = [1, 2, 3, 4, 5, 6, 7, 8]
429+
430+
x, y = np.meshgrid(x, y)
431+
matrix = np.array(
432+
[
433+
[-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
434+
[-1, 1, 2, 3, 4, 4, 4, 3, 2, 1, 1],
435+
[-1, -1., 4, 5, 6, 8, 6, 5, 4, 3, -1.],
436+
[-1, -1., 7, 8, 11, 12, 11, 8, 7, -1., -1.],
437+
[-1, -1., 8, 9, 10, 16, 10, 9, 10, 7, -1.],
438+
[-1, -1., -1., 12, 16, 20, 16, 12, 11, -1., -1.],
439+
[-1, -1., -1., -1., 22, 24, 22, 20, 18, -1., -1.],
440+
[-1, -1., -1., -1., -1., 28, 26, 25, -1., -1., -1.],
441+
]
442+
)
443+
z = np.ma.masked_less(matrix, 0)
444+
norm = mcolors.Normalize(vmax=z.max(), vmin=z.min())
445+
colors = plt.get_cmap("plasma")(norm(z))
446+
ax.plot_surface(x, y, z, facecolors=colors)
447+
ax.view_init(30, -80)
448+
449+
450+
@mpl3d_image_comparison(['surface3d_masked_strides.png'])
451+
def test_surface3d_masked_strides():
452+
fig = plt.figure()
453+
ax = fig.add_subplot(projection='3d')
454+
455+
x, y = np.mgrid[-6:6.1:1, -6:6.1:1]
456+
z = np.ma.masked_less(x * y, 2)
457+
458+
ax.plot_surface(x, y, z, rstride=4, cstride=4)
459+
ax.view_init(60, -45)
460+
461+
423462
@mpl3d_image_comparison(['text3d.png'], remove_text=False)
424463
def test_text3d():
425464
fig = plt.figure()

0 commit comments

Comments
 (0)