Skip to content
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

Color blind-friendly default color cycle #9460

Open
mpetroff opened this issue Oct 17, 2017 · 46 comments
Open

Color blind-friendly default color cycle #9460

mpetroff opened this issue Oct 17, 2017 · 46 comments
Labels
accessibility keep Items to be ignored by the “Stale” Github Action topic: color/color & colormaps

Comments

@mpetroff
Copy link
Contributor

mpetroff commented Oct 17, 2017

The default tab10 qualitative colormap is not color blind friendly, at least with my form of color blindness; I have difficulty telling the second and third colors apart. It would be nice to have a new default qualitative colormap that is color blind friendly, since it's the most commonly used. As Matplotlib 2 is finding increased adoption, I'm often coming across plots that I have difficulty reading due to the default colormap.

I find the perceptually uniform sequential colormaps quite nice, since I can actually read them. It's unfortunate that the same isn't true of the qualitative colormaps. The new Tableau 10 colormap is much better in this regard, but I'm guessing that there are intellectual property concerns that would bar including it.

@jklymak
Copy link
Member

jklymak commented Oct 17, 2017

@mpetroff did you happen to see #9255? I don't know that it'll be made the default, but may help address your concerns...

@WeatherGod
Copy link
Member

WeatherGod commented Oct 17, 2017 via email

@afvincent
Copy link
Contributor

afvincent commented Oct 17, 2017

I think that @mpetroff's point (please correct me if I am wrong) was more that having a not-so-great default (qualitative) color cycle makes a significant number of the plots made with Matplotlib 2 difficult to read for quite a lot of people (including him), as I guess most of the end-users simply rely on the default color cycle. From my own experience, I have to admit that even for non colorblind people, (at least) the first colors of the new default cycle are sometimes difficult to distinguish when printed out in grayscale...

Unfortunately, I guess that changing again the default color cycle is not a plausible option before Matplotlib 3 :/ and that the best we can currently do is indeed to provide nice colorblind-friendly color cycles (like #9255), possibly with more “advertising” about them in the relevant part of the documentation.

Edit: English...

@WeatherGod
Copy link
Member

WeatherGod commented Oct 17, 2017 via email

@mpetroff
Copy link
Contributor Author

@jklymak I had only searched the issues, not the pull requests, so thanks for pointing that out.
@WeatherGod Yes, I meant color cycle. I wrote colormap, since I was looking at the set of colors on the colormap documentation page.

As @afvincent surmised, my main point is that the default color cycle should be color blind-friendly, since many people will just use the default.

@mpetroff mpetroff changed the title Color blind-friendly qualitative colormap Color blind-friendly default color cycle Oct 17, 2017
@dstansby
Copy link
Member

I think this is really important and should be fixed as soon as possible. Are there major problems with changing the default color cycle? Would it be possible to do this in 2.2?

@WeatherGod
Copy link
Member

WeatherGod commented Oct 19, 2017 via email

@mpetroff
Copy link
Contributor Author

I have some ideas for creating a tool for creating color blind-friendly color cycles and quantitative colormaps. The gist of it is to create a color picker that enforces a minimum perceptual distance between the different selected colors both for normal color vision and various degrees of color blindness, such as by using the color blindness simulation and color similarity tools in Colorspacious (these thresholds would be adjustable). I'll see if I can get a prototype together in the next month or so.

@lrq3000
Copy link

lrq3000 commented Jan 29, 2018

@mpetroff This would be awesome! Any news on this?

@dstansby dstansby added this to the v3.0 milestone Jan 29, 2018
@mpetroff
Copy link
Contributor Author

I made significant progress on this in October, building a web app with D3.js and some custom WebGL shaders, but haven't had time to work on it more recently.
screenshot
Most of the functionality is there, but I still need to add the color blindness simulation to the color distance constraint (it's currently only enforcing a minimum standard perceptual distance). I hope to have time to work on this again in the next month or two.

@mpetroff
Copy link
Contributor Author

mpetroff commented Mar 29, 2018

I found time to work on the color cycle picker the last few weeks and was able to mostly finish it. I pushed the code to mpetroff/color-cycle-picker and have a hosted copy at https://colorcyclepicker.mpetroff.net/. Feedback is definitely welcome (but should probably be left on the repository's issue tracker instead of here to avoid clutter).

The picker enforces a minimum perceptual distance between colors in CAM02-UCS and a minimum lightness distance. It also simulates protanomaly, deuteranomaly, and tritanomaly and enforces the minimum perceptual distance for the simulated colors, treating each CVD type separately. Colors are picked from a CAM02-UCS gamut. The minimum distances and the severity of the CVD simulation are all configurable.

screen shot 2018-03-29 at 14 30 33

@PaulEcoffet
Copy link

PaulEcoffet commented Jul 25, 2018

Have you heard of I want hue ? It generates color map in a similar fashion as your color picker but with clustering instead. Might be interesting to have a look at their source code.

@mpetroff
Copy link
Contributor Author

mpetroff commented Aug 3, 2018

It takes a very different approach, and, unfortunately, I find many of the color sets it generates to be hard to distinguish, even when using the "colorblind friendly" preset. The clustering approach is an interesting concept, though.

@tacaswell tacaswell modified the milestones: v3.0, v3.1 Aug 4, 2018
@milankl
Copy link

milankl commented Nov 27, 2018

It would be great to have this as a default color cycle, but in any case, would it be possible to implement this similar to the "C0", "C1", ... colors as "D0", "D1" etc for example? I would find that incredibly handy, as sometimes one knows about the non-colorblindness of the audience, in which case I would prefer the C0,C1,C2 colors as they are easier to separate, whereas in other situations D0,D1,D2 would be better

@ImportanceOfBeingErnest
Copy link
Member

An initiative to introduce the new tableau colors as (non-default) colormap/-cycler is in #12009. It was however not well received.

@jklymak
Copy link
Member

jklymak commented Nov 27, 2018

Just to be clear, folks know we have an rcParam to set the default cycle in your matplotlib.rc or via a style? axes.prop_cycle can be set to any cycle you want. i.e. like in #9255,

# Tableau colorblind 10 palette
 axes.prop_cycle: cycler('color', ['006BA4', 'FF800E', 'ABABAB', '595959', '5F9ED1', 'C85200', '898989', 'A2C8EC', 'FFBC79', 'CFCFCF'])

@mpetroff
Copy link
Contributor Author

mpetroff commented Dec 8, 2018

I've been working on another approach to addressing this issue by combining randomly generated color sets that have an enforced minimum perceptual distance including color vision deficiency simulation with an online survey to collect data on what's aesthetically pleasing:

https://colorcyclesurvey.mpetroff.net/

Obviously, this is only useful if I'm able to collect enough survey responses. Details of the technique are included in a pair of blog posts.

@jklymak
Copy link
Member

jklymak commented Feb 11, 2019

I'm not seeing an action item here so closing, but feel free to reopen if I'm incorrect...

@jklymak jklymak closed this as completed Feb 11, 2019
@mpetroff
Copy link
Contributor Author

The action item would be to change the default color cycle to something that's more colorblind friendly. Unfortunately, it's not yet clear what the better default would be.

@jklymak
Copy link
Member

jklymak commented Feb 11, 2019

OK, fair enough - re-opening and de-milestoning

@jklymak jklymak reopened this Feb 11, 2019
@jklymak jklymak modified the milestones: v3.1.0, unassigned Feb 11, 2019
@mpetroff
Copy link
Contributor Author

I hope to have my analysis and manuscript draft finished this month (although I had hoped to have it finished a year ago, so the timeline could slip). The analysis of the survey data is done, but there's still some more work to be done on additional constraints to improve accessibility.

Also, Wong (2011) just copied, without attribution, the palette previously published by Masataka Okabe & Kei Ito in 2002 (Wayback Machine link). Thus, it shouldn't be referred to as "Wong's palette" (but it's an understandable mistake to make, given the lack of attribution in the article).

@jklymak
Copy link
Member

jklymak commented Apr 10, 2021

The first step of adding a new style with a color-blind color cycle is a pretty low bar of entry. The next step of making it default is going to be more controversial.

@mpetroff
Copy link
Contributor Author

mpetroff commented Jul 7, 2021

I finally finished the manuscript and have the pre-print posted (and the analysis code). The final results are:

Six color:
#5790fc, #f89c20, #e42536, #964a8b, #9c9ca1, #7a21dd

["#5790fc", "#f89c20", "#e42536", "#964a8b", "#9c9ca1", "#7a21dd"]

Eight color:
#1845fb, #ff5e02, #c91f16, #c849a9, #adad7d, #86c8dd, #578dff, #656364

["#1845fb", "#ff5e02", "#c91f16", "#c849a9", "#adad7d", "#86c8dd", "#578dff", "#656364"]

Ten color:
#3f90da, #ffa90e, #bd1f01, #94a4a2, #832db6, #a96b59, #e76300, #b9ac70, #717581, #92dadd

["#3f90da", "#ffa90e", "#bd1f01", "#94a4a2", "#832db6", "#a96b59", "#e76300", "#b9ac70", "#717581", "#92dadd"]

@Baalkikhaal
Copy link

Hope to see this comprehensive piece of work into the next release of matplotlib 😸

@story645
Copy link
Member

A PR contributing the style would probably be welcome.

@mpetroff
Copy link
Contributor Author

I can certainly put together a draft PR. The questions are whether to include the six-color and eight-color cycles in addition to the ten-color cycle and what to call them. My tendency would be to not consider merging anything until the manuscript is accepted (although I don't expect the results to change during review).

@jklymak
Copy link
Member

jklymak commented Jul 13, 2021

My tendency would be to not consider merging anything until the manuscript is accepted

I agree with that - it'd be hard to modify them once part of a release.

@milankl
Copy link

milankl commented Jul 13, 2021

what to call them.

I like, similar to the current "C1","C2",... to have "D1","D2","D3", "E1","E2",... for alternative colour cycles (whichever is set as default) Yours could be D,E,F for example, and more could be added in the future in a similar way?

@jklymak
Copy link
Member

jklymak commented Jul 13, 2021

This would be implemented as a style that would change the meaning of "C0", "C1", etc. https://matplotlib.org/stable/gallery/style_sheets/style_sheets_reference.html

@timhoffm
Copy link
Member

"Cn" is the n-th color of the current/active color/property cycle. There's only one at a time.

Naming: There was an inconclusive discussion on naming colors in #12009 (comment) and following posts.

@ahrendsen
Copy link

So the question is what to name the cycle rather than each of the individual colors? I think there's an obvious choice, and I don't know if you've avoided mentioning it to prevent seeming narcissistic, but I don't think there's any shame.

petroff-colorblind10

If you want to avoid attaching your name to it, maybe something like:

perceptual-colorblind10

These keep with the existing tableau-colorblind10 naming format which I've just discovered is actually a styling and not a color cycle.

My own personal preference would be to stick to the six color cycle. When restricting yourself to keeping things colorblind friendly, I think you quickly come across colors that aren't immediately distinguishable. I see that happening with colors 4, 9, and 10 in the 10 color cycle. I advocate that if your plot has more than 6 different lines that you need to distinguish on it, it's time to reconsider which pieces of data you want your readers to focus on.

@timhoffm
Copy link
Member

timhoffm commented Feb 2, 2022

IMHO (and that's the point in #12009 (comment)) the main issue is that we do not have a good API for named color sequences. We only have ListedColormap, from which one can extract the colors again and use as plt.rcParams['axes.prop_cycle'] = plt.cycler(color=plt.colormaps['Pastel1'].colors). However, ListedColormap carries all the notion of colormapping which is rather confusing because we only need a sequence of colors. I'd rather not add more ListedColormaps.

@mpetroff
Copy link
Contributor Author

mpetroff commented Feb 2, 2022

My tendency would be to avoid using "colorblind" in the name, since there are people who will inevitably decide to treat it as a special case to use only if they are going to show a plot to a colleague who they know is colorblind (and only if they remember). But maybe, I'm being too cynical. Regardless, in an ideal world things would be accessible by default, so there wouldn't be a need to specifically name it as such.

@ahrendsen If I'm understanding your comment about colors 4, 9, and 10 in the ten-color cycle, you find those three color fairly similar. If that is the case, the metric used to choose the order worked as designed, since if only eight items are plotted, the colors are all easily distinguished. It's only when nine or ten items are plotted that it becomes more difficult.

@timhoffm
Copy link
Member

timhoffm commented Feb 3, 2022

in an ideal world things would be accessible by default, so there wouldn't be a need to specifically name it as such.

we are very conservative in changing the default visual aspects of a plot because people are used to how their plots look. Even changing colors can be a source of irritation. For now this would be opt-in. Visual changes are only done in major releases.

@jklymak
Copy link
Member

jklymak commented Feb 3, 2022

we do not have a good API for named color sequences

Do we need one? Where would we use it, and why would it be superior to a bare list of colors?

@mpetroff
Copy link
Contributor Author

mpetroff commented Feb 3, 2022

Visual changes are only done in major releases.

I know. Since we don't live in an ideal world, I'm just being optimistic that the defaults will eventually be accessible.

@timhoffm
Copy link
Member

timhoffm commented Feb 3, 2022

Do we need one? Where would we use it, and why would it be superior to a bare list of colors?

Color sequences themselves can be simple lists of colors. What we don't have it is a central space to store them by name. IMHO we want something like plt.color_sequences[name] --> list of color values.

Use cases are e.g.

plt.rcParams['axes.prop_cycle'] = plt.cycler(color=plt.color_sequences['Pastel1'])

or

for y, color in zip(datasets, plt.color_sequences['Pastel1']):
    plt.plot(x, y, color=color)
    plt.text(x[0], y[0], 'some description', color=color)

In the simplest case color_sequences could be a dict. We just need to define and document it. In practice however, I'd create a similar structures as the ColormapRegistry so that 1) you cannot delete or overwrite builtin color sequences and 2) it returns a copy to prevent accidental in-place modifications of registered sequences.

That's all fairly trivial and I can put together a PR later. But IMHO it's valuable to make that concept explicit.

@timhoffm
Copy link
Member

timhoffm commented Feb 3, 2022

See #22387 for the proposed ColorSequenceRegistry.

@github-actions
Copy link

github-actions bot commented Oct 9, 2023

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!

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Oct 9, 2023
@story645 story645 added keep Items to be ignored by the “Stale” Github Action and removed status: inactive Marked by the “Stale” Github Action labels Oct 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accessibility keep Items to be ignored by the “Stale” Github Action topic: color/color & colormaps
Projects
None yet
Development

No branches or pull requests