diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 6c0556b20fdb..291a8b6c1eaf 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -414,6 +414,7 @@ class _AxesBase(martist.Artist): _shared_x_axes = cbook.Grouper() _shared_y_axes = cbook.Grouper() + _twinned_axes = cbook.Grouper() def __str__(self): return "{0}({1[0]:g},{1[1]:g};{1[2]:g}x{1[3]:g})".format( @@ -440,7 +441,7 @@ def __init__(self, fig, rect, ================ ========================================= Keyword Description ================ ========================================= - *adjustable* [ 'box' | 'datalim' | 'box-forced'] + *adjustable* [ 'box' | 'datalim' ] *alpha* float: the alpha transparency (can be None) *anchor* [ 'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', 'NW', 'W' ] @@ -488,25 +489,15 @@ def __init__(self, fig, rect, self._originalPosition = self._position.frozen() # self.set_axes(self) self.axes = self - self.set_aspect('auto') + self._aspect = 'auto' self._adjustable = 'box' - self.set_anchor('C') + self._anchor = 'C' self._sharex = sharex self._sharey = sharey if sharex is not None: self._shared_x_axes.join(self, sharex) - if sharex._adjustable == 'box': - sharex._adjustable = 'datalim' - # warnings.warn( - # 'shared axes: "adjustable" is being changed to "datalim"') - self._adjustable = 'datalim' if sharey is not None: self._shared_y_axes.join(self, sharey) - if sharey._adjustable == 'box': - sharey._adjustable = 'datalim' - # warnings.warn( - # 'shared axes: "adjustable" is being changed to "datalim"') - self._adjustable = 'datalim' self.set_label(label) self.set_figure(fig) @@ -530,6 +521,7 @@ def __init__(self, fig, rect, self._connected = {} # a dict from events to (id, func) self.cla() + # funcs used to format x and y - fall back on major formatters self.fmt_xdata = None self.fmt_ydata = None @@ -630,8 +622,7 @@ def set_figure(self, fig): def _set_lim_and_transforms(self): """ - set the *dataLim* and *viewLim* - :class:`~matplotlib.transforms.Bbox` attributes and the + set the *_xaxis_transform*, *_yaxis_transform*, *transScale*, *transData*, *transLimits* and *transAxes* transformations. @@ -881,10 +872,11 @@ def set_position(self, pos, which='both'): """ if not isinstance(pos, mtransforms.BboxBase): pos = mtransforms.Bbox.from_bounds(*pos) - if which in ('both', 'active'): - self._position.set(pos) - if which in ('both', 'original'): - self._originalPosition.set(pos) + for ax in self._twinned_axes.get_siblings(self): + if which in ('both', 'active'): + ax._position.set(pos) + if which in ('both', 'original'): + ax._originalPosition.set(pos) self.stale = True def reset_position(self): @@ -894,8 +886,9 @@ def reset_position(self): This resets the a possible position change due to aspect constraints. For an explanation of the positions see `.set_position`. """ - pos = self.get_position(original=True) - self.set_position(pos, which='active') + for ax in self._twinned_axes.get_siblings(self): + pos = ax.get_position(original=True) + ax.set_position(pos, which='active') def set_axes_locator(self, locator): """ @@ -980,6 +973,7 @@ def cla(self): self.xaxis.cla() self.yaxis.cla() + for name, spine in six.iteritems(self.spines): spine.cla() @@ -987,7 +981,7 @@ def cla(self): self.callbacks = cbook.CallbackRegistry() if self._sharex is not None: - # major and minor are class instances with + # major and minor are axis.Ticker class instances with # locator and formatter attributes self.xaxis.major = self._sharex.xaxis.major self.xaxis.minor = self._sharex.xaxis.minor @@ -1015,7 +1009,6 @@ def cla(self): self.set_ylim(0, 1) except TypeError: pass - # update the minor locator for x and y axis based on rcParams if (rcParams['xtick.minor.visible']): self.xaxis.set_minor_locator(mticker.AutoMinorLocator()) @@ -1257,7 +1250,7 @@ def hold(self, b=None): def get_aspect(self): return self._aspect - def set_aspect(self, aspect, adjustable=None, anchor=None): + def set_aspect(self, aspect, adjustable=None, anchor=None, share=False): """ Set the aspect of the axis scaling, i.e. the ratio of y-unit to x-unit. @@ -1276,7 +1269,7 @@ def set_aspect(self, aspect, adjustable=None, anchor=None): aspect='equal'. ======== ================================================ - adjustable : None or ['box' | 'datalim' | 'box-forced'], optional + adjustable : None or ['box' | 'datalim'], optional If not ``None``, this defines which parameter will be adjusted to meet the required aspect. See `.set_adjustable` for further details. @@ -1298,6 +1291,10 @@ def set_aspect(self, aspect, adjustable=None, anchor=None): See `.set_anchor` for further details. + share : bool, optional + If ``True``, apply the settings to all shared Axes. + Default is ``False``. + See Also -------- matplotlib.axes.Axes.set_adjustable @@ -1306,54 +1303,73 @@ def set_aspect(self, aspect, adjustable=None, anchor=None): matplotlib.axes.Axes.set_anchor defining the position in case of extra space. """ - if (isinstance(aspect, six.string_types) + if not (isinstance(aspect, six.string_types) and aspect in ('equal', 'auto')): - self._aspect = aspect + aspect = float(aspect) # raise ValueError if necessary + if share: + axes = set(self._shared_x_axes.get_siblings(self) + + self._shared_y_axes.get_siblings(self)) else: - self._aspect = float(aspect) # raise ValueError if necessary + axes = [self] + for ax in axes: + ax._aspect = aspect + + if adjustable is None: + adjustable = self._adjustable + self.set_adjustable(adjustable, share=share) # Handle sharing. - if adjustable is not None: - self.set_adjustable(adjustable) if anchor is not None: - self.set_anchor(anchor) + self.set_anchor(anchor, share=share) self.stale = True def get_adjustable(self): return self._adjustable - def set_adjustable(self, adjustable): + def set_adjustable(self, adjustable, share=False): """ Define which parameter the Axes will change to achieve a given aspect. - Possible values are: - - ============ ===================================== - value description - ============ ===================================== - 'box' change the physical size of the Axes - 'datalim' change xlim or ylim - 'box-forced' same as 'box', but axes can be shared - ============ ===================================== + Parameters + ---------- + adjustable : ['box' | 'datalim'] + If 'box', change the physical dimensions of the Axes. + If 'datalim', change the ``x`` or ``y`` data limits. - 'box' does not allow axes sharing, as this can cause - unintended side effect. For cases when sharing axes is - fine, use 'box-forced'. + share : bool, optional + If ``True``, apply the settings to all shared Axes. + Default is ``False``. - .. ACCEPTS: [ 'box' | 'datalim' | 'box-forced' ] + .. ACCEPTS: [ 'box' | 'datalim'] See Also -------- matplotlib.axes.Axes.set_aspect for a description of aspect handling. - """ - if adjustable in ('box', 'datalim', 'box-forced'): - if self in self._shared_x_axes or self in self._shared_y_axes: - if adjustable == 'box': - raise ValueError( - 'adjustable must be "datalim" for shared axes') - self._adjustable = adjustable + + Notes + ----- + Shared Axes (of which twinned Axes are a special case) + impose restrictions on how aspect ratios can be imposed. + For twinned Axes, use 'datalim'. For Axes that share both + x and y, use 'box'. Otherwise, either 'datalim' or 'box' + may be used. These limitations are partly a requirement + to avoid over-specification, and partly a result of the + particular implementation we are currently using, in + which the adjustments for aspect ratios are done sequentially + and independently on each Axes as it is drawn. + """ + if adjustable == 'box-forced': + warnings.warn("The 'box-forced' keyword argument is deprecated" + " since 2.2.", cbook.mplDeprecation) + if adjustable not in ('box', 'datalim', 'box-forced'): + raise ValueError("argument must be 'box', or 'datalim'") + if share: + axes = set(self._shared_x_axes.get_siblings(self) + + self._shared_y_axes.get_siblings(self)) else: - raise ValueError('argument must be "box", or "datalim"') + axes = [self] + for ax in axes: + ax._adjustable = adjustable self.stale = True def get_anchor(self): @@ -1369,7 +1385,7 @@ def get_anchor(self): """ return self._anchor - def set_anchor(self, anchor): + def set_anchor(self, anchor, share=False): """ Define the anchor location. @@ -1405,16 +1421,26 @@ def set_anchor(self, anchor): | 'SW' | 'S' | 'SE' | +------+------+------+ + share : bool, optional + If ``True``, apply the settings to all shared Axes. + Default is ``False``. + See Also -------- matplotlib.axes.Axes.set_aspect for a description of aspect handling. """ - if anchor in mtransforms.Bbox.coefs or len(anchor) == 2: - self._anchor = anchor - else: + if not (anchor in mtransforms.Bbox.coefs or len(anchor) == 2): raise ValueError('argument must be among %s' % ', '.join(mtransforms.Bbox.coefs)) + if share: + axes = set(self._shared_x_axes.get_siblings(self) + + self._shared_y_axes.get_siblings(self)) + else: + axes = [self] + for ax in axes: + ax._anchor = anchor + self.stale = True def get_data_ratio(self): @@ -1447,21 +1473,22 @@ def get_data_ratio_log(self): def apply_aspect(self, position=None): """ - Adjust the Axes so that it fulfills its aspect setting. + Adjust the Axes for a specified data aspect ratio. - Depending on `.get_adjustable` and `.get_anchor` this will either - modify the Axes box or the view limits. + Depending on `.get_adjustable` this will modify either the Axes box + (position) or the view limits. In the former case, `.get_anchor` + will affect the position. Notes ----- - This is automatically called on draw. So you won't need to call this - yourself in most cases. One exception may be if you need to update the - Axes before drawing. + This is called automatically when each Axes is drawn. You may need + to call it yourself if you need to update the Axes position and/or + view limits before the Figure is drawn. See Also -------- matplotlib.axes.Axes.set_aspect - for a description of aspect handling. + for a description of aspect ratio handling. matplotlib.axes.Axes.set_adjustable defining the parameter to adjust in order to meet the required aspect. @@ -1500,17 +1527,12 @@ def apply_aspect(self, position=None): else: A = aspect - # Ensure at drawing time that any Axes involved in axis-sharing - # does not have its position changed. - if self in self._shared_x_axes or self in self._shared_y_axes: - if self._adjustable == 'box': - self._adjustable = 'datalim' - warnings.warn( - 'shared axes: "adjustable" is being changed to "datalim"') - figW, figH = self.get_figure().get_size_inches() fig_aspect = figH / figW if self._adjustable in ['box', 'box-forced']: + if self in self._twinned_axes: + raise RuntimeError("Adjustable 'box' is not allowed in a" + " twinned Axes. Use 'datalim' instead.") if aspect_scale_mode == "log": box_aspect = A * self.get_data_ratio_log() else: @@ -1565,15 +1587,15 @@ def apply_aspect(self, position=None): xm = 0 ym = 0 - changex = (self in self._shared_y_axes and - self not in self._shared_x_axes) - changey = (self in self._shared_x_axes and - self not in self._shared_y_axes) - if changex and changey: - warnings.warn("adjustable='datalim' cannot work with shared " - "x and y axes") - return - if changex: + shared_x = self in self._shared_x_axes + shared_y = self in self._shared_y_axes + # Not sure whether we need this check: + if shared_x and shared_y: + raise RuntimeError("adjustable='datalim' is not allowed when both" + " axes are shared.") + + # If y is shared, then we are only allowed to change x, etc. + if shared_y: adjust_y = False else: if xmarg > xm and ymarg > ym: @@ -1581,7 +1603,8 @@ def apply_aspect(self, position=None): (Xmarg < 0 and y_expander > 0)) else: adjy = y_expander > 0 - adjust_y = changey or adjy # (Ymarg > xmarg) + adjust_y = shared_x or adjy # (Ymarg > xmarg) + if adjust_y: yc = 0.5 * (ymin + ymax) y0 = yc - Ysize / 2.0 @@ -4118,9 +4141,17 @@ def get_tightbbox(self, renderer, call_axes_locator=True): def _make_twin_axes(self, *kl, **kwargs): """ - make a twinx axes of self. This is used for twinx and twiny. + Make a twinx axes of self. This is used for twinx and twiny. """ + # Typically, SubplotBase._make_twin_axes is called instead of this. + # There is also an override in axes_grid1/axes_divider.py. + if 'sharex' in kwargs and 'sharey' in kwargs: + raise ValueError("Twinned Axes may share only one axis.") ax2 = self.figure.add_axes(self.get_position(True), *kl, **kwargs) + ## do not touch every thing shared, just this and it's twin. + self.set_adjustable('datalim') + ax2.set_adjustable('datalim') + self._twinned_axes.join(self, ax2) return ax2 def twinx(self): @@ -4183,9 +4214,9 @@ def twiny(self): return ax2 def get_shared_x_axes(self): - """Return a copy of the shared axes Grouper object for x axes.""" + """Return a reference to the shared axes Grouper object for x axes.""" return self._shared_x_axes def get_shared_y_axes(self): - """Return a copy of the shared axes Grouper object for y axes.""" + """Return a reference to the shared axes Grouper object for y axes.""" return self._shared_y_axes diff --git a/lib/matplotlib/axes/_subplots.py b/lib/matplotlib/axes/_subplots.py index 10979bfd2c2f..9c033c728889 100644 --- a/lib/matplotlib/axes/_subplots.py +++ b/lib/matplotlib/axes/_subplots.py @@ -144,9 +144,11 @@ def label_outer(self): def _make_twin_axes(self, *kl, **kwargs): """ - make a twinx axes of self. This is used for twinx and twiny. + Make a twinx axes of self. This is used for twinx and twiny. """ from matplotlib.projections import process_projection_requirements + if 'sharex' in kwargs and 'sharey' in kwargs: + raise ValueError("Twinned Axes may share only one axis.") kl = (self.get_subplotspec(),) + kl projection_class, kwargs, key = process_projection_requirements( self.figure, *kl, **kwargs) @@ -154,6 +156,9 @@ def _make_twin_axes(self, *kl, **kwargs): ax2 = subplot_class_factory(projection_class)(self.figure, *kl, **kwargs) self.figure.add_subplot(ax2) + self.set_adjustable('datalim') + ax2.set_adjustable('datalim') + self._twinned_axes.join(self, ax2) return ax2 _subplot_classes = {} diff --git a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.pdf b/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.pdf index 209842345b46..c16fc9c2d916 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.pdf and b/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.png b/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.png index 9abe25a233cd..7af54d6eefbf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.png and b/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.svg b/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.svg index 668efde6a8ad..ff18e2b4df0b 100644 --- a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.svg +++ b/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.svg @@ -2,7 +2,7 @@ - + - - - - - - - @@ -60,188 +60,188 @@ L 230.4 86.4 +" id="m368fc901b1" style="stroke:#000000;stroke-width:0.5;"/> - + +" id="mc63e59a608" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + - + + + + - + - + - + - + - - - + - - - - + - - - - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -249,209 +249,209 @@ L -4 0 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -459,209 +459,209 @@ L 460.8 86.4 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -669,209 +669,209 @@ L 691.2 86.4 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -879,209 +879,209 @@ L 921.6 86.4 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1089,209 +1089,209 @@ L 1152 86.4 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1299,209 +1299,209 @@ L 230.4 247.282759 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1509,209 +1509,209 @@ L 460.8 247.282759 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1719,209 +1719,209 @@ L 691.2 247.282759 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1929,209 +1929,209 @@ L 921.6 247.282759 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2139,209 +2139,209 @@ L 1152 247.282759 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2349,209 +2349,209 @@ L 230.4 408.165517 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2559,209 +2559,209 @@ L 460.8 408.165517 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2769,209 +2769,209 @@ L 691.2 408.165517 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2979,209 +2979,209 @@ L 921.6 408.165517 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -3189,209 +3189,209 @@ L 1152 408.165517 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -3399,209 +3399,209 @@ L 230.4 569.048276 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -3609,209 +3609,209 @@ L 460.8 569.048276 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -3819,209 +3819,209 @@ L 691.2 569.048276 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -4029,209 +4029,209 @@ L 921.6 569.048276 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -4239,209 +4239,209 @@ L 1152 569.048276 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -4449,209 +4449,209 @@ L 230.4 729.931034 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -4659,209 +4659,209 @@ L 460.8 729.931034 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -4869,209 +4869,209 @@ L 691.2 729.931034 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -5079,209 +5079,209 @@ L 921.6 729.931034 - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -5289,80 +5289,80 @@ L 1152 729.931034 - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index a47486369916..16078e93c14e 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -4439,6 +4439,61 @@ def test_empty_shared_subplots(): assert y1 >= 6 +def test_shared_with_aspect_1(): + # allow sharing one axis + for adjustable in ['box', 'datalim']: + fig, axes = plt.subplots(nrows=2, sharex=True) + axes[0].set_aspect(2, adjustable=adjustable, share=True) + assert axes[1].get_aspect() == 2 + assert axes[1].get_adjustable() == adjustable + + fig, axes = plt.subplots(nrows=2, sharex=True) + axes[0].set_aspect(2, adjustable=adjustable) + assert axes[1].get_aspect() == 'auto' + + +def test_shared_with_aspect_2(): + # Share 2 axes only with 'box': + fig, axes = plt.subplots(nrows=2, sharex=True, sharey=True) + axes[0].set_aspect(2, share=True) + axes[0].plot([1, 2], [3, 4]) + axes[1].plot([3, 4], [1, 2]) + plt.draw() # Trigger apply_aspect(). + assert axes[0].get_xlim() == axes[1].get_xlim() + assert axes[0].get_ylim() == axes[1].get_ylim() + + +def test_shared_with_aspect_3(): + # Different aspect ratios: + for adjustable in ['box', 'datalim']: + fig, axes = plt.subplots(nrows=2, sharey=True) + axes[0].set_aspect(2, adjustable=adjustable) + axes[1].set_aspect(0.5, adjustable=adjustable) + axes[0].plot([1, 2], [3, 4]) + axes[1].plot([3, 4], [1, 2]) + plt.draw() # Trigger apply_aspect(). + assert axes[0].get_xlim() != axes[1].get_xlim() + assert axes[0].get_ylim() == axes[1].get_ylim() + fig_aspect = fig.bbox_inches.height / fig.bbox_inches.width + for ax in axes: + p = ax.get_position() + box_aspect = p.height / p.width + lim_aspect = ax.viewLim.height / ax.viewLim.width + expected = fig_aspect * box_aspect / lim_aspect + assert round(expected, 4) == round(ax.get_aspect(), 4) + + +@pytest.mark.parametrize('twin', ('x', 'y')) +def test_twin_with_aspect(twin): + fig, ax = plt.subplots() + # test twinx or twiny + ax_twin = getattr(ax, 'twin{}'.format(twin))() + ax.set_aspect(5) + ax_twin.set_aspect(2) + assert_array_equal(ax.bbox.extents, + ax_twin.bbox.extents) + + def test_relim_visible_only(): x1 = (0., 10.) y1 = (0., 10.) diff --git a/lib/matplotlib/tests/test_skew.py b/lib/matplotlib/tests/test_skew.py index d36f806e63f3..628506f4db48 100644 --- a/lib/matplotlib/tests/test_skew.py +++ b/lib/matplotlib/tests/test_skew.py @@ -190,14 +190,14 @@ def test_set_line_coll_dash_image(): @image_comparison(baseline_images=['skew_rects'], remove_text=True) def test_skew_rectangle(): - fix, axes = plt.subplots(5, 5, sharex=True, sharey=True, figsize=(16, 12)) + fix, axes = plt.subplots(5, 5, sharex=True, sharey=True, figsize=(8, 8)) axes = axes.flat rotations = list(itertools.product([-3, -1, 0, 1, 3], repeat=2)) - axes[0].set_xlim([-4, 4]) - axes[0].set_ylim([-4, 4]) - axes[0].set_aspect('equal') + axes[0].set_xlim([-3, 3]) + axes[0].set_ylim([-3, 3]) + axes[0].set_aspect('equal', share=True) for ax, (xrots, yrots) in zip(axes, rotations): xdeg, ydeg = 45 * xrots, 45 * yrots @@ -208,4 +208,4 @@ def test_skew_rectangle(): transform=t + ax.transData, alpha=0.5, facecolor='coral')) - plt.subplots_adjust(wspace=0, left=0, right=1, bottom=0) + plt.subplots_adjust(wspace=0, left=0.01, right=0.99, bottom=0.01, top=0.99) diff --git a/lib/mpl_toolkits/axes_grid1/axes_divider.py b/lib/mpl_toolkits/axes_grid1/axes_divider.py index c86b2edd4043..b238e73cc5ec 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_divider.py +++ b/lib/mpl_toolkits/axes_grid1/axes_divider.py @@ -915,9 +915,14 @@ def _make_twin_axes(self, *kl, **kwargs): Need to overload so that twinx/twiny will work with these axes. """ + if 'sharex' in kwargs and 'sharey' in kwargs: + raise ValueError("Twinned Axes may share only one axis.") ax2 = type(self)(self.figure, self.get_position(True), *kl, **kwargs) ax2.set_axes_locator(self.get_axes_locator()) self.figure.add_axes(ax2) + self.set_adjustable('datalim') + ax2.set_adjustable('datalim') + self._twinned_axes.join(self, ax2) return ax2 _locatableaxes_classes = {} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy