Skip to content

Commit 9034a37

Browse files
committed
Warn in colorbar() when mappable.axes != figure.gca().
1 parent 9984f9c commit 9034a37

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
@@ -56,3 +56,16 @@ Setting the same property under multiple aliases now raises a TypeError
5656
Previously, calling e.g. ``plot(..., color=somecolor, c=othercolor)`` would
5757
emit a warning because ``color`` and ``c`` actually map to the same Artist
5858
property. This now raises a TypeError.
59+
60+
Figure.colorbar now warns when the mappable's axes is different from the current axes
61+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
62+
63+
Currently, `Figure.colorbar()` steals space by default from the current axes
64+
to place the colorbar. In a future version, it will steal space from the
65+
mappable's axes instead. In preparation for this change, `Figure.colorbar()`
66+
now emits a warning when the current axes is not the same as the mappable's
67+
axes.
68+
69+
The :attr:`.ax` attribute to `ContourSet` is deprecated in favor of
70+
:attr:`.axes` for consistency with artists (even though `ContourSet` is not an
71+
`Artist` subclass).

lib/matplotlib/blocking_input.py

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

274274
def __init__(self, cs):
275275
self.cs = cs
276-
BlockingMouseInput.__init__(self, fig=cs.ax.figure)
276+
BlockingMouseInput.__init__(self, fig=cs.axes.figure)
277277

278278
def add_click(self, event):
279279
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."""
@@ -396,7 +396,7 @@ def calc_label_rot_and_inline(self, slc, ind, lw, lc=None, spacing=5):
396396
return rotation, nlc
397397

398398
def _get_label_text(self, x, y, rotation):
399-
dx, dy = self.ax.transData.inverted().transform((x, y))
399+
dx, dy = self.axes.transData.inverted().transform((x, y))
400400
t = text.Text(dx, dy, rotation=rotation,
401401
horizontalalignment='center',
402402
verticalalignment='center')
@@ -407,7 +407,7 @@ def _get_label_clabeltext(self, x, y, rotation):
407407
# the data coordinate and create a label using ClabelText
408408
# class. This way, the rotation of the clabel is along the
409409
# contour line always.
410-
transDataInv = self.ax.transData.inverted()
410+
transDataInv = self.axes.transData.inverted()
411411
dx, dy = transDataInv.transform((x, y))
412412
drotation = transDataInv.transform_angles(np.array([rotation]),
413413
np.array([[x, y]]))
@@ -427,7 +427,7 @@ def _add_label(self, t, x, y, lev, cvalue):
427427
self.labelXYs.append((x, y))
428428

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

432432
def add_label(self, x, y, rotation, lev, cvalue):
433433
"""
@@ -471,7 +471,7 @@ def add_label_near(self, x, y, inline=True, inline_spacing=5,
471471
"""
472472

473473
if transform is None:
474-
transform = self.ax.transData
474+
transform = self.axes.transData
475475

476476
if transform:
477477
x, y = transform.transform((x, y))
@@ -490,7 +490,7 @@ def add_label_near(self, x, y, inline=True, inline_spacing=5,
490490
# grab its vertices
491491
lc = active_path.vertices
492492
# sort out where the new vertex should be added data-units
493-
xcmin = self.ax.transData.inverted().transform([xmin, ymin])
493+
xcmin = self.axes.transData.inverted().transform([xmin, ymin])
494494
# if there isn't a vertex close enough
495495
if not np.allclose(xcmin, lc[imin]):
496496
# insert new data into the vertex list
@@ -506,13 +506,13 @@ def add_label_near(self, x, y, inline=True, inline_spacing=5,
506506
lc = paths[segmin].vertices
507507

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

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

518518
# Figure out label rotation.
@@ -556,7 +556,7 @@ def labels(self, inline, inline_spacing):
556556
con = self.collections[icon]
557557
trans = con.get_transform()
558558
lw = self.get_label_width(lev, self.labelFmt, fsize)
559-
lw *= self.ax.figure.dpi / 72.0 # scale to screen coordinates
559+
lw *= self.axes.figure.dpi / 72 # scale to screen coordinates
560560
additions = []
561561
paths = con.get_paths()
562562
for segNum, linepath in enumerate(paths):
@@ -777,7 +777,7 @@ def __init__(self, ax, *args,
777777
Keyword arguments are as described in the docstring of
778778
`~axes.Axes.contour`.
779779
"""
780-
self.ax = ax
780+
self.axes = ax
781781
self.levels = levels
782782
self.filled = filled
783783
self.linewidths = linewidths
@@ -893,7 +893,7 @@ def __init__(self, ax, *args,
893893
alpha=self.alpha,
894894
transform=self.get_transform(),
895895
zorder=zorder)
896-
self.ax.add_collection(col, autolim=False)
896+
self.axes.add_collection(col, autolim=False)
897897
self.collections.append(col)
898898
else:
899899
tlinewidths = self._process_linewidths()
@@ -915,14 +915,14 @@ def __init__(self, ax, *args,
915915
transform=self.get_transform(),
916916
zorder=zorder)
917917
col.set_label('_nolegend_')
918-
self.ax.add_collection(col, autolim=False)
918+
self.axes.add_collection(col, autolim=False)
919919
self.collections.append(col)
920920

921921
for col in self.collections:
922922
col.sticky_edges.x[:] = [self._mins[0], self._maxs[0]]
923923
col.sticky_edges.y[:] = [self._mins[1], self._maxs[1]]
924-
self.ax.update_datalim([self._mins, self._maxs])
925-
self.ax.autoscale_view(tight=True)
924+
self.axes.update_datalim([self._mins, self._maxs])
925+
self.axes.autoscale_view(tight=True)
926926

927927
self.changed() # set the colors
928928

@@ -931,16 +931,21 @@ def __init__(self, ax, *args,
931931
cbook._warn_external('The following kwargs were not used by '
932932
'contour: ' + s)
933933

934+
@cbook.deprecated("3.3")
935+
@property
936+
def ax(self):
937+
return self.axes
938+
934939
def get_transform(self):
935940
"""
936941
Return the :class:`~matplotlib.transforms.Transform`
937942
instance used by this ContourSet.
938943
"""
939944
if self._transform is None:
940-
self._transform = self.ax.transData
945+
self._transform = self.axes.transData
941946
elif (not isinstance(self._transform, mtransforms.Transform)
942947
and hasattr(self._transform, '_as_mpl_transform')):
943-
self._transform = self._transform._as_mpl_transform(self.ax)
948+
self._transform = self._transform._as_mpl_transform(self.axes)
944949
return self._transform
945950

946951
def __getstate__(self):
@@ -1426,9 +1431,9 @@ def _process_args(self, *args, **kwargs):
14261431

14271432
# if the transform is not trans data, and some part of it
14281433
# contains transData, transform the xs and ys to data coordinates
1429-
if (t != self.ax.transData and
1430-
any(t.contains_branch_seperately(self.ax.transData))):
1431-
trans_to_data = t - self.ax.transData
1434+
if (t != self.axes.transData and
1435+
any(t.contains_branch_seperately(self.axes.transData))):
1436+
trans_to_data = t - self.axes.transData
14321437
pts = (np.vstack([x.flat, y.flat]).T)
14331438
transformed_pts = trans_to_data.transform(pts)
14341439
x = transformed_pts[..., 0]
@@ -1493,9 +1498,9 @@ def _check_xyz(self, args, kwargs):
14931498
convert them to 2D using meshgrid.
14941499
"""
14951500
x, y = args[:2]
1496-
kwargs = self.ax._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)
1497-
x = self.ax.convert_xunits(x)
1498-
y = self.ax.convert_yunits(y)
1501+
kwargs = self.axes._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)
1502+
x = self.axes.convert_xunits(x)
1503+
y = self.axes.convert_yunits(y)
14991504

15001505
x = np.asarray(x, dtype=np.float64)
15011506
y = np.asarray(y, dtype=np.float64)

lib/matplotlib/figure.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -2203,13 +2203,20 @@ def colorbar(self, mappable, cax=None, ax=None, use_gridspec=True, **kw):
22032203
"""
22042204
if ax is None:
22052205
ax = self.gca()
2206+
if hasattr(mappable, "axes") and ax is not mappable.axes:
2207+
cbook.warn_deprecated(
2208+
"3.3", message="Starting from Matplotlib 3.5, colorbar() "
2209+
"will steal space from the mappable's axes, rather than "
2210+
"from the current axes, to place the colorbar. To "
2211+
"silence this warning, explicitly pass the 'ax' argument "
2212+
"to colorbar().")
22062213

22072214
# Store the value of gca so that we can set it back later on.
22082215
current_ax = self.gca()
22092216

22102217
if cax is None:
2211-
if use_gridspec and isinstance(ax, SubplotBase) \
2212-
and (not self.get_constrained_layout()):
2218+
if (use_gridspec and isinstance(ax, SubplotBase)
2219+
and not self.get_constrained_layout()):
22132220
cax, kw = cbar.make_axes_gridspec(ax, **kw)
22142221
else:
22152222
cax, kw = cbar.make_axes(ax, **kw)

0 commit comments

Comments
 (0)