Skip to content

Backport PR #21326 on branch v3.5.x (Add ability to scale BBox with just x or y values) #21416

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions lib/matplotlib/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -902,11 +902,51 @@ def update_from_path(self, path, ignore=None, updatex=True, updatey=True):
self._points[:, 1] = points[:, 1]
self._minpos[1] = minpos[1]

def update_from_data_x(self, x, ignore=None):
"""
Update the x-bounds of the `Bbox` based on the passed in data. After
updating, the bounds will have positive *width*, and *x0* will be the
minimal value.

Parameters
----------
x : ndarray
Array of x-values.

ignore : bool, optional
- When ``True``, ignore the existing bounds of the `Bbox`.
- When ``False``, include the existing bounds of the `Bbox`.
- When ``None``, use the last value passed to :meth:`ignore`.
"""
x = np.ravel(x)
self.update_from_data_xy(np.column_stack([x, np.ones(x.size)]),
ignore=ignore, updatey=False)

def update_from_data_y(self, y, ignore=None):
"""
Update the y-bounds of the `Bbox` based on the passed in data. After
updating, the bounds will have positive *height*, and *y0* will be the
minimal value.

Parameters
----------
y : ndarray
Array of y-values.

ignore : bool, optional
- When ``True``, ignore the existing bounds of the `Bbox`.
- When ``False``, include the existing bounds of the `Bbox`.
- When ``None``, use the last value passed to :meth:`ignore`.
"""
y = np.array(y).ravel()
self.update_from_data_xy(np.column_stack([np.ones(y.size), y]),
ignore=ignore, updatex=False)

def update_from_data_xy(self, xy, ignore=None, updatex=True, updatey=True):
"""
Update the bounds of the `Bbox` based on the passed in
data. After updating, the bounds will have positive *width*
and *height*; *x0* and *y0* will be the minimal values.
Update the bounds of the `Bbox` based on the passed in data. After
updating, the bounds will have positive *width* and *height*;
*x0* and *y0* will be the minimal values.

Parameters
----------
Expand Down
15 changes: 8 additions & 7 deletions lib/mpl_toolkits/mplot3d/axes3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def __init__(
self.xy_viewLim = Bbox.unit()
self.zz_viewLim = Bbox.unit()
self.xy_dataLim = Bbox.unit()
# z-limits are encoded in the x-component of the Bbox, y is un-used
self.zz_dataLim = Bbox.unit()

# inhibit autoscale_view until the axes are defined
Expand Down Expand Up @@ -643,14 +644,14 @@ def autoscale(self, enable=True, axis='both', tight=None):
def auto_scale_xyz(self, X, Y, Z=None, had_data=None):
# This updates the bounding boxes as to keep a record as to what the
# minimum sized rectangular volume holds the data.
X = np.reshape(X, -1)
Y = np.reshape(Y, -1)
self.xy_dataLim.update_from_data_xy(
np.column_stack([X, Y]), not had_data)
if np.shape(X) == np.shape(Y):
self.xy_dataLim.update_from_data_xy(
np.column_stack([np.ravel(X), np.ravel(Y)]), not had_data)
else:
self.xy_dataLim.update_from_data_x(X, not had_data)
self.xy_dataLim.update_from_data_y(Y, not had_data)
if Z is not None:
Z = np.reshape(Z, -1)
self.zz_dataLim.update_from_data_xy(
np.column_stack([Z, Z]), not had_data)
self.zz_dataLim.update_from_data_x(Z, not had_data)
# Let autoscale_view figure out how to use this data.
self.autoscale_view()

Expand Down
11 changes: 11 additions & 0 deletions lib/mpl_toolkits/tests/test_mplot3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,17 @@ def test_tricontour():
ax.tricontourf(x, y, z)


def test_contour3d_1d_input():
# Check that 1D sequences of different length for {x, y} doesn't error
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
nx, ny = 30, 20
x = np.linspace(-10, 10, nx)
y = np.linspace(-10, 10, ny)
z = np.random.randint(0, 2, [ny, nx])
ax.contour(x, y, z, [0.5])


@mpl3d_image_comparison(['lines3d.png'])
def test_lines3d():
fig = plt.figure()
Expand Down