Skip to content

Commit 4a811b0

Browse files
committed
Warn in colorbar() when mappable.axes != figure.gca().
1 parent 2c5c351 commit 4a811b0

File tree

4 files changed

+50
-25
lines changed

4 files changed

+50
-25
lines changed

doc/api/next_api_changes/behaviour.rst

+13
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,16 @@ shape ``(n, 2)`` would plot the first column of *x* against the first column
7070
of *y*, the second column of *x* against the second column of *y*, **and** the
7171
first column of *x* against the third column of *y*. This now raises an error
7272
instead.
73+
74+
Figure.colorbar now warns when the mappable's axes is different from the current axes
75+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
76+
77+
Currently, `.Figure.colorbar` steals space by default from the current axes
78+
to place the colorbar. In a future version, it will steal space from the
79+
mappable's axes instead. In preparation for this change, `.Figure.colorbar`
80+
now emits a warning when the current axes is not the same as the mappable's
81+
axes.
82+
83+
The ``.ax`` attribute to `.ContourSet` is deprecated in favor of
84+
``.axes`` for consistency with artists (even though `.ContourSet` is not an
85+
`.Artist` subclass).

lib/matplotlib/blocking_input.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ class BlockingContourLabeler(BlockingMouseInput):
274274

275275
def __init__(self, cs):
276276
self.cs = cs
277-
BlockingMouseInput.__init__(self, fig=cs.ax.figure)
277+
BlockingMouseInput.__init__(self, fig=cs.axes.figure)
278278

279279
def add_click(self, event):
280280
self.button1(event)

lib/matplotlib/contour.py

+27-22
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ def set_label_props(self, label, text, color):
254254
label.set_text(text)
255255
label.set_color(color)
256256
label.set_fontproperties(self.labelFontProps)
257-
label.set_clip_box(self.ax.bbox)
257+
label.set_clip_box(self.axes.bbox)
258258

259259
def get_text(self, lev, fmt):
260260
"""Get the text of the label."""
@@ -394,7 +394,7 @@ def calc_label_rot_and_inline(self, slc, ind, lw, lc=None, spacing=5):
394394
return rotation, nlc
395395

396396
def _get_label_text(self, x, y, rotation):
397-
dx, dy = self.ax.transData.inverted().transform((x, y))
397+
dx, dy = self.axes.transData.inverted().transform((x, y))
398398
t = text.Text(dx, dy, rotation=rotation,
399399
horizontalalignment='center',
400400
verticalalignment='center')
@@ -405,7 +405,7 @@ def _get_label_clabeltext(self, x, y, rotation):
405405
# the data coordinate and create a label using ClabelText
406406
# class. This way, the rotation of the clabel is along the
407407
# contour line always.
408-
transDataInv = self.ax.transData.inverted()
408+
transDataInv = self.axes.transData.inverted()
409409
dx, dy = transDataInv.transform((x, y))
410410
drotation = transDataInv.transform_angles(np.array([rotation]),
411411
np.array([[x, y]]))
@@ -425,7 +425,7 @@ def _add_label(self, t, x, y, lev, cvalue):
425425
self.labelXYs.append((x, y))
426426

427427
# Add label to plot here - useful for manual mode label selection
428-
self.ax.add_artist(t)
428+
self.axes.add_artist(t)
429429

430430
def add_label(self, x, y, rotation, lev, cvalue):
431431
"""
@@ -469,7 +469,7 @@ def add_label_near(self, x, y, inline=True, inline_spacing=5,
469469
"""
470470

471471
if transform is None:
472-
transform = self.ax.transData
472+
transform = self.axes.transData
473473

474474
if transform:
475475
x, y = transform.transform((x, y))
@@ -488,7 +488,7 @@ def add_label_near(self, x, y, inline=True, inline_spacing=5,
488488
# grab its vertices
489489
lc = active_path.vertices
490490
# sort out where the new vertex should be added data-units
491-
xcmin = self.ax.transData.inverted().transform([xmin, ymin])
491+
xcmin = self.axes.transData.inverted().transform([xmin, ymin])
492492
# if there isn't a vertex close enough
493493
if not np.allclose(xcmin, lc[imin]):
494494
# insert new data into the vertex list
@@ -504,13 +504,13 @@ def add_label_near(self, x, y, inline=True, inline_spacing=5,
504504
lc = paths[segmin].vertices
505505

506506
# In pixel/screen space
507-
slc = self.ax.transData.transform(lc)
507+
slc = self.axes.transData.transform(lc)
508508

509509
# Get label width for rotating labels and breaking contours
510510
lw = self.get_label_width(self.labelLevelList[lmin],
511511
self.labelFmt, self.labelFontSizeList[lmin])
512512
# lw is in points.
513-
lw *= self.ax.figure.dpi / 72.0 # scale to screen coordinates
513+
lw *= self.axes.figure.dpi / 72 # scale to screen coordinates
514514
# now lw in pixels
515515

516516
# Figure out label rotation.
@@ -549,7 +549,7 @@ def labels(self, inline, inline_spacing):
549549
con = self.collections[icon]
550550
trans = con.get_transform()
551551
lw = self.get_label_width(lev, self.labelFmt, fsize)
552-
lw *= self.ax.figure.dpi / 72.0 # scale to screen coordinates
552+
lw *= self.axes.figure.dpi / 72 # scale to screen coordinates
553553
additions = []
554554
paths = con.get_paths()
555555
for segNum, linepath in enumerate(paths):
@@ -765,7 +765,7 @@ def __init__(self, ax, *args,
765765
Keyword arguments are as described in the docstring of
766766
`~.Axes.contour`.
767767
"""
768-
self.ax = ax
768+
self.axes = ax
769769
self.levels = levels
770770
self.filled = filled
771771
self.linewidths = linewidths
@@ -881,7 +881,7 @@ def __init__(self, ax, *args,
881881
alpha=self.alpha,
882882
transform=self.get_transform(),
883883
zorder=zorder)
884-
self.ax.add_collection(col, autolim=False)
884+
self.axes.add_collection(col, autolim=False)
885885
self.collections.append(col)
886886
else:
887887
tlinewidths = self._process_linewidths()
@@ -903,14 +903,14 @@ def __init__(self, ax, *args,
903903
transform=self.get_transform(),
904904
zorder=zorder)
905905
col.set_label('_nolegend_')
906-
self.ax.add_collection(col, autolim=False)
906+
self.axes.add_collection(col, autolim=False)
907907
self.collections.append(col)
908908

909909
for col in self.collections:
910910
col.sticky_edges.x[:] = [self._mins[0], self._maxs[0]]
911911
col.sticky_edges.y[:] = [self._mins[1], self._maxs[1]]
912-
self.ax.update_datalim([self._mins, self._maxs])
913-
self.ax.autoscale_view(tight=True)
912+
self.axes.update_datalim([self._mins, self._maxs])
913+
self.axes.autoscale_view(tight=True)
914914

915915
self.changed() # set the colors
916916

@@ -919,16 +919,21 @@ def __init__(self, ax, *args,
919919
cbook._warn_external('The following kwargs were not used by '
920920
'contour: ' + s)
921921

922+
@cbook.deprecated("3.3")
923+
@property
924+
def ax(self):
925+
return self.axes
926+
922927
def get_transform(self):
923928
"""
924929
Return the :class:`~matplotlib.transforms.Transform`
925930
instance used by this ContourSet.
926931
"""
927932
if self._transform is None:
928-
self._transform = self.ax.transData
933+
self._transform = self.axes.transData
929934
elif (not isinstance(self._transform, mtransforms.Transform)
930935
and hasattr(self._transform, '_as_mpl_transform')):
931-
self._transform = self._transform._as_mpl_transform(self.ax)
936+
self._transform = self._transform._as_mpl_transform(self.axes)
932937
return self._transform
933938

934939
def __getstate__(self):
@@ -1414,9 +1419,9 @@ def _process_args(self, *args, **kwargs):
14141419

14151420
# if the transform is not trans data, and some part of it
14161421
# contains transData, transform the xs and ys to data coordinates
1417-
if (t != self.ax.transData and
1418-
any(t.contains_branch_seperately(self.ax.transData))):
1419-
trans_to_data = t - self.ax.transData
1422+
if (t != self.axes.transData and
1423+
any(t.contains_branch_seperately(self.axes.transData))):
1424+
trans_to_data = t - self.axes.transData
14201425
pts = np.vstack([x.flat, y.flat]).T
14211426
transformed_pts = trans_to_data.transform(pts)
14221427
x = transformed_pts[..., 0]
@@ -1481,9 +1486,9 @@ def _check_xyz(self, args, kwargs):
14811486
convert them to 2D using meshgrid.
14821487
"""
14831488
x, y = args[:2]
1484-
kwargs = self.ax._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)
1485-
x = self.ax.convert_xunits(x)
1486-
y = self.ax.convert_yunits(y)
1489+
kwargs = self.axes._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)
1490+
x = self.axes.convert_xunits(x)
1491+
y = self.axes.convert_yunits(y)
14871492

14881493
x = np.asarray(x, dtype=np.float64)
14891494
y = np.asarray(y, dtype=np.float64)

lib/matplotlib/figure.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -2183,13 +2183,20 @@ def colorbar(self, mappable, cax=None, ax=None, use_gridspec=True, **kw):
21832183
"""
21842184
if ax is None:
21852185
ax = self.gca()
2186+
if hasattr(mappable, "axes") and ax is not mappable.axes:
2187+
cbook.warn_deprecated(
2188+
"3.3", message="Starting from Matplotlib 3.5, colorbar() "
2189+
"will steal space from the mappable's axes, rather than "
2190+
"from the current axes, to place the colorbar. To "
2191+
"silence this warning, explicitly pass the 'ax' argument "
2192+
"to colorbar().")
21862193

21872194
# Store the value of gca so that we can set it back later on.
21882195
current_ax = self.gca()
21892196

21902197
if cax is None:
2191-
if use_gridspec and isinstance(ax, SubplotBase) \
2192-
and (not self.get_constrained_layout()):
2198+
if (use_gridspec and isinstance(ax, SubplotBase)
2199+
and not self.get_constrained_layout()):
21932200
cax, kw = cbar.make_axes_gridspec(ax, **kw)
21942201
else:
21952202
cax, kw = cbar.make_axes(ax, **kw)

0 commit comments

Comments
 (0)