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

Skip to content

Fix for shared axes diverging after setting tick markers #10691

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

Closed
wants to merge 10 commits into from
Closed
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
38 changes: 8 additions & 30 deletions lib/matplotlib/axes/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3071,21 +3071,10 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False, **kw):
'invalid limits will be ignored.')
left, right = self.xaxis.limit_range_for_scale(left, right)

self.viewLim.intervalx = (left, right)
if auto is not None:
self._autoscaleXon = bool(auto)

if emit:
self.callbacks.process('xlim_changed', self)
# Call all of the other x-axes that are shared with this one
for other in self._shared_x_axes.get_siblings(self):
if other is not self:
other.set_xlim(self.viewLim.intervalx,
emit=False, auto=auto)
if (other.figure != self.figure and
other.figure.canvas is not None):
other.figure.canvas.draw_idle()
self.stale = True
# We force the use of `maxis.XAxis` so that subclasses have access
# to changing `viewLim` in this way (see Axes3D)
maxis.XAxis.set_view_interval(self.xaxis, left, right, ignore=True,
emit=emit, auto=auto)
return left, right

def get_xscale(self):
Expand Down Expand Up @@ -3391,21 +3380,10 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False, **kw):
'invalid limits will be ignored.')
bottom, top = self.yaxis.limit_range_for_scale(bottom, top)

self.viewLim.intervaly = (bottom, top)
if auto is not None:
self._autoscaleYon = bool(auto)

if emit:
self.callbacks.process('ylim_changed', self)
# Call all of the other y-axes that are shared with this one
for other in self._shared_y_axes.get_siblings(self):
if other is not self:
other.set_ylim(self.viewLim.intervaly,
emit=False, auto=auto)
if (other.figure != self.figure and
other.figure.canvas is not None):
other.figure.canvas.draw_idle()
self.stale = True
# We force the use of `maxis.YAxis` so that subclasses have access
# to changing `viewLim` in this way (see Axes3D)
maxis.YAxis.set_view_interval(self.yaxis, bottom, top, ignore=True,
emit=emit, auto=auto)
return bottom, top

def get_yscale(self):
Expand Down
133 changes: 115 additions & 18 deletions lib/matplotlib/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -926,14 +926,15 @@ def get_view_interval(self):
'return the Interval instance for this axis view limits'
raise NotImplementedError('Derived must override')

def set_view_interval(self, vmin, vmax, ignore=False):
def set_view_interval(self, vmin, vmax, ignore=False, emit=True,
auto=False):
raise NotImplementedError('Derived must override')

def get_data_interval(self):
'return the Interval instance for this axis data limits'
raise NotImplementedError('Derived must override')

def set_data_interval(self):
def set_data_interval(self, vmin, vmax, ignore=False):
'''set the axis data limits'''
raise NotImplementedError('Derived must override')

Expand Down Expand Up @@ -2062,18 +2063,53 @@ def get_view_interval(self):
'return the Interval instance for this axis view limits'
return self.axes.viewLim.intervalx

def set_view_interval(self, vmin, vmax, ignore=False):
def set_view_interval(self, vmin, vmax, ignore=False, emit=True,
auto=False):
"""
If *ignore* is *False*, the order of vmin, vmax
does not matter; the original axis orientation will
be preserved. In addition, the view limits can be
expanded, but will not be reduced. This method is
for mpl internal use; for normal use, see
:meth:`~matplotlib.axes.Axes.set_xlim`.
Set the x-axis view limits for the parent Axes instance.

.. ACCEPTS: (vmin: float, vmax: float)

Parameters
----------
vmin : scalar
The smaller value of viewLim.

vmax : scalar
The higher value of viewLim.

ignore : bool, optional
Whether we should take (vmin, vmax) literally (default: False).
If this is False, the order of vmin, vmax does not matter; the
original axis orientation will be preserved.

emit : bool, optional
Whether to notify observers of limit change (default: True).

auto : bool or None, optional
Whether to turn on autoscaling of this axis. True turns on,
False turns off (default action), None leaves unchanged.

Notes
-----
If `ignore` is False (default), the view limits can be expanded, but
will not be reduced. Otherwise, if `ignore` is True, the `vmin` value
may be greater than the `vmax` value, in which case the viewLim will
decrease from left to right.

Examples
--------
>>> set_view_interval(vmin, vmax, ignore=True)

Sets the new view interval to (vmin, vmax).

>>> set_view_interval(vmin, vmax)

Expands the view interval to the minimum of the current interval
and vmin, and the maximum of the current interval and vmax.
"""
if ignore:
self.axes.viewLim.intervalx = vmin, vmax
self.axes.viewLim.intervalx = (vmin, vmax)
else:
Vmin, Vmax = self.get_view_interval()
if Vmin < Vmax:
Expand All @@ -2082,6 +2118,19 @@ def set_view_interval(self, vmin, vmax, ignore=False):
else:
self.axes.viewLim.intervalx = (max(vmin, vmax, Vmin),
min(vmin, vmax, Vmax))
if auto is not None:
self.axes.set_autoscalex_on(bool(auto))
if emit:
self.axes.callbacks.process('xlim_changed', self.axes)
# Call all of the other axes that are shared with this one
for other in self.axes.get_shared_x_axes().get_siblings(self.axes):
if other is not self.axes:
other.set_xlim(self.axes.viewLim.intervalx, emit=False,
auto=auto)
if (other.figure != self.axes.figure and
other.figure.canvas is not None):
other.figure.canvas.draw_idle()
self.axes.stale = True

def get_minpos(self):
return self.axes.dataLim.minposx
Expand Down Expand Up @@ -2440,18 +2489,53 @@ def get_view_interval(self):
'return the Interval instance for this axis view limits'
return self.axes.viewLim.intervaly

def set_view_interval(self, vmin, vmax, ignore=False):
def set_view_interval(self, vmin, vmax, ignore=False, emit=True,
auto=False):
"""
If *ignore* is *False*, the order of vmin, vmax
does not matter; the original axis orientation will
be preserved. In addition, the view limits can be
expanded, but will not be reduced. This method is
for mpl internal use; for normal use, see
:meth:`~matplotlib.axes.Axes.set_ylim`.
Set the y-axis view limits for the parent Axes instance.

.. ACCEPTS: (vmin: float, vmax: float)

Parameters
----------
vmin : scalar
The smaller value of viewLim.

vmax : scalar
The higher value of viewLim.

ignore : bool, optional
Whether we should take (vmin, vmax) literally (default: False).
If this is False, the order of vmin, vmax does not matter; the
original axis orientation will be preserved.

emit : bool, optional
Whether to notify observers of limit change (default: True).

auto : bool or None, optional
Whether to turn on autoscaling of this axis. True turns on,
False turns off (default action), None leaves unchanged.

Notes
-----
If `ignore` is False (default), the view limits can be expanded, but
will not be reduced. Otherwise, if `ignore` is True, the `vmin` value
may be greater than the `vmax` value, in which case the viewLim will
decrease from left to right.

Examples
--------
>>> set_view_interval(vmin, vmax, ignore=True)

Sets the new view interval to (vmin, vmax).

>>> set_view_interval(vmin, vmax)

Expands the view interval to the minimum of the current interval
and vmin, and the maximum of the current interval and vmax.
"""
if ignore:
self.axes.viewLim.intervaly = vmin, vmax
self.axes.viewLim.intervaly = (vmin, vmax)
else:
Vmin, Vmax = self.get_view_interval()
if Vmin < Vmax:
Expand All @@ -2460,6 +2544,19 @@ def set_view_interval(self, vmin, vmax, ignore=False):
else:
self.axes.viewLim.intervaly = (max(vmin, vmax, Vmin),
min(vmin, vmax, Vmax))
if auto is not None:
self.axes.set_autoscaley_on(bool(auto))
if emit:
self.axes.callbacks.process('ylim_changed', self.axes)
# Call all of the other axes that are shared with this one
for other in self.axes.get_shared_y_axes().get_siblings(self.axes):
if other is not self.axes:
other.set_ylim(self.axes.viewLim.intervaly, emit=False,
auto=auto)
if (other.figure != self.axes.figure and
other.figure.canvas is not None):
other.figure.canvas.draw_idle()
self.axes.stale = True
self.stale = True

def get_minpos(self):
Expand Down
23 changes: 23 additions & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5134,6 +5134,29 @@ def test_remove_shared_axes_relim():
assert_array_equal(ax_lst[0][1].get_xlim(), orig_xlim)


def test_shared_axes_retick():
# related to GitHub issue 8946
# set_xticks should set shared axes limits
fig, ax_lst = plt.subplots(2, 2, sharex='all', sharey='all')

data = np.random.randn(10)
data2 = np.random.randn(10)
index = range(10)
index2 = [x + 5.5 for x in index]

ax_lst[0][0].scatter(index, data)
ax_lst[0][1].scatter(index2, data2)

ax_lst[1][0].scatter(index, data)
ax_lst[1][1].scatter(index2, data2)

ax_lst[0][0].set_xticks(range(-10, 20, 1))
ax_lst[0][0].set_yticks(range(-10, 20, 1))

assert ax_lst[0][0].get_xlim() == ax_lst[0][1].get_xlim()
assert ax_lst[0][0].get_ylim() == ax_lst[1][0].get_ylim()


def test_shared_axes_autoscale():
l = np.arange(-80, 90, 40)
t = np.random.random_sample((l.size, l.size))
Expand Down
65 changes: 16 additions & 49 deletions lib/mpl_toolkits/mplot3d/axes3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,22 +642,9 @@ def set_xlim3d(self, left=None, right=None, emit=True, auto=False, **kw):
'left=%s, right=%s') % (left, right))
left, right = mtransforms.nonsingular(left, right, increasing=False)
left, right = self.xaxis.limit_range_for_scale(left, right)
self.xy_viewLim.intervalx = (left, right)

if auto is not None:
self._autoscaleXon = bool(auto)

if emit:
self.callbacks.process('xlim_changed', self)
# Call all of the other x-axes that are shared with this one
for other in self._shared_x_axes.get_siblings(self):
if other is not self:
other.set_xlim(self.xy_viewLim.intervalx,
emit=False, auto=auto)
if (other.figure != self.figure and
other.figure.canvas is not None):
other.figure.canvas.draw_idle()
self.stale = True

self.xaxis.set_view_interval(left, right, ignore=True, emit=emit,
auto=auto)
return left, right
set_xlim = set_xlim3d

Expand Down Expand Up @@ -694,22 +681,9 @@ def set_ylim3d(self, bottom=None, top=None, emit=True, auto=False, **kw):
'bottom=%s, top=%s') % (bottom, top))
bottom, top = mtransforms.nonsingular(bottom, top, increasing=False)
bottom, top = self.yaxis.limit_range_for_scale(bottom, top)
self.xy_viewLim.intervaly = (bottom, top)

if auto is not None:
self._autoscaleYon = bool(auto)

if emit:
self.callbacks.process('ylim_changed', self)
# Call all of the other y-axes that are shared with this one
for other in self._shared_y_axes.get_siblings(self):
if other is not self:
other.set_ylim(self.xy_viewLim.intervaly,
emit=False, auto=auto)
if (other.figure != self.figure and
other.figure.canvas is not None):
other.figure.canvas.draw_idle()
self.stale = True

self.yaxis.set_view_interval(bottom, top, ignore=True, emit=emit,
auto=auto)
return bottom, top
set_ylim = set_ylim3d

Expand Down Expand Up @@ -746,22 +720,9 @@ def set_zlim3d(self, bottom=None, top=None, emit=True, auto=False, **kw):
'bottom=%s, top=%s') % (bottom, top))
bottom, top = mtransforms.nonsingular(bottom, top, increasing=False)
bottom, top = self.zaxis.limit_range_for_scale(bottom, top)
self.zz_viewLim.intervalx = (bottom, top)

if auto is not None:
self._autoscaleZon = bool(auto)

if emit:
self.callbacks.process('zlim_changed', self)
# Call all of the other y-axes that are shared with this one
for other in self._shared_z_axes.get_siblings(self):
if other is not self:
other.set_zlim(self.zz_viewLim.intervalx,
emit=False, auto=auto)
if (other.figure != self.figure and
other.figure.canvas is not None):
other.figure.canvas.draw_idle()
self.stale = True

self.zaxis.set_view_interval(bottom, top, ignore=True, emit=emit,
auto=auto)
return bottom, top
set_zlim = set_zlim3d

Expand Down Expand Up @@ -952,6 +913,10 @@ def clabel(self, *args, **kwargs):
"""
return None

def get_shared_z_axes(self):
"""Return a reference to the shared axes Grouper object for z axes."""
return self._shared_z_axes

def view_init(self, elev=None, azim=None):
"""
Set the elevation and azimuth of the axes.
Expand Down Expand Up @@ -2003,6 +1968,7 @@ def plot_trisurf(self, *args, **kwargs):
xt = tri.x[triangles]
yt = tri.y[triangles]
zt = z[triangles]

verts = np.stack((xt, yt, zt), axis=-1)

polyc = art3d.Poly3DCollection(verts, *args, **kwargs)
Expand Down Expand Up @@ -2814,7 +2780,8 @@ def voxels(filled, **kwargs):
def _broadcast_color_arg(color, name):
if np.ndim(color) in (0, 1):
# single color, like "red" or [1, 0, 0]
return np.broadcast_to(color, filled.shape + np.shape(color))
return np.broadcast_to(
color, filled.shape + np.shape(color))
elif np.ndim(color) in (3, 4):
# 3D array of strings, or 4D array with last axis rgb
if np.shape(color)[:3] != filled.shape:
Expand Down
Loading