Skip to content

Error when setting labelloc='top' #163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ToryDeng opened this issue Apr 17, 2025 · 4 comments
Closed

Error when setting labelloc='top' #163

ToryDeng opened this issue Apr 17, 2025 · 4 comments
Labels
bug Something isn't working enhancement New feature or request
Milestone

Comments

@ToryDeng
Copy link

I'm not sure if I did something wrong, but when I try to set the colorbar's label location to top, I get an error:

import ultraplot as uplt
import numpy as np
import pandas as pd

state = np.random.RandomState(51423)
data = state.normal(size=(3, 3)).cumsum(axis=0)
data = pd.DataFrame(data, columns=["a", "b", "c"])

fig, ax = uplt.subplots()
ax.heatmap(
    data, 
    cmap="ColdHot", 
    colorbar=True, 
    colorbar_kw={"length": 0.3, "label": "LABEL", "labelcolor": "red", "labelloc": "top"}
)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[75], line 10
      7 data = pd.DataFrame(data, columns=["a", "b", "c"])
      9 fig, ax = uplt.subplots()
---> 10 ax.heatmap(
     11     data, 
     12     cmap="ColdHot", 
     13     colorbar=True, 
     14     colorbar_kw={"length": 0.3, "label": "LABEL", "labelcolor": "red", "labelloc": "top"}
     15 )

File /usr/local/miniforge3/envs/experiment/lib/python3.12/site-packages/ultraplot/axes/plot.py:4356, in PlotAxes.heatmap(self, aspect, *args, **kwargs)
   4351 @docstring._snippet_manager
   4352 def heatmap(self, *args, aspect=None, **kwargs):
   4353     """
   4354     %(plot.heatmap)s
   4355     """
-> 4356     obj = self.pcolormesh(*args, default_discrete=False, **kwargs)
   4357     aspect = _not_none(aspect, rc["image.aspect"])
   4358     if self._name != "cartesian":

File /usr/local/miniforge3/envs/experiment/lib/python3.12/site-packages/ultraplot/internals/inputs.py:365, in _preprocess_or_redirect.<locals>._decorator.<locals>._preprocess_or_redirect(self, *args, **kwargs)
    363     kwargs["color"] = color
    364 # Call main function
--> 365 return func(self, *args, **kwargs)

File /usr/local/miniforge3/envs/experiment/lib/python3.12/site-packages/ultraplot/axes/plot.py:4321, in PlotAxes.pcolormesh(self, x, y, z, **kwargs)
   4319 self._fix_patch_edges(m, **edgefix_kw, **kw)
   4320 self._add_auto_labels(m, **labels_kw)
-> 4321 self._update_guide(m, queue_colorbar=False, **guide_kw)
   4322 return m

File /usr/local/miniforge3/envs/experiment/lib/python3.12/site-packages/ultraplot/axes/base.py:1719, in Axes._update_guide(self, objs, legend, legend_kw, queue_legend, colorbar, colorbar_kw, queue_colorbar)
   1717 align = colorbar_kw.pop("align", None)
   1718 queue = colorbar_kw.pop("queue", queue_colorbar)
-> 1719 self.colorbar(objs, loc=colorbar, align=align, queue=queue, **colorbar_kw)

File /usr/local/miniforge3/envs/experiment/lib/python3.12/site-packages/ultraplot/axes/base.py:3118, in Axes.colorbar(self, mappable, values, loc, location, **kwargs)
   3116     self._register_guide("colorbar", (mappable, values), (loc, align), **kwargs)
   3117 else:
-> 3118     return self._add_colorbar(mappable, values, loc=loc, align=align, **kwargs)

File /usr/local/miniforge3/envs/experiment/lib/python3.12/site-packages/ultraplot/internals/warnings.py:118, in _rename_kwargs.<locals>._decorator.<locals>._deprecate_kwargs_wrapper(*args, **kwargs)
    113         key_new = key_new.format(value)
    114     _warn_ultraplot(
    115         f"Keyword {key_old!r} was deprecated in version {version} and may "
    116         f"be removed in {next_release()}. Please use {key_new!r} instead."
    117     )
--> 118 return func_orig(*args, **kwargs)

File /usr/local/miniforge3/envs/experiment/lib/python3.12/site-packages/ultraplot/axes/base.py:1254, in Axes._add_colorbar(self, mappable, values, loc, align, space, pad, width, length, shrink, label, title, reverse, rotation, grid, edges, drawedges, extend, extendsize, extendfrac, ticks, locator, locator_kw, format, formatter, ticklabels, formatter_kw, minorticks, minorlocator, minorlocator_kw, tickminor, ticklen, ticklenratio, tickdir, tickdirection, tickwidth, tickwidthratio, ticklabelsize, ticklabelweight, ticklabelcolor, labelloc, labellocation, labelsize, labelweight, labelcolor, c, color, lw, linewidth, edgefix, rasterized, **kwargs)
   1252     obj.set_label(label)
   1253 if labelloc is not None:
-> 1254     axis.set_label_position(labelloc)
   1255 axis.label.update(kw_label)
   1256 for label in axis.get_ticklabels():

File /usr/local/miniforge3/envs/experiment/lib/python3.12/site-packages/matplotlib/axis.py:2638, in YAxis.set_label_position(self, position)
   2630 """
   2631 Set the label position (left or right)
   2632 
   (...)   2635 position : {'left', 'right'}
   2636 """
   2637 self.label.set_rotation_mode('anchor')
-> 2638 self.label.set_verticalalignment(_api.check_getitem({
   2639     'left': 'bottom', 'right': 'top',
   2640 }, position=position))
   2641 self.label_position = position
   2642 self.stale = True

File /usr/local/miniforge3/envs/experiment/lib/python3.12/site-packages/matplotlib/_api/__init__.py:183, in check_getitem(mapping, **kwargs)
    181     return mapping[v]
    182 except KeyError:
--> 183     raise ValueError(
    184         f"{v!r} is not a valid value for {k}; supported values are "
    185         f"{', '.join(map(repr, mapping))}") from None

ValueError: 'top' is not a valid value for position; supported values are 'left', 'right'

So the error info said the supported values are either left or right. But according to the document of labelloc, I should be able to use top:

  • labelloc, labellocation ({'bottom', 'top', 'left', 'right'}) – The colorbar label location. Inherits from tickloc by default. Default is toward the outside of the subplot for outer colorbars and 'bottom' for inset colorbars.

If I remove this argument, I can plot the colorbar:

ax.heatmap(
    data, 
    cmap="ColdHot", 
    colorbar=True, 
    colorbar_kw={"length": 0.3, "label": "LABEL", "labelcolor": "red"}
)

Image

@ToryDeng
Copy link
Author

I'm using UltraPlot with the latest commit and matplotlib==3.9.4:

!pip show UltraPlot matplotlib
Name: ultraplot
Version: 1.10.1.dev28+g6737b13
Summary: A succinct matplotlib wrapper for making beautiful, publication-quality graphics.
Home-page: 
Author: 
Author-email: Casper van Elteren <[email protected]>, Luke Davis <[email protected]>
License: MIT
Location: /usr/local/miniforge3/envs/experiment/lib/python3.12/site-packages
Requires: matplotlib, numpy
Required-by: 
---
Name: matplotlib
Version: 3.9.4
Summary: Python plotting package
Home-page: https://matplotlib.org
Author: John D. Hunter, Michael Droettboom
Author-email: Unknown <[email protected]>
License: License agreement for matplotlib versions 1.3.0 and later

@cvanelteren
Copy link
Contributor

cvanelteren commented Apr 17, 2025

Hi again!

The output is a bit cryptic but it is due to how the labels are handled inside matplotlib. For colorbars on the left or right, the allowed sides are left and right which is controllable, e.g. a colorbar on the left with labels right or left.

I think what you want is to put the label "on top" for a side colorbar. This can be achieved but requires more fiddling:

import ultraplot as uplt
import numpy as np
import pandas as pd

state = np.random.RandomState(51423)
data = state.normal(size=(3, 3)).cumsum(axis=0)
data = pd.DataFrame(data, columns=["a", "b", "c"])


kw = {
    "length": 0.3,
    "label": "LABEL",
    "labelcolor": "red",
    "loc": "r",
    "labelloc": "right",
}
fig, ax = uplt.subplots()
h = ax.heatmap(
    data,
    cmap="ColdHot",
)
cbar = ax.colorbar(h, **kw)

cbar.ax.set_xlabel("My Label", labelpad=10)
cbar.ax.xaxis.set_label_position("top")
uplt.show(block=1)

That being said, I agree that we should address this by allowing a more user friendly control. PR is welcome otherwise I would have to do this somewhere in the future.

@cvanelteren cvanelteren added bug Something isn't working enhancement New feature or request labels Apr 17, 2025
@cvanelteren cvanelteren modified the milestones: v1.1, v1.11 Apr 17, 2025
@ToryDeng
Copy link
Author

I think what you want is to put the label "on top" for a side colorbar. This can be achieved but requires more fiddling:

Exactly, and thanks for the solution you have provided! I'll try to submit a pull request to implement this feature when I have time 😄

@cvanelteren
Copy link
Contributor

Fixed in main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants