Skip to content

Commit 0442dd3

Browse files
committed
Add location keyword argument to Colorbar
1 parent 69cf385 commit 0442dd3

5 files changed

Lines changed: 403 additions & 15 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
``colorbar`` now has a *location* keyword argument
2+
==================================================
3+
4+
The ``colorbar`` method now supports a *location* keyword argument to more
5+
easily position the color bar. This is useful when providing your own inset
6+
axes using the *cax* keyword argument and behaves similar to the case where
7+
axes are not provided (where the *location* keyword is passed on). The
8+
*orientation* and *ticklocation* are no longer required to be provided as they
9+
are determined by *location*. *ticklocation* can still be provided if the
10+
automatic setting is not preferred. (*orientation* can also be provided but
11+
must be compatible with the *location*.)
12+
13+
An example is:
14+
15+
.. plot::
16+
:include-source: true
17+
18+
import matplotlib.pyplot as plt
19+
import numpy as np
20+
rng = np.random.default_rng(19680801)
21+
imdata = rng.random((10, 10))
22+
fig, ax = plt.subplots()
23+
im = ax.imshow(imdata)
24+
fig.colorbar(im, cax=ax.inset_axes([0, 1.05, 1, 0.05]),
25+
location='top')

lib/matplotlib/colorbar.py

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
of the colorbar, as that also determines the *orientation*; passing
4343
incompatible values for *location* and *orientation* raises an exception.
4444
45+
ticklocation : {'auto', 'left', 'right', 'top', 'bottom'}
46+
The location of the colorbar ticks. The *ticklocation* location value must
47+
match *orientation*. For example, a horizontal colorbar can only have ticks
48+
at the top or the bottom.
49+
4550
fraction : float, default: 0.15
4651
Fraction of original axes to use for colorbar.
4752
@@ -249,13 +254,18 @@ class Colorbar:
249254
alpha : float
250255
The colorbar transparency between 0 (transparent) and 1 (opaque).
251256
252-
orientation : {'vertical', 'horizontal'}
257+
orientation : None or {'vertical', 'horizontal'}
258+
If None, use the value determined by *location*. If both
259+
*orientation* and *location* are None, 'vertical'.
253260
254261
ticklocation : {'auto', 'left', 'right', 'top', 'bottom'}
255262
256263
drawedges : bool
257264
258265
filled : bool
266+
267+
location : None or {'left', 'right', 'top', 'bottom'}
268+
259269
%(_colormap_kw_doc)s
260270
"""
261271

@@ -267,7 +277,7 @@ def __init__(self, ax, mappable=None, *, cmap=None,
267277
alpha=None,
268278
values=None,
269279
boundaries=None,
270-
orientation='vertical',
280+
orientation=None,
271281
ticklocation='auto',
272282
extend=None,
273283
spacing='uniform', # uniform or proportional
@@ -278,6 +288,7 @@ def __init__(self, ax, mappable=None, *, cmap=None,
278288
extendfrac=None,
279289
extendrect=False,
280290
label='',
291+
location=None,
281292
):
282293

283294
if mappable is None:
@@ -308,14 +319,23 @@ def __init__(self, ax, mappable=None, *, cmap=None,
308319
mappable.colorbar_cid = mappable.callbacks.connect(
309320
'changed', self.update_normal)
310321

322+
location_orientation = _get_orientation_from_location(location)
323+
311324
_api.check_in_list(
312-
['vertical', 'horizontal'], orientation=orientation)
325+
[None, 'vertical', 'horizontal'], orientation=orientation)
313326
_api.check_in_list(
314327
['auto', 'left', 'right', 'top', 'bottom'],
315328
ticklocation=ticklocation)
316329
_api.check_in_list(
317330
['uniform', 'proportional'], spacing=spacing)
318331

332+
if location_orientation is not None and orientation is not None:
333+
if location_orientation != orientation:
334+
raise TypeError(
335+
"location and orientation are mutually exclusive")
336+
else:
337+
orientation = orientation or location_orientation or "vertical"
338+
319339
self.ax = ax
320340
self.ax._axes_locator = _ColorbarAxesLocator(self)
321341

@@ -374,7 +394,8 @@ def __init__(self, ax, mappable=None, *, cmap=None,
374394
self.__scale = None # linear, log10 for now. Hopefully more?
375395

376396
if ticklocation == 'auto':
377-
ticklocation = 'bottom' if orientation == 'horizontal' else 'right'
397+
ticklocation = _get_ticklocation_from_orientation(
398+
orientation) if location is None else location
378399
self.ticklocation = ticklocation
379400

380401
self.set_label(label)
@@ -1335,25 +1356,36 @@ def drag_pan(self, button, key, x, y):
13351356

13361357
def _normalize_location_orientation(location, orientation):
13371358
if location is None:
1338-
location = _api.check_getitem(
1339-
{None: "right", "vertical": "right", "horizontal": "bottom"},
1340-
orientation=orientation)
1359+
location = _get_ticklocation_from_orientation(orientation)
13411360
loc_settings = _api.check_getitem({
1342-
"left": {"location": "left", "orientation": "vertical",
1343-
"anchor": (1.0, 0.5), "panchor": (0.0, 0.5), "pad": 0.10},
1344-
"right": {"location": "right", "orientation": "vertical",
1345-
"anchor": (0.0, 0.5), "panchor": (1.0, 0.5), "pad": 0.05},
1346-
"top": {"location": "top", "orientation": "horizontal",
1347-
"anchor": (0.5, 0.0), "panchor": (0.5, 1.0), "pad": 0.05},
1348-
"bottom": {"location": "bottom", "orientation": "horizontal",
1349-
"anchor": (0.5, 1.0), "panchor": (0.5, 0.0), "pad": 0.15},
1361+
"left": {"location": "left", "anchor": (1.0, 0.5),
1362+
"panchor": (0.0, 0.5), "pad": 0.10},
1363+
"right": {"location": "right", "anchor": (0.0, 0.5),
1364+
"panchor": (1.0, 0.5), "pad": 0.05},
1365+
"top": {"location": "top", "anchor": (0.5, 0.0),
1366+
"panchor": (0.5, 1.0), "pad": 0.05},
1367+
"bottom": {"location": "bottom", "anchor": (0.5, 1.0),
1368+
"panchor": (0.5, 0.0), "pad": 0.15},
13501369
}, location=location)
1370+
loc_settings["orientation"] = _get_orientation_from_location(location)
13511371
if orientation is not None and orientation != loc_settings["orientation"]:
13521372
# Allow the user to pass both if they are consistent.
13531373
raise TypeError("location and orientation are mutually exclusive")
13541374
return loc_settings
13551375

13561376

1377+
def _get_orientation_from_location(location):
1378+
return _api.check_getitem(
1379+
{None: None, "left": "vertical", "right": "vertical",
1380+
"top": "horizontal", "bottom": "horizontal"}, location=location)
1381+
1382+
1383+
def _get_ticklocation_from_orientation(orientation):
1384+
return _api.check_getitem(
1385+
{None: "right", "vertical": "right", "horizontal": "bottom"},
1386+
orientation=orientation)
1387+
1388+
13571389
@_docstring.interpd
13581390
def make_axes(parents, location=None, orientation=None, fraction=0.15,
13591391
shrink=1.0, aspect=20, **kwargs):
2.02 KB
Loading

0 commit comments

Comments
 (0)