question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Diverging colormaps for scalp plots: Always have "white" as zero

See original GitHub issue

Problem description

I want to compare scalp maps of ERPs across three different tasks. To allow for comparability between the subplots, they all need to share the same colorbar, which I can achieve by the following:

  1. find the maximum value across all tasks and the minimum value across all tasks
  2. pass max and min from step 1. into the vmin and vmax arguments when plotting

The result is as follows (note the colorbar):

figure_1

The problem is, that the white color of the “RdBu_r” colormap should be centered on zero, but this is not the case, as soon as vmin != vmax.

A workaround is to perform an intermediate step between 1. and 2. from above:

  1. find the maximum value across all tasks and the minimum value across all tasks
  2. find the absolute maximum of the max and min identified in step 1.
  3. pass abs_max from step 2. into both the vmin and vmax arguments when plotting

The result is as follows (note the colorbar … vmin == vmax):

figure_2

While it is great to have the white color centered on the zero value, here the problem is that we lose some of the color range into one direction of the scale. In this example, this is visible in the red colors of the positive scale … dark red is at 6 … but the maximum is actually 4, so dark red is never reached.

Potential solutions

One solution to get the full color range and still the zero value centered on white color is described here (also provides a minimal working example to play around with):

http://chris35wills.github.io/matplotlib_diverging_colorbar/

Basically, it is possible by subclassing mpl.color.Normalize

# set the colormap and centre the colorbar
class MidpointNormalize(mpl.colors.Normalize):
    """Normalise the colorbar."""
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        mpl.colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
        return np.ma.masked_array(np.interp(value, x, y), np.isnan(value))

… and then passing this class as an argument to plt.imshow’s parameter called norm:

im = ax.imshow(mydata, vmin=mymin, vmax=mymax, norm=MidpointNormalize(mymin, mymax, 0.))

What are your thoughts on implementing something like this in MNE-Python? How have other people solved this problem?

cc @cbrnr @jona-sassenhagen

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:1
  • Comments:11 (11 by maintainers)

github_iconTop GitHub Comments

3reactions
larsonercommented, Nov 5, 2018

I also prefer the second image. But preferences aside, I think that it’s fine for advanced users to be able to do this sort of tweaking when they know what they are doing – but that we should not promote it because a) it’s likely to be abused more often than used properly and b) complicates the code base.

What I we could consider doing is adding the asymmetric cmap conversion function in https://github.com/mne-tools/mne-python/blob/master/examples/time_frequency/plot_time_frequency_erds.py#L54 to mne.viz.utils with tests, and then use it in the example. That’s a sort of in-between that allows us not to pollute our viz functions with more arguments, but also facilitates code reuse and simplifies things for advanced users.

2reactions
cbrnrcommented, Nov 5, 2018

Yes, I need that all the time, and I have included a function in my ERDS example, which doesn’t subclass and is pretty simple. If it is needed in more places, we could make it available somewhere in the viz package.

Read more comments on GitHub >

github_iconTop Results From Across the Web

matplotlib bwr-colormap, always centered on zero
I want to use the bwr-colormap (blue -> white - red) such that zero is always color-coded in white. -1 should be colorcoded...
Read more >
Choosing Colormaps in Matplotlib
Diverging : change in lightness and possibly saturation of two different colors that meet in the middle at an unsaturated color; should be...
Read more >
Mapping Color to Meaning in Colormap Data Visualizations
The colormaps are the same on the (C) white and (D) black background. The most saturated color is in the middle of the...
Read more >
FAQ — CMasher documentation
Some diverging colormaps in CMasher, like fusion and waterlily, have a white center and linearly decrease to 10% lightness at the edges.
Read more >
Diverging Color Maps for Scientific Visualization (Expanded)
Perceptual experiments show that although a test subject with no prior training will always order grayscale colors in order of luminance (in one...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found