10000 DOC: selecting individual colors from a colormap by rcomer · Pull Request #27678 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

DOC: selecting individual colors from a colormap #27678

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

Merged
merged 1 commit into from
Jan 21, 2024

Conversation

rcomer
Copy link
Member
@rcomer rcomer commented Jan 20, 2024

PR summary

Closes #27671 by adding an example to show using colormaps in places where we need discrete sets of colours.

The plots themselves could be more interesting, but I guess the more interesting we make them the more code there will be to distract from the main point.

PR checklist

@github-actions github-actions bot added the Documentation: examples files in galleries/examples label Jan 20, 2024
n_lines = 21

cmap = mpl.colormaps.get_cmap('plasma').resampled(n_lines)
colors = cmap.colors
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I note that the colors attribute does not appear in the API docs. So perhaps I am not supposed to use it and should do cmap(i) instead? I find the attribute quite intuitive though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a bit confusing to me. Colors won't work at all on linear segmented colormaps, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah OK, better go back to cmap(i) then.

Comment on lines 58 to 61
# - `matplotlib.colormaps.get_cmap`
# - `matplotlib.colors.Colormap`
# - `matplotlib.colors.Colormap.resampled`
# - `maplotlib.rc_context`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my local build, get_cmap and rc_context failed to make a link and I have no idea why.


Once we have hold of a `.Colormap` instance, the individual colors can be accessed
simply using its ``.colors`` attribute. If we want a specific number of colors taken
at regular intervals from a continuous colormap, we can create a new colormap using the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found this a little confusing because you don't use it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use what? resampled is used on line 22.

n_lines = 21

cmap = mpl.colormaps.get_cmap('plasma').resampled(n_lines)
colors = cmap.colors
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a bit confusing to me. Colors won't work at all on linear segmented colormaps, right?

@rcomer rcomer force-pushed the colors-from-colormap branch from 7dbb453 to d39e083 Compare January 20, 2024 16:25
Copy link
Member
@jklymak jklymak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems useful. I think it would benefit from linking to colormap-manipulation which I think is where we explain the different colormaps in enough detail.

I wonder if you need to caveat n_lines with the fact that colors will get repeated for ListedColormaps if n_lines is larger than the lookup table? Maybe more detail than needed here

@rcomer rcomer force-pushed the colors-from-colormap branch from d39e083 to 3140966 Compare January 20, 2024 17:29
@rcomer
Copy link
Member Author
rcomer commented Jan 20, 2024

I wonder if you need to caveat n_lines with the fact that colors will get repeated for ListedColormaps if n_lines is larger than the lookup table? Maybe more detail than needed here

I did not know that. I think it might fit better in the newly linked colormap-manipulation though, since that's already discussing different types of colormap, as well as the resampled method.

Comment on lines 34 to 35
# Alternatively, we may want to replace the default color cycle with a different
# discrete set of colors. We can use a `~cycler.cycler` instance within `.rcParams` to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to dribble comments, but I found "Alternatively" poor guidance here, as I immediately thought it would be "alternative" was of getting the colors, whereas its an alternative way of passing the colors to plot.

Maybe something like:

Suggested change
# Alternatively, we may want to replace the default color cycle with a different
# discrete set of colors. We can use a `~cycler.cycler` instance within `.rcParams` to
# Instead of specifying the colors one by one in ``plot``, we can create a temporary `~cycler.cycler` that has the list of colors specified.

@rcomer
Copy link
Member Author
rcomer commented Jan 20, 2024

Current iteration

Copy link
Member
@jklymak jklymak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small clarification. I find the integer indexing surprising for colormaps, because you need to know cmap.N (or resample) before you can use the integers. But you can take or leave the clarification, and self merge when you think ready.

@rcomer rcomer force-pushed the colors-from-colormap branch from 2dbd0f1 to 95dbab0 Compare January 21, 2024 10:12
@rcomer rcomer merged commit 09eab5b into matplotlib:main Jan 21, 2024
@rcomer rcomer added this to the v3.8-doc milestone Jan 21, 2024
@rcomer
Copy link
Member Author
rcomer commented Jan 21, 2024

@meeseeksdev backport to v3.8.2-doc
@meeseeksdev backport to v3.8.x

meeseeksmachine pushed a commit to meeseeksmachine/matplotlib that referenced this pull request Jan 21, 2024
meeseeksmachine pushed a commit to meeseeksmachine/matplotlib that referenced this pull request Jan 21, 2024
@rcomer rcomer deleted the colors-from-colormap branch January 21, 2024 12:19
greglucas added a commit that referenced this pull request Jan 21, 2024
…678-on-v3.8.2-doc

Backport PR #27678 on branch v3.8.2-doc (DOC: selecting individual colors from a colormap)
greglucas added a commit that referenced this pull request Jan 21, 2024
…678-on-v3.8.x

Backport PR #27678 on branch v3.8.x (DOC: selecting individual colors from a col
57A7
ormap)
Copy link
Member
@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rcomer Thanks for creating the example! And sorry for being late to the party.

I've addedsome comments that you may or may not want to consider, even though the PR is already merged.

Comment on lines +24 to +31
cmap = mpl.colormaps.get_cmap('plasma').resampled(n_lines)

fig, ax = plt.subplots(layout='constrained')

for i in range(n_lines):
ax.plot([0, i], color=cmap(i))

plt.show()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have used

colors = mpl.colormaps['plasma'](np.linspace(0, 1, n_lines))

for i, color in enumerate(colors):
    ax.plot([0, i], color=color)

in particular

  • mpl.colormaps.get_cmap('plasma') is somewhat unconventional. The ColormapRegistry supports item access for colormap names. That feels more natural to me for just looking up a colormap on the registry. get_cmap() is similar but has additional functionality like Colormap-passthrough and default-lookup for None. I would either use mpl.colormaps['plasma'] or just use the pyplot function plt.get_cmap('plasma') to save the import mpl (technically you could also do plt.colormaps['plasma'] because we re-export the registry in pyplot).
  • I didn't even know that one can index colormaps by integer, and I find it a bit harder to understand. First, one has to know the integer-indexing (which feels half an implementation detail to me because I regard the colormaps as conceptually continuous). Second, looking up the color is now split beween creating the resampled cmap (l.24) and later looking up the color (l.29). They only make sense together but are quite separted. The vectorized approach of mapping an array of floats to colors is more explicit. Note also that you can easily sample parts of the colormap in the vectorized lookup, e.g. mpl.colormaps['RdYlGn'](np.linspace(0.5, 1, n_lines)) to sample only the upper half of a diverging colormap.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @timhoffm. It seems you and @jklymak are in agreement about the integer indexing being “suprising” so we should probably change it!

I did start with plt.get_cmap but I thought we were generally supposed to avoid pyplot for most things.

Comment on lines +41 to +42
cmap = mpl.colormaps.get_cmap('Dark2')
colors = cmap(range(cmap.N)) # cmap.N is number of unique colors in the colormap
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The qualitative colormaps are ListedColormaps and obtaining all their colors can be done easier via:

colors = mpl.colormaps['Dark2'].colors

Note that this is a significantly different task than selecting N equidistant colors from a continuous map. I'm not clear on the focus we want to set here: #27671 was primaily "I have N lines and want differnt colors", which is the first part here. My comment on a context example was the idea one should mention in the context of the above task that you can make a context so that you don't have to carry the colors explicitly. That's a different direction than focussing on various aspects of getting color values. Both ways are possbile, but we should not mix them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I started by using the colors attribute for both examples (plasma is also a ListedColorMap), but changed it in response to one of @jklymak’s comments.

My thinking for using a qualitative colormap: if someone is changing the color cycle in rcParams then they are using it across several plots which might need different numbers of colors, so getting a specific number of colors out of a continuous map would make less sense there. This is in the context where the user was also asking for an increase in the default cycle.

@rcomer
Copy link
Member Author
rcomer commented Jan 22, 2024

@timhoffm apologies, I should have waited to give you a chance to comment before merging since you had put ideas in the issue.

@tacaswell
Copy link
Member

@rcomer Better to keep things moving in this case than to let it fall off everyone's radar!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation: examples files in galleries/examples
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ENH]: Adding more colours to represent the graphs
4 participants
0