diff --git a/doc/api/api_changes/2015-11-12-DDH.rst b/doc/api/api_changes/2015-11-12-DDH.rst new file mode 100644 index 000000000000..ba899dc6e7f0 --- /dev/null +++ b/doc/api/api_changes/2015-11-12-DDH.rst @@ -0,0 +1,16 @@ +New defaults for 3D quiver function in mpl_toolkits.mplot3d.axes3d.py +``````````````````````````` +Matplotlib has both a 2D and a 3D ``quiver`` function. These changes affect only the 3D function and make the default behavior of the 3D function match 2D version. There are two changes: + +1) The 3D quiver function previously normalized the arrows to be the same length, which makes it unusable for situations where the arrows should be different lengths and does not match the behavior of the 2D function. This normalization behavior is now controlled with the ``normalize`` keyword, which defaults to False. + +2) The ``pivot`` keyword now defaults to ``tail`` instead of ``tip``. This was done in order to match the default behavior of the 2D quiver function. + +To obtain the previous behavior with the 3D quiver function, one can call the function with :: + + ax.quiver(x, y, z, u, v, w, normalize=True, pivot='tip') + +where "ax" is a axes3d object created with something like :: + + import mpl_toolkits.mplot3d.axes3d + ax = plt.sublot(111, projection='3d') \ No newline at end of file diff --git a/examples/mplot3d/quiver3d_demo.py b/examples/mplot3d/quiver3d_demo.py index 1051c2fe3ff1..65d02862db8a 100644 --- a/examples/mplot3d/quiver3d_demo.py +++ b/examples/mplot3d/quiver3d_demo.py @@ -14,6 +14,6 @@ w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z)) -ax.quiver(x, y, z, u, v, w, length=0.1) +ax.quiver(x, y, z, u, v, w, length=0.1, normalize=True) plt.show() diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 912722bc4583..59ce4e6626f3 100755 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -2477,7 +2477,7 @@ def quiver(self, *args, **kwargs): *X*, *Y*, *Z*: The x, y and z coordinates of the arrow locations (default is - tip of arrow; see *pivot* kwarg) + tail of arrow; see *pivot* kwarg) *U*, *V*, *W*: The x, y and z components of the arrow vectors @@ -2499,7 +2499,13 @@ def quiver(self, *args, **kwargs): *pivot*: [ 'tail' | 'middle' | 'tip' ] The part of the arrow that is at the grid point; the arrow - rotates about this point, hence the name *pivot*. + rotates about this point, hence the name *pivot*. + Default is 'tail' + + *normalize*: [False | True] + When True, all of the arrows will be the same length. This + defaults to False, where the arrows will be different lengths + depending on the values of u,v,w. Any additional keyword arguments are delegated to :class:`~matplotlib.collections.LineCollection` @@ -2508,6 +2514,7 @@ def quiver(self, *args, **kwargs): def calc_arrow(uvw, angle=15): """ To calculate the arrow head. uvw should be a unit vector. + We normalize it here: """ # get unit direction vector perpendicular to (u,v,w) norm = np.linalg.norm(uvw[:2]) @@ -2540,7 +2547,9 @@ def calc_arrow(uvw, angle=15): # arrow length ratio to the shaft length arrow_length_ratio = kwargs.pop('arrow_length_ratio', 0.3) # pivot point - pivot = kwargs.pop('pivot', 'tip') + pivot = kwargs.pop('pivot', 'tail') + # normalize + normalize = kwargs.pop('normalize', False) # handle args argi = 6 @@ -2601,7 +2610,10 @@ def calc_arrow(uvw, angle=15): # If any row of UVW is all zeros, don't make a quiver for it mask = norm > 1e-10 XYZ = XYZ[mask] - UVW = UVW[mask] / norm[mask].reshape((-1, 1)) + if normalize: + UVW = UVW[mask] / norm[mask].reshape((-1, 1)) + else: + UVW = UVW[mask] if len(XYZ) > 0: # compute the shaft lines all at once with an outer product diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index 4dbf4c0e6912..86f62af9fd8f 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -215,7 +215,7 @@ def test_quiver3d(): w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z)) - ax.quiver(x, y, z, u, v, w, length=0.1) + ax.quiver(x, y, z, u, v, w, length=0.1, pivot='tip', normalize=True) @image_comparison(baseline_images=['quiver3d_empty'], remove_text=True) def test_quiver3d_empty(): @@ -229,7 +229,7 @@ def test_quiver3d_empty(): w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z)) - ax.quiver(x, y, z, u, v, w, length=0.1) + ax.quiver(x, y, z, u, v, w, length=0.1, pivot='tip', normalize=True) @image_comparison(baseline_images=['quiver3d_masked'], remove_text=True) def test_quiver3d_masked(): @@ -247,7 +247,7 @@ def test_quiver3d_masked(): u = np.ma.masked_where((-0.4 < x) & (x < 0.1), u, copy=False) v = np.ma.masked_where((0.1 < y) & (y < 0.7), v, copy=False) - ax.quiver(x, y, z, u, v, w, length=0.1) + ax.quiver(x, y, z, u, v, w, length=0.1, pivot='tip', normalize=True) @image_comparison(baseline_images=['quiver3d_pivot_middle'], remove_text=True, extensions=['png']) @@ -262,7 +262,7 @@ def test_quiver3d_pivot_middle(): w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z)) - ax.quiver(x, y, z, u, v, w, length=0.1, pivot='middle') + ax.quiver(x, y, z, u, v, w, length=0.1, pivot='middle', normalize=True) @image_comparison(baseline_images=['quiver3d_pivot_tail'], remove_text=True, extensions=['png']) @@ -277,7 +277,7 @@ def test_quiver3d_pivot_tail(): w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z)) - ax.quiver(x, y, z, u, v, w, length=0.1, pivot='tail') + ax.quiver(x, y, z, u, v, w, length=0.1, pivot='tail', normalize=True) @image_comparison(baseline_images=['axes3d_labelpad'], extensions=['png'])
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: