Add location keyword argument to Colorbar by oscargus · Pull Request #23267 · matplotlib/matplotlib · GitHub
Skip to content
Merged
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
25 changes: 25 additions & 0 deletions doc/users/next_whats_new/colorbar_has_location_argument.rst
73 changes: 58 additions & 15 deletions lib/matplotlib/colorbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,14 +246,35 @@ class Colorbar:
alpha : float
The colorbar transparency between 0 (transparent) and 1 (opaque).

orientation : {'vertical', 'horizontal'}
orientation : None or {'vertical', 'horizontal'}
If None, use the value determined by *location*. If both
*orientation* and *location* are None then defaults to 'vertical'.

ticklocation : {'auto', 'left', 'right', 'top', 'bottom'}
The location of the colorbar ticks. The *ticklocation* must match
*orientation*. For example, a horizontal colorbar can only have ticks
at the top or the bottom. If 'auto', the ticks will be the same as
*location*, so a colorbar to the left will have ticks to the left. If
*location* is None, the ticks will be at the bottom for a horizontal
colorbar and at the right for a vertical.

drawedges : bool
Whether to draw lines at color boundaries.

filled : bool

%(_colormap_kw_doc)s

location : None or {'left', 'right', 'top', 'bottom'}
Set the *orientation* and *ticklocation* of the colorbar using a
single argument. Colorbars on the left and right are vertical,
colorbars at the top and bottom are horizontal. The *ticklocation* is
the same as *location*, so if *location* is 'top', the ticks are on
the top. *orientation* and/or *ticklocation* can be provided as well
and overrides the value set by *location*, but there will be an error
for incompatible combinations.

.. versionadded:: 3.7
"""

n_rasterize = 50 # rasterize solids if number of colors >= n_rasterize
Expand All @@ -264,7 +285,7 @@ def __init__(self, ax, mappable=None, *, cmap=None,
alpha=None,
values=None,
boundaries=None,
orientation='vertical',
orientation=None,
ticklocation='auto',
extend=None,
spacing='uniform', # uniform or proportional
Expand All @@ -275,6 +296,7 @@ def __init__(self, ax, mappable=None, *, cmap=None,
extendfrac=None,
extendrect=False,
label='',
location=None,
):

if mappable is None:
Expand Down Expand Up @@ -305,14 +327,23 @@ def __init__(self, ax, mappable=None, *, cmap=None,
mappable.colorbar_cid = mappable.callbacks.connect(
'changed', self.update_normal)

location_orientation = _get_orientation_from_location(location)

Comment thread
oscargus marked this conversation as resolved.
_api.check_in_list(
['vertical', 'horizontal'], orientation=orientation)
[None, 'vertical', 'horizontal'], orientation=orientation)
Comment thread
oscargus marked this conversation as resolved.
_api.check_in_list(
['auto', 'left', 'right', 'top', 'bottom'],
ticklocation=ticklocation)
_api.check_in_list(
['uniform', 'proportional'], spacing=spacing)

if location_orientation is not None and orientation is not None:
if location_orientation != orientation:
raise TypeError(
"location and orientation are mutually exclusive")
else:
orientation = orientation or location_orientation or "vertical"

self.ax = ax
self.ax._axes_locator = _ColorbarAxesLocator(self)

Expand Down Expand Up @@ -365,7 +396,8 @@ def __init__(self, ax, mappable=None, *, cmap=None,
self.__scale = None # linear, log10 for now. Hopefully more?

if ticklocation == 'auto':
ticklocation = 'bottom' if orientation == 'horizontal' else 'right'
ticklocation = _get_ticklocation_from_orientation(
orientation) if location is None else location
self.ticklocation = ticklocation

self.set_label(label)
Expand Down Expand Up @@ -1330,25 +1362,36 @@ def drag_pan(self, button, key, x, y):

def _normalize_location_orientation(location, orientation):
if location is None:
location = _api.check_getitem(
{None: "right", "vertical": "right", "horizontal": "bottom"},
orientation=orientation)
location = _get_ticklocation_from_orientation(orientation)
loc_settings = _api.check_getitem({
"left": {"location": "left", "orientation": "vertical",
"anchor": (1.0, 0.5), "panchor": (0.0, 0.5), "pad": 0.10},
"right": {"location": "right", "orientation": "vertical",
"anchor": (0.0, 0.5), "panchor": (1.0, 0.5), "pad": 0.05},
"top": {"location": "top", "orientation": "horizontal",
"anchor": (0.5, 0.0), "panchor": (0.5, 1.0), "pad": 0.05},
"bottom": {"location": "bottom", "orientation": "horizontal",
"anchor": (0.5, 1.0), "panchor": (0.5, 0.0), "pad": 0.15},
"left": {"location": "left", "anchor": (1.0, 0.5),
"panchor": (0.0, 0.5), "pad": 0.10},
"right": {"location": "right", "anchor": (0.0, 0.5),
"panchor": (1.0, 0.5), "pad": 0.05},
"top": {"location": "top", "anchor": (0.5, 0.0),
"panchor": (0.5, 1.0), "pad": 0.05},
"bottom": {"location": "bottom", "anchor": (0.5, 1.0),
"panchor": (0.5, 0.0), "pad": 0.15},
}, location=location)
loc_settings["orientation"] = _get_orientation_from_location(location)
if orientation is not None and orientation != loc_settings["orientation"]:
# Allow the user to pass both if they are consistent.
raise TypeError("location and orientation are mutually exclusive")
return loc_settings


def _get_orientation_from_location(location):
return _api.check_getitem(
{None: None, "left": "vertical", "right": "vertical",
"top": "horizontal", "bottom": "horizontal"}, location=location)


def _get_ticklocation_from_orientation(orientation):
return _api.check_getitem(
{None: "right", "vertical": "right", "horizontal": "bottom"},
orientation=orientation)


@_docstring.interpd
def make_axes(parents, location=None, orientation=None, fraction=0.15,
shrink=1.0, aspect=20, **kwargs):
Expand Down
31 changes: 31 additions & 0 deletions lib/matplotlib/tests/test_colorbar.py