Skip to content

Color maps from function #19258

Open
Open

Description

@Inspirateur

Problem

Would be nice if we could just pass a function as a cmap, and matplotlib would just query it to get a color from a value.

example of usage:

from colorsys import hsl_to_rgb
import matplotlib.pyplot as plt

y = ...  # some data for an histogram
cmap = lambda x: hsl_to_rgb(x, .9, .5)**2
plt.hist(y, cmap=cmap)

Proposed Solution

I don't know how realistic this is but I've just never seen it even suggested when googling.
It certainly feels reasonable to me but I can't tell because I don't know much about the implementation.
If this is not feasible at least this would set a record for future google queries...

Activity

  1. timhoffm commented on Jan 8, 2021

    @timhoffm
    Member

    We currently only have lookup-table based colormaps for continous color scales (see LinearSegmentedColormap). From a design perspective, it would be reasonable to add a FunctionColormap for this. Due to over/under/bad settings a colormap is slightly more than just the continuous mapping with a function.

    Whether we implicitly create the colormap for cmap=lambda x: hsl_to_rgb(x, .9, .5) or if we require explicit creation via cmap=FunctionColormap(lambda x: hsl_to_rgb(x, .9, .5)) is still to be decided separately.

  2. jklymak commented on Jan 8, 2021

    @jklymak
    Member

    We also have ListedColormap which can easily be generated with your function above. https://matplotlib.org/tutorials/colors/colormap-manipulation.html
    that you could make to arbitrary resolution:

    import matplotlib.pyplot as plt
    import numpy as np
    import matplotlib.colors as mcolors
    from colorsys import hls_to_rgb
    
    x = np.linspace(0, 1, 256)
    X = np.zeros((256, 3))
    for i in range(256):
        X[i, :] = hls_to_rgb(x[i], 0.9, 0.5)
    cmap = mcolors.ListedColormap(X)

    (there is probably a way to vectorize that, but...)

    Given the simplicity of this I don't know that I'd be in favour of a third way to do the same thing....

  3. story645 commented on Jan 8, 2021

    @story645
    Member

    I'm in favor of this since it's the straightforward way to do discrete categorical mapping, only conceptual problem is it conflates norm w/ cmap but I dunno that that's a bad thing since the alternative (#6934) gets messy fast.

  4. jklymak commented on Jan 8, 2021

    @jklymak
    Member

    I'm in favor of this since it's the straightforward way to do discrete categorical mapping, only conceptual problem is it conflates norm w/ cmap but I dunno that that's a bad thing since the alternative (#6934) gets messy fast.

    Isn't that what a BoundaryNorm is for?

  5. story645 commented on Jan 8, 2021

    @story645
    Member

    Isn't that what a BoundaryNorm is for?

    BoundaryNorm is for binning data, while categories are basically the edges of those bins (or the center) and therefore requires some hackyness since BoundaryNorm returns a color for every bin rather than for every edge. There also isn't a direct val-color mapping, that's given by separately using a listed colormap that happens to line up w/ the bins.

    categorical color mapping is {'category': 'color'} - the upside also is that this would allow bypassing of the unit system for color while still getting some of the same benefits.

  6. jklymak commented on Jan 8, 2021

    @jklymak
    Member

    BoundaryNorm is for binning data, while categories are basically the edges of those bins (or the center) and therefore requires some hackyness since BoundaryNorm returns a color for every bin rather than for every edge. There also isn't a direct val-color mapping, that's given by separately using a listed colormap that happens to line up w/ the bins.

    I'd still suggest this mapping is the job of a Norm. If we want to call it CategoricalNorm that would be great - it would really just be a trivial extension of BoundaryNorm.

  7. story645 commented on Jan 8, 2021

    @story645
    Member

    But 'NoNorm' handles it natively - the difference is that like in this case it doesn't really make sense to split the color transform into norm and cmap steps since the value: color map is so direct.

  8. timhoffm commented on Jan 9, 2021

    @timhoffm
    Member

    IMHO the categorical colormap discussion is largely orthogonal to the topic of function colorbars.

    Our current colormap classes are restricted to a lookup table. While you can approximate anything with a lookup table, it would be nice to have interpolation-free mapping - at least on the API level. The user should not have to care about discretizing the values by hand.

    Side note: Calling the function for evaluation will usually be slower, but that's a trade-off the user will have to make. One could also add conversions like FunctionColormap(lambda x: hsl_to_rgb(x, .9, .5)).to_listedcolormap(N=256). With a little effort, it should even be possible to automatically create a lookup-table, that has a resolution below the RGB discretization threshold.

    Generally, I agree that mapping from categorical values is the task of a norm. Colormaps are currently always [0, 1] -> (R, G, B) mappings. However, one might discuss if the restriction can be lifted for discrete categorical mappings. But that's another topic.

    That said, there are a number of issues with the current colormap implementation (limitation to LUT, difficult create custom cmaps from data, difficult to create new colormaps from existing colormaps, ...). Function colorbars should probably discussed in a more general colormap redo.

  9. changed the title [-]Colorbars from function[/-] [+]Color maps from function[/+] on Jan 12, 2021
  10. github-actions commented on Sep 27, 2023

    @github-actions

    This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

  11. story645 commented on Sep 27, 2023

    @story645
    Member

    I'm kinda setting as keep but I also think this is probably more or less handled via some composition with https://matplotlib.org/devdocs/api/_as_gen/matplotlib.colors.FuncNorm.html#matplotlib.colors.FuncNorm and possibly would be useful to add an example showing that.

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