Skip to content

[ENH]: Add Colorbar.{get,set}_{,minor}{locator,formatter} #26896

Closed

Description

@anntzer

Problem

Currently, setting a Colorbar's formatter is done by assigning to the cbar.formatter property. It would be nice if a getter/setter was provided following the standard Matplotlib API (ditto for minor formatters), as that would also allow directly setting the formatter in the constructor (fig.colorbar(..., formatter=...)) or via a general cbar.set(..., formatter=...)

The same issue applies for ticks, although in that case there's actually already set_ticks which already accepts taking a locator as argument; here I guess(?) it should be possible to just let ticks be an alias for locator.

Proposed solution

No response

Activity

  1. jklymak commented on Sep 23, 2023

    @jklymak
    Member

    You can access the yaxis and set these like you do for any other axes, can't you?

  2. anntzer commented on Sep 23, 2023

    @anntzer
    ContributorAuthor

    Sure, though in that case one may even ask why cbar.locator/cbar.formatter even exists as accessing through the axis would likewise work. I think the advantage of having direct/shorthand access is in particular because it is generic wrt orientation (i.e. you can write the same code for horizontal and for vertical axes); what I'm suggesting here is that the shorthand versions should go through getters/setters like many other Matplotlib APIs rather than through properties.

  3. jklymak commented on Sep 24, 2023

    @jklymak
    Member

    I'm not super against adding these, I just think we should decide if we want all these shortcuts, or if we want to make the API more like axes. Another idea is to provide long_axis as a property and then you could do cax.long_axis.set_major_formatter so that the same code could be used for horizontal and vertical

  4. anntzer commented on Sep 24, 2023

    @anntzer
    ContributorAuthor

    Publically exposing long_axis seems fine to me too.

  5. jklymak commented on Sep 27, 2023

    @jklymak
    Member

    Added to the weekly meeting. If he cannot make it, perhaps @timhoffm has an opinion. @greglucas has also though a lot about colorbar.

    My personal take would be that exposing long_axis stops us from having to expose a whole shadow axis API on colorbar, in keeping with the goal of making colorbar a more normal axes.

  6. timhoffm commented on Sep 28, 2023

    @timhoffm
    Member

    My personal take would be that exposing long_axis stops us from having to expose a whole shadow axis API on colorbar, in keeping with the goal of making colorbar a more normal axes.

    This is reasonable and should be done for the arguments given. Maybe there's a better name than long_axis? value_axis, color_axis ...?

    Of course, it does not allow the orignally requested calls ((fig.colorbar(..., formatter=...)) or cbar.set(..., formatter=...)). While they would be nice as well, this indeed means reexposing already existing axis functions. I suggest to not do this right now. If there is a strong desire for that later and the cbar.*_axis access is not sufficient, we can always add that later.

  7. anntzer commented on Sep 28, 2023

    @anntzer
    ContributorAuthor

    I think exposing long_axis (name TBD) would be good enough, and agree that "exposing a whole shadow axis API on colorbar" is not great.

  8. jklymak commented on Sep 28, 2023

    @jklymak
    Member

    main_axis? primary_axis? value_axis and color_axis are good too. Agree that long_axis is probably not intuitive - it's just what we have internally.

  9. jklymak commented on Sep 28, 2023

    @jklymak
    Member

    BTW, I don't think this precludes passing formatter= etc in the colorbar constructor. The only issue there is if we want major/minor to be differentiated.

  10. timhoffm commented on Oct 5, 2023

    @timhoffm
    Member

    Note that there is already a format kwarg in the factory function https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure.colorbar. That applies to the major formatter should be enough as a high level interface for colorbar(). In the rare case that users need more conrol, they should go through the axis.

  11. anntzer commented on Oct 5, 2023

    @anntzer
    ContributorAuthor

    Ah, I had completely missed that API; I agree that's enough for the high-level interface. Perhaps ticks and format could gain aliases (locator and formatter respectively), though, so that they are available under more standard names?

  12. timhoffm commented on Oct 5, 2023

    @timhoffm
    Member

    I'm -0.5 on aliases here. Aliases have a cost (additional code, longer documentation). AFAIK, we don't have other cases where we pass in Formatters or Locators as a configuration parameter, so it's not strictly a consistency topic.

    Maybe even more important: aside from Locators/Formatters the kwargs accept a list of tick positions/a format string. While the present kwargs read well both ways (colorbar(..., format='%.3f', ticks=[1, 2, 3]) and colorbar(..., format=DateFormatter("%Y-%m-%d"), ticks=MaxNLocator(5))), using colorbar(..., formatter='%.3f', locator=[1, 2, 3]) feels a bit odd. - The reason being: The current kwargs format/ticks generically describe semantics, but formatter/locator call for specific specific code representations (classes) of the semantics.

  13. anntzer commented on Oct 5, 2023

    @anntzer
    ContributorAuthor

    The current kwargs format/ticks generically describe semantics, but formatter/locator call for specific specific code representations (classes) of the semantics.

    Note that this is already not really anymore the case, as Axis.set_major_formatter already accepts format strings and arbitrary callables (respectively autoconverting them to StrMethodFormatter and to FuncFormatter). Colorbar tries to accept both %-format strings and {}-format strings, so at least something like formatter="{:.3f}" still only requires an alias, and is consistent with the set_major_formatter API.

  14. timhoffm commented on Oct 5, 2023

    @timhoffm
    Member

    so at least something like formatter="{:.3f}" still only requires an alias, and is consistent with the set_major_formatter API.

    Point taken. Still, I'm unsure whether aliases are worth it. Let's say. I'm -0 on formatter alias now.

  15. tacaswell commented on Oct 12, 2023

    @tacaswell
    Member

    The consensus of the developer call is to expose long_axis as a public property .

  16. timhoffm commented on Oct 24, 2023

    @timhoffm
    Member

    Can you please comment on the reasoning behind going with long_axis? While that name is ok and clear enough to understand, the purely geometrical description is a different logical approach than x/y axis. color_axis or value_axis seem more logically consistent with x/yaxis to me:

    • color_axis: the scatter(x, y, color) inputs go to the xaxis/yaxis/color_axis).
    • value_axis: the type of data in the axis are the values associated with the colors - note that the color name part will typically come in via the Colorbar Axes, I.e. colorbar.value_axis, so that we don’t need an extra “color” in the axis attribute like colorbar.color_value_axis

    Bluntly speaking, long_axis feels a bit like if we had named yaxis vertical_axis instead. It’s clear, but vertical_axis and xaxis do not rhyme.

  17. anntzer commented on Oct 24, 2023

    @anntzer
    ContributorAuthor

    Fwiw value_axis and color_axis both sound good to me, with a slight preference for the former I think.

  18. tacaswell commented on Oct 24, 2023

    @tacaswell
    Member

    The logic against "color_axis" was that it would cross with the things you change through the norm / colormap vs the things you change via the axis.

    The logic against "value_axis" is that everything is a "value". It leaves too much space for users to do "wishful API reading" and have incorrect expectations about what it refers to.

    The logic for "long_axis" is that if two people are looking at a figure with a color bar Q: "which axis of the colorbar are the ticks on?" A: "the long axis" is completely unambiguous.

    With x and y there are very ingrained expectations of what those mean (and we Axes level API with x/y/z in the names). With the color axis there is less ingrained expectations. Rather than try to induce those expectations, go with the super clear geometric naming.


    My preference is long > color > value.

  19. jklymak commented on Oct 24, 2023

    @jklymak
    Member

    long_axis is pretty intuitive - in my view xaxis is only intuitive because of long tradition; certainly the xaxis is often not the xaxis.

    I don't like either color_axis or value_axis for the reasons above, though I find color_axis the most confusing. I'd rank long > value >> color.

    Maybe labelled_axis since that is what is functionally being done here?

  20. timhoffm commented on Oct 26, 2023

    @timhoffm
    Member

    Thanks for the explanation and patience. I want to make sure we have carefully chosen the new API. If there is still a majority for long_axis after weighing the arguments, I'll submit to that.

    The key distinction between a colorbar Axes and and a standard x/y Axes is that the colorbar is conceptually 1D: we only have one axis that contains semantic information. If possible, I'd like to have that captured in the name. labelled_axis basically works, but feels a bit bulky (maybe that is just me always struggling to remember whether there's a double "l" or not).

    I just started to like data_axis. While data is a very generic term and should usually be avoided, maybe we actually want that generic aspect here. We don't need to focus on the exact type of data (one can think label, color, numeric value as one likes). data generically captures the semantic information aspect, contrasting from the other non-data axis.

  21. timhoffm commented on Oct 27, 2025

    @timhoffm
    Member

    I think this is reasonably solved via the long_axis property #27167. You can do cbar.long_axis,set_minor_locator() and the likes.

    @anntzer please reopen if I'm missing something.

  22. anntzer commented on Oct 27, 2025

    @anntzer
    ContributorAuthor

    That's close enough, indeed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions