Skip to content

Commit b88b9c5

Browse files
committed
Merge branch 'mplot3d/empty_plots'
2 parents 35071df + c128f0e commit b88b9c5

File tree

3 files changed

+89
-21
lines changed

3 files changed

+89
-21
lines changed

CHANGELOG

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2011-06-28 3D versions of scatter, plot, plot_wireframe, plot_surface,
2+
bar3d, and some other functions now support empty inputs. - BVR
3+
14
2011-06-16 Added *bottom* keyword parameter for the stem command.
25
Also, implemented a legend handler for the stem plot.
36
- JJL

lib/mpl_toolkits/mplot3d/art3d.py

+24-9
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,10 @@ def do_3d_projection(self, renderer):
319319
self.set_edgecolors(zalpha(self._edgecolor3d, vzs))
320320
PatchCollection.set_offsets(self, zip(vxs, vys))
321321

322-
return min(vzs)
322+
if vzs.size > 0 :
323+
return min(vzs)
324+
else :
325+
return np.nan
323326

324327
def draw(self, renderer):
325328
self._old_draw(renderer)
@@ -395,7 +398,13 @@ def get_vector(self, segments3d):
395398
ei = si+len(p)
396399
segis.append((si, ei))
397400
si = ei
398-
xs, ys, zs = zip(*points)
401+
402+
if len(segments3d) > 0 :
403+
xs, ys, zs = zip(*points)
404+
else :
405+
# We need this so that we can skip the bad unpacking from zip()
406+
xs, ys, zs = [], [], []
407+
399408
ones = np.ones(len(xs))
400409
self._vec = np.array([xs, ys, zs, ones])
401410
self._segis = segis
@@ -458,11 +467,16 @@ def do_3d_projection(self, renderer):
458467

459468
# Return zorder value
460469
if self._sort_zpos is not None:
461-
zvec = np.array([[0], [0], [self._sort_zpos], [1]])
462-
ztrans = proj3d.proj_transform_vec(zvec, renderer.M)
463-
return ztrans[2][0]
464-
else:
470+
zvec = np.array([[0], [0], [self._sort_zpos], [1]])
471+
ztrans = proj3d.proj_transform_vec(zvec, renderer.M)
472+
return ztrans[2][0]
473+
elif tzs.size > 0 :
474+
# FIXME: Some results still don't look quite right.
475+
# In particular, examine contourf3d_demo2.py
476+
# with az = -54 and elev = -45.
465477
return np.min(tzs)
478+
else :
479+
return np.nan
466480

467481
def set_facecolor(self, colors):
468482
PolyCollection.set_facecolor(self, colors)
@@ -559,8 +573,9 @@ def get_colors(c, num):
559573
def zalpha(colors, zs):
560574
"""Modify the alphas of the color list according to depth"""
561575
colors = get_colors(colors, len(zs))
562-
norm = Normalize(min(zs), max(zs))
563-
sats = 1 - norm(zs) * 0.7
564-
colors = [(c[0], c[1], c[2], c[3] * s) for c, s in zip(colors, sats)]
576+
if zs.size > 0 :
577+
norm = Normalize(min(zs), max(zs))
578+
sats = 1 - norm(zs) * 0.7
579+
colors = [(c[0], c[1], c[2], c[3] * s) for c, s in zip(colors, sats)]
565580
return colors
566581

lib/mpl_toolkits/mplot3d/axes3d.py

+62-12
Original file line numberDiff line numberDiff line change
@@ -670,17 +670,29 @@ def plot(self, xs, ys, *args, **kwargs):
670670
Other arguments are passed on to
671671
:func:`~matplotlib.axes.Axes.plot`
672672
'''
673-
673+
# FIXME: This argument parsing might be better handled
674+
# when we set later versions of python for
675+
# minimum requirements. Currently at 2.4.
676+
# Note that some of the reason for the current difficulty
677+
# is caused by the fact that we want to insert a new
678+
# (semi-optional) positional argument 'Z' right before
679+
# many other traditional positional arguments occur
680+
# such as the color, linestyle and/or marker.
674681
had_data = self.has_data()
675682
zs = kwargs.pop('zs', 0)
676683
zdir = kwargs.pop('zdir', 'z')
677684

678685
argsi = 0
679686
# First argument is array of zs
680687
if len(args) > 0 and cbook.iterable(args[0]) and \
681-
len(xs) == len(args[0]) and cbook.is_scalar(args[0][0]):
682-
zs = args[argsi]
683-
argsi += 1
688+
len(xs) == len(args[0]) :
689+
# So, we know that it is an array with
690+
# first dimension the same as xs.
691+
# Next, check to see if the data contained
692+
# therein (if any) is scalar (and not another array).
693+
if len(args[0]) == 0 or cbook.is_scalar(args[0][0]) :
694+
zs = args[argsi]
695+
argsi += 1
684696

685697
# First argument is z value
686698
elif len(args) > 0 and cbook.is_scalar(args[0]):
@@ -860,7 +872,7 @@ def _shade_colors(self, color, normals):
860872
colors = (0.5 + norm(shade)[:, np.newaxis] * 0.5) * color
861873
colors[:, 3] = alpha
862874
else:
863-
colors = color.copy()
875+
colors = np.asanyarray(color).copy()
864876

865877
return colors
866878

@@ -892,12 +904,37 @@ def plot_wireframe(self, X, Y, Z, *args, **kwargs):
892904
cstride = kwargs.pop("cstride", 1)
893905

894906
had_data = self.has_data()
907+
Z = np.atleast_2d(Z)
908+
# FIXME: Support masked arrays
909+
X = np.asarray(X)
910+
Y = np.asarray(Y)
895911
rows, cols = Z.shape
896-
912+
# Force X and Y to take the same shape.
913+
# If they can not be fitted to that shape,
914+
# then an exception is automatically thrown.
915+
X.shape = (rows, cols)
916+
Y.shape = (rows, cols)
917+
918+
# We want two sets of lines, one running along the "rows" of
919+
# Z and another set of lines running along the "columns" of Z.
920+
# This transpose will make it easy to obtain the columns.
897921
tX, tY, tZ = np.transpose(X), np.transpose(Y), np.transpose(Z)
898922

899-
rii = [i for i in range(0, rows, rstride)]+[rows-1]
900-
cii = [i for i in range(0, cols, cstride)]+[cols-1]
923+
rii = range(0, rows, rstride)
924+
cii = range(0, cols, cstride)
925+
926+
# Add the last index only if needed
927+
if rows > 0 and rii[-1] != (rows - 1) :
928+
rii += [rows-1]
929+
if cols > 0 and cii[-1] != (cols - 1) :
930+
cii += [cols-1]
931+
932+
# If the inputs were empty, then just
933+
# reset everything.
934+
if Z.size == 0 :
935+
rii = []
936+
cii = []
937+
901938
xlines = [X[i] for i in rii]
902939
ylines = [Y[i] for i in rii]
903940
zlines = [Z[i] for i in rii]
@@ -1133,16 +1170,21 @@ def add_collection3d(self, col, zs=0, zdir='z'):
11331170
- LineColleciton
11341171
- PatchCollection
11351172
'''
1173+
zvals = np.atleast_1d(zs)
1174+
if len(zvals) > 0 :
1175+
zsortval = min(zvals)
1176+
else :
1177+
zsortval = 0 # FIXME: Fairly arbitrary. Is there a better value?
11361178

11371179
if type(col) is collections.PolyCollection:
11381180
art3d.poly_collection_2d_to_3d(col, zs=zs, zdir=zdir)
1139-
col.set_sort_zpos(min(zs))
1181+
col.set_sort_zpos(zsortval)
11401182
elif type(col) is collections.LineCollection:
11411183
art3d.line_collection_2d_to_3d(col, zs=zs, zdir=zdir)
1142-
col.set_sort_zpos(min(zs))
1184+
col.set_sort_zpos(zsortval)
11431185
elif type(col) is collections.PatchCollection:
11441186
art3d.patch_collection_2d_to_3d(col, zs=zs, zdir=zdir)
1145-
col.set_sort_zpos(min(zs))
1187+
col.set_sort_zpos(zsortval)
11461188

11471189
Axes.add_collection(self, col)
11481190

@@ -1251,7 +1293,14 @@ def bar(self, left, height, zs=0, zdir='z', *args, **kwargs):
12511293
if 'alpha' in kwargs:
12521294
p.set_alpha(kwargs['alpha'])
12531295

1254-
xs, ys = zip(*verts)
1296+
if len(verts) > 0 :
1297+
# the following has to be skipped if verts is empty
1298+
# NOTE: Bugs could still occur if len(verts) > 0,
1299+
# but the "2nd dimension" is empty.
1300+
xs, ys = zip(*verts)
1301+
else :
1302+
xs, ys = [], []
1303+
12551304
xs, ys, verts_zs = art3d.juggle_axes(xs, ys, verts_zs, zdir)
12561305
self.auto_scale_xyz(xs, ys, verts_zs, had_data)
12571306

@@ -1317,6 +1366,7 @@ def bar3d(self, x, y, z, dx, dy, dz, color='b',
13171366
if len(x) != len(y) or len(x) != len(z):
13181367
warnings.warn('x, y, and z must be the same length.')
13191368

1369+
# FIXME: This is archaic and could be done much better.
13201370
minx, miny, minz = 1e20, 1e20, 1e20
13211371
maxx, maxy, maxz = -1e20, -1e20, -1e20
13221372

0 commit comments

Comments
 (0)