-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Style fixes for mplot3d. #12069
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Style fixes for mplot3d. #12069
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -108,11 +108,7 @@ def draw(self, renderer): | |
[self._position3d, self._position3d + self._dir_vec], renderer.M) | ||
dx = proj[0][1] - proj[0][0] | ||
dy = proj[1][1] - proj[1][0] | ||
if dx==0. and dy==0.: | ||
# atan2 raises ValueError: math domain error on 0,0 | ||
angle = 0. | ||
else: | ||
angle = math.degrees(math.atan2(dy, dx)) | ||
angle = math.degrees(math.atan2(dy, dx)) | ||
self.set_position((proj[0][0], proj[1][0])) | ||
self.set_rotation(norm_text_angle(angle)) | ||
mtext.Text.draw(self, renderer) | ||
|
@@ -318,7 +314,7 @@ def do_3d_projection(self, renderer): | |
def get_patch_verts(patch): | ||
"""Return a list of vertices for the path of a patch.""" | ||
trans = patch.get_patch_transform() | ||
path = patch.get_path() | ||
path = patch.get_path() | ||
polygons = path.to_polygons(trans) | ||
if len(polygons): | ||
return polygons[0] | ||
|
@@ -469,10 +465,7 @@ def do_3d_projection(self, renderer): | |
self.set_edgecolors(ecs) | ||
PathCollection.set_offsets(self, np.column_stack([vxs, vys])) | ||
|
||
if vzs.size > 0 : | ||
return min(vzs) | ||
else : | ||
return np.nan | ||
return np.min(vzs) if vzs.size else np.nan | ||
|
||
|
||
def patch_collection_2d_to_3d(col, zs=0, zdir='z', depthshade=True): | ||
|
@@ -563,7 +556,7 @@ def get_vector(self, segments3d): | |
|
||
if len(segments3d): | ||
xs, ys, zs = zip(*points) | ||
else : | ||
else: | ||
# We need this so that we can skip the bad unpacking from zip() | ||
xs, ys, zs = [], [], [] | ||
|
||
|
@@ -651,12 +644,12 @@ def do_3d_projection(self, renderer): | |
zvec = np.array([[0], [0], [self._sort_zpos], [1]]) | ||
ztrans = proj3d.proj_transform_vec(zvec, renderer.M) | ||
return ztrans[2][0] | ||
elif tzs.size > 0 : | ||
elif tzs.size > 0: | ||
# FIXME: Some results still don't look quite right. | ||
# In particular, examine contourf3d_demo2.py | ||
# with az = -54 and elev = -45. | ||
return np.min(tzs) | ||
else : | ||
else: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see where you're coming from but mixing in a ternary in a if... elif chain looks meh to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, I don't think that the three blocks are logically equal. To me, the current form
is logically more like
Usually
However, I agree that depends on the point of view you take. And I won't argue further if you still prefer to leave it as is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know (hence the "I see where you're coming from" above), but it still looks not so nice to me. (Really, best would be |
||
return np.nan | ||
|
||
def set_facecolor(self, colors): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
import matplotlib.collections as mcoll | ||
import matplotlib.colors as mcolors | ||
import matplotlib.docstring as docstring | ||
import matplotlib.projections as proj | ||
import matplotlib.scale as mscale | ||
import matplotlib.transforms as mtransforms | ||
from matplotlib.axes import Axes, rcParams | ||
|
@@ -71,7 +72,7 @@ def __init__( | |
.. versionadded :: 1.2.1 | ||
*sharez* | ||
|
||
''' % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} | ||
''' % {'scale': ' | '.join(repr(x) for x in mscale.get_scale_names())} | ||
|
||
if rect is None: | ||
rect = [0.0, 0.0, 1.0, 1.0] | ||
|
@@ -375,7 +376,7 @@ def set_zmargin(self, m): | |
.. versionadded :: 1.1.0 | ||
This function was added, but not tested. Please report any bugs. | ||
""" | ||
if m < 0 or m > 1 : | ||
if m < 0 or m > 1: | ||
raise ValueError("margin must be in range 0 to 1") | ||
self._zmargin = m | ||
self.stale = True | ||
|
@@ -493,7 +494,8 @@ def auto_scale_xyz(self, X, Y, Z=None, had_data=None): | |
# data. | ||
self.xy_dataLim.update_from_data_xy(np.array([x, y]).T, not had_data) | ||
if z is not None: | ||
self.zz_dataLim.update_from_data_xy(np.array([z, z]).T, not had_data) | ||
self.zz_dataLim.update_from_data_xy( | ||
np.array([z, z]).T, not had_data) | ||
|
||
# Let autoscale_view figure out how to use this data. | ||
self.autoscale_view() | ||
|
@@ -773,19 +775,19 @@ def get_xlim3d(self): | |
get_xlim = get_xlim3d | ||
if get_xlim.__doc__ is not None: | ||
get_xlim.__doc__ += """ | ||
.. versionchanged :: 1.1.0 | ||
This function now correctly refers to the 3D x-limits | ||
""" | ||
.. versionchanged :: 1.1.0 | ||
This function now correctly refers to the 3D x-limits | ||
""" | ||
|
||
def get_ylim3d(self): | ||
return tuple(self.xy_viewLim.intervaly) | ||
get_ylim3d.__doc__ = maxes.Axes.get_ylim.__doc__ | ||
get_ylim = get_ylim3d | ||
if get_ylim.__doc__ is not None: | ||
get_ylim.__doc__ += """ | ||
.. versionchanged :: 1.1.0 | ||
This function now correctly refers to the 3D y-limits. | ||
""" | ||
.. versionchanged :: 1.1.0 | ||
This function now correctly refers to the 3D y-limits. | ||
""" | ||
|
||
def get_zlim3d(self): | ||
'''Get 3D z limits.''' | ||
|
@@ -809,10 +811,9 @@ def set_xscale(self, value, **kwargs): | |
self._update_transScale() | ||
if maxes.Axes.set_xscale.__doc__ is not None: | ||
set_xscale.__doc__ = maxes.Axes.set_xscale.__doc__ + """ | ||
|
||
.. versionadded :: 1.1.0 | ||
This function was added, but not tested. Please report any bugs. | ||
""" | ||
.. versionadded :: 1.1.0 | ||
This function was added, but not tested. Please report any bugs. | ||
""" | ||
|
||
def set_yscale(self, value, **kwargs): | ||
self.yaxis._set_scale(value, **kwargs) | ||
|
@@ -821,10 +822,9 @@ def set_yscale(self, value, **kwargs): | |
self.stale = True | ||
if maxes.Axes.set_yscale.__doc__ is not None: | ||
set_yscale.__doc__ = maxes.Axes.set_yscale.__doc__ + """ | ||
|
||
.. versionadded :: 1.1.0 | ||
This function was added, but not tested. Please report any bugs. | ||
""" | ||
.. versionadded :: 1.1.0 | ||
This function was added, but not tested. Please report any bugs. | ||
""" | ||
|
||
@docstring.dedent_interpd | ||
def set_zscale(self, value, **kwargs): | ||
|
@@ -1340,7 +1340,7 @@ def ticklabel_format( | |
self.xaxis.major.formatter.set_scientific(sb) | ||
if axis in ['both', 'y']: | ||
self.yaxis.major.formatter.set_scientific(sb) | ||
if axis in ['both', 'z'] : | ||
if axis in ['both', 'z']: | ||
self.zaxis.major.formatter.set_scientific(sb) | ||
if scilimits is not None: | ||
if axis in ['both', 'x']: | ||
|
@@ -1413,7 +1413,7 @@ def tick_params(self, axis='both', **kwargs): | |
This function was added, but not tested. Please report any bugs. | ||
""" | ||
super().tick_params(axis, **kwargs) | ||
if axis in ['z', 'both'] : | ||
if axis in ['z', 'both']: | ||
zkw = dict(kwargs) | ||
zkw.pop('top', None) | ||
zkw.pop('bottom', None) | ||
|
@@ -1676,8 +1676,8 @@ def get_normals(polygons): | |
v1 = np.empty((len(polygons), 3)) | ||
v2 = np.empty((len(polygons), 3)) | ||
for poly_i, ps in enumerate(polygons): | ||
# pick three points around the polygon at which to find the normal | ||
# doesn't vectorize because polygons is jagged | ||
# pick three points around the polygon at which to find the | ||
# normal doesn't vectorize because polygons is jagged | ||
i1, i2, i3 = 0, len(ps)//3, 2*len(ps)//3 | ||
v1[poly_i, :] = ps[i1, :] - ps[i2, :] | ||
v2[poly_i, :] = ps[i2, :] - ps[i3, :] | ||
|
@@ -1937,7 +1937,8 @@ def plot_trisurf(self, *args, color=None, norm=None, vmin=None, vmax=None, | |
cmap = kwargs.get('cmap', None) | ||
shade = kwargs.pop('shade', cmap is None) | ||
|
||
tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs) | ||
tri, args, kwargs = \ | ||
Triangulation.get_from_args_and_kwargs(*args, **kwargs) | ||
if 'Z' in kwargs: | ||
z = np.asarray(kwargs.pop('Z')) | ||
else: | ||
|
@@ -2027,7 +2028,8 @@ def _3d_extend_contour(self, cset, stride=5): | |
for col in colls: | ||
self.collections.remove(col) | ||
|
||
def add_contour_set(self, cset, extend3d=False, stride=5, zdir='z', offset=None): | ||
def add_contour_set( | ||
self, cset, extend3d=False, stride=5, zdir='z', offset=None): | ||
zdir = '-' + zdir | ||
if extend3d: | ||
self._3d_extend_contour(cset, stride) | ||
|
@@ -2040,7 +2042,7 @@ def add_contour_set(self, cset, extend3d=False, stride=5, zdir='z', offset=None) | |
def add_contourf_set(self, cset, zdir='z', offset=None): | ||
zdir = '-' + zdir | ||
for z, linec in zip(cset.levels, cset.collections): | ||
if offset is not None : | ||
if offset is not None: | ||
z = offset | ||
art3d.poly_collection_2d_to_3d(linec, z, zdir=zdir) | ||
linec.set_sort_zpos(z) | ||
|
@@ -2225,10 +2227,8 @@ def add_collection3d(self, col, zs=0, zdir='z'): | |
- PatchCollection | ||
''' | ||
zvals = np.atleast_1d(zs) | ||
if len(zvals) > 0 : | ||
zsortval = min(zvals) | ||
else : | ||
zsortval = 0 # FIXME: Fairly arbitrary. Is there a better value? | ||
zsortval = (np.min(zvals) if zvals.size | ||
else 0) # FIXME: arbitrary default | ||
|
||
# FIXME: use issubclass() (although, then a 3D collection | ||
# object would also pass.) Maybe have a collection3d | ||
|
@@ -2345,12 +2345,12 @@ def bar(self, left, height, zs=0, zdir='z', *args, **kwargs): | |
if 'alpha' in kwargs: | ||
p.set_alpha(kwargs['alpha']) | ||
|
||
if len(verts) > 0 : | ||
if len(verts) > 0: | ||
# the following has to be skipped if verts is empty | ||
# NOTE: Bugs could still occur if len(verts) > 0, | ||
# but the "2nd dimension" is empty. | ||
xs, ys = list(zip(*verts)) | ||
else : | ||
xs, ys = zip(*verts) | ||
else: | ||
xs, ys = [], [] | ||
|
||
xs, ys, verts_zs = art3d.juggle_axes(xs, ys, verts_zs, zdir) | ||
|
@@ -2485,7 +2485,8 @@ def quiver(self, *args, | |
length=1, arrow_length_ratio=.3, pivot='tail', normalize=False, | ||
**kwargs): | ||
""" | ||
ax.quiver(X, Y, Z, U, V, W, /, length=1, arrow_length_ratio=.3, pivot='tail', normalize=False, **kwargs) | ||
ax.quiver(X, Y, Z, U, V, W, /, length=1, arrow_length_ratio=.3, \ | ||
pivot='tail', normalize=False, **kwargs) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be indented to align with the bracket in the line above? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not really, that'll look awkward in the actual docstring (the problem is the same as always re: line continuations in rst). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think treating the first line of the docstring as a replacement |
||
|
||
Plot a 3D field of arrows. | ||
|
||
|
@@ -2549,7 +2550,8 @@ def calc_arrow(uvw, angle=15): | |
[-y*s, x*s, c]]) | ||
# opposite rotation negates all the sin terms | ||
Rneg = Rpos.copy() | ||
Rneg[[0, 1, 2, 2], [2, 2, 0, 1]] = -Rneg[[0, 1, 2, 2], [2, 2, 0, 1]] | ||
Rneg[[0, 1, 2, 2], [2, 2, 0, 1]] = \ | ||
-Rneg[[0, 1, 2, 2], [2, 2, 0, 1]] | ||
|
||
# multiply them to get the rotated vector | ||
return Rpos.dot(uvw), Rneg.dot(uvw) | ||
|
@@ -2569,7 +2571,8 @@ def calc_arrow(uvw, angle=15): | |
for k in input_args] | ||
|
||
# extract the masks, if any | ||
masks = [k.mask for k in input_args if isinstance(k, np.ma.MaskedArray)] | ||
masks = [k.mask for k in input_args | ||
if isinstance(k, np.ma.MaskedArray)] | ||
# broadcast to match the shape | ||
bcast = np.broadcast_arrays(*(input_args + masks)) | ||
input_args = bcast[:argi] | ||
|
@@ -2622,9 +2625,9 @@ def calc_arrow(uvw, angle=15): | |
if len(XYZ) > 0: | ||
# compute the shaft lines all at once with an outer product | ||
shafts = (XYZ - np.multiply.outer(shaft_dt, UVW)).swapaxes(0, 1) | ||
# compute head direction vectors, n heads by 2 sides by 3 dimensions | ||
# compute head direction vectors, n heads x 2 sides x 3 dimensions | ||
head_dirs = np.array([calc_arrow(d) for d in UVW]) | ||
# compute all head lines at once, starting from where the shaft ends | ||
# compute all head lines at once, starting from the shaft ends | ||
heads = shafts[:, :1] - np.multiply.outer(arrow_dt, head_dirs) | ||
# stack left and right head lines together | ||
heads.shape = (len(arrow_dt), -1, 3) | ||
|
@@ -2669,13 +2672,13 @@ def voxels(self, *args, facecolors=None, edgecolors=None, **kwargs): | |
|
||
x, y, z : 3D np.array, optional | ||
The coordinates of the corners of the voxels. This should broadcast | ||
to a shape one larger in every dimension than the shape of `filled`. | ||
These can be used to plot non-cubic voxels. | ||
to a shape one larger in every dimension than the shape of | ||
`filled`. These can be used to plot non-cubic voxels. | ||
|
||
If not specified, defaults to increasing integers along each axis, | ||
like those returned by :func:`~numpy.indices`. | ||
As indicated by the ``/`` in the function signature, these arguments | ||
can only be passed positionally. | ||
As indicated by the ``/`` in the function signature, these | ||
arguments can only be passed positionally. | ||
|
||
facecolors, edgecolors : array_like, optional | ||
The color to draw the faces and edges of the voxels. Can only be | ||
|
@@ -2758,7 +2761,7 @@ def _broadcast_color_arg(color, name): | |
# broadcast but no default on edgecolors | ||
edgecolors = _broadcast_color_arg(edgecolors, 'edgecolors') | ||
|
||
# always scale to the full array, even if the data is only in the center | ||
# scale to the full array, even if the data is only in the center | ||
self.auto_scale_xyz(x, y, z) | ||
|
||
# points lying on corners of a square | ||
|
@@ -2778,8 +2781,8 @@ def permutation_matrices(n): | |
yield mat | ||
mat = np.roll(mat, 1, axis=0) | ||
|
||
# iterate over each of the YZ, ZX, and XY orientations, finding faces to | ||
# render | ||
# iterate over each of the YZ, ZX, and XY orientations, finding faces | ||
# to render | ||
for permute in permutation_matrices(3): | ||
# find the set of ranges to iterate over | ||
pc, qc, rc = permute.T.dot(size) | ||
|
@@ -2822,7 +2825,8 @@ def permutation_matrices(n): | |
if filled[ik]: | ||
voxel_faces[ik].append(pk2 + square_rot) | ||
|
||
# iterate over the faces, and generate a Poly3DCollection for each voxel | ||
# iterate over the faces, and generate a Poly3DCollection for each | ||
# voxel | ||
polygons = {} | ||
for coord, faces_inds in voxel_faces.items(): | ||
# convert indices into 3D positions | ||
|
@@ -2871,5 +2875,4 @@ def get_test_data(delta=0.05): | |
# Register Axes3D as a 'projection' object available | ||
# for use just like any other axes | ||
######################################################## | ||
import matplotlib.projections as proj | ||
proj.projection_registry.register(Axes3D) |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
math.atan2(0, 0) (or likewise with floats) returns 0 or pi depending on the signedness of the zeros in Py2 and Py3 and that's also mandated by the C standard. norm_text_angle later takes it modulo 180 so we're fine.