13

As one can see in this sample code since 0 is somewhere in the spectrum it is hard to trace which points are negative and which are positive. Although my real plot is more contiguous I wonder if there is a way to seperate negative and postivie values in these clorplots; for example how can I use two different spectrum of colours for positive and negative values.

import numpy as np
from matplotlib import pyplot as plt
a=np.random.randn(2500).reshape((50,50))
plt.imshow(a,interpolation='none')
plt.colorbar()
plt.show()

enter image description here

EDIT With the help of @MultiVAC and looking for solutions I came across this.

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.colors import BoundaryNorm
a=np.random.randn(2500).reshape((50,50))

# define the colormap
cmap = plt.cm.jet
# extract all colors from the .jet map
cmaplist = [cmap(i) for i in range(cmap.N)]
# create the new map
cmap = cmap.from_list('Custom cmap', cmaplist, cmap.N)

# define the bins and normalize
bounds = np.linspace(np.min(a),np.max(a),5)
norm = BoundaryNorm(bounds, cmap.N)

plt.imshow(a,interpolation='none',norm=norm,cmap=cmap)
plt.colorbar()
plt.show()

Still I don't know how to differentiate zero!

enter image description here

Community
  • 1
  • 1
Cupitor
  • 11,007
  • 19
  • 65
  • 91
  • See http://colorbrewer2.org and pick a diverging scale. All of those color maps are in mpl with those names (iirc). – tacaswell Jun 02 '14 at 12:44
  • @tcaswell, sorry I don't follow. I think this is to make bar with custom colors right? The colors don't matter for me. The only thing is the fact to be able to differentiate between positive and negative values vividly. Probably I didn't get the point! – Cupitor Jun 02 '14 at 12:50
  • 1
    I would personally force the scale to be equal. i.e., force the negative minimum to equal the positive maximum...whichever one has the highest absolute value. That, combined with an even number of colors, would make that center value on your colorbar 0. – mauve Jun 02 '14 at 12:54
  • 1
    Look at the diverging color maps, positive in red, negative is blue and 0 is white. That is _exactly_ what you want. – tacaswell Jun 02 '14 at 12:54
  • @mauve, thats not a good idea since my positive and negative values are not close, but I instead inserted a zero in the bin manually. But thanks. – Cupitor Jun 02 '14 at 12:56
  • @tcaswell, thanks a lot. I found this: http://matplotlib.org/examples/color/colormaps_reference.html And I am trying to understand it! – Cupitor Jun 02 '14 at 13:01
  • A great color map to use for this purpose is plt.cm.seismic, as its is used to display waveform data – Reuben Zotz-wilson Jun 23 '20 at 19:31

3 Answers3

7

Ok for the future reference. I used diverging maps as part of it as @tcaswell suggested. You can look to the above links.

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.colors import BoundaryNorm
a=np.random.randn(2500).reshape((50,50))

# define the colormap
cmap = plt.get_cmap('PuOr')

# extract all colors from the .jet map
cmaplist = [cmap(i) for i in range(cmap.N)]
# create the new map
cmap = cmap.from_list('Custom cmap', cmaplist, cmap.N)

# define the bins and normalize and forcing 0 to be part of the colorbar!
bounds = np.arange(np.min(a),np.max(a),.5)
idx=np.searchsorted(bounds,0)
bounds=np.insert(bounds,idx,0)
norm = BoundaryNorm(bounds, cmap.N)

plt.imshow(a,interpolation='none',norm=norm,cmap=cmap)
plt.colorbar()
plt.show()

enter image description here

Cupitor
  • 11,007
  • 19
  • 65
  • 91
  • why don't you just use: `plt.imshow(a,interpolation='none',norm=norm,cmap='PuOr')` ? – tacaswell Jun 02 '14 at 14:10
  • @tcaswell, because when its spectrum its impossible to differentiate between positive and negative. For me the exact sign is important. I think that won't work, right? – Cupitor Jun 02 '14 at 14:13
  • 1
    just make sure the limits are symmetric. If you really care about the sign of very small numbers then threshold and plot it as a binary image. – tacaswell Jun 02 '14 at 14:20
  • Thanks for the help. I took the absolute value and set itself and its minus as bounds with even number of colours(16 in my case). Then I can see the pattern... the boundary is visible as well. – Cupitor Jun 02 '14 at 14:22
1

I arrived at this thread looking for something like what I've written below, hopefully others find it helpful.

import matplotlib.colors as colors
from matplotlib import cm
import numpy as np
import seaborn as sns

with sns.axes_style('whitegrid'):
    rand_normal_y = np.random.randn(1000)
    x = np.arange(0,1000, 1)
    norm = colors.CenteredNorm()
    rand_normal_y_norm = norm(rand_normal_y)
    cmap = cm.coolwarm(rand_normal_y_norm)
    sns.scatterplot(x = x, y = rand_normal_y , c=cmap,  )
    plt.plot(np.linspace(0,1000, 1000), np.repeat(0, 1000), color = 'black', ls = "-")

enter image description here

Kelley Brady
  • 348
  • 2
  • 10
0

there is a lot of good example material on simple self-defined segmented color bars on the matplotlib documentation pages

for instance

http://matplotlib.org/examples/api/colorbar_only.html http://matplotlib.org/examples/pylab_examples/contourf_demo.html

EDIT:

from what I understand, this might be the perfect example for what you are looking for:

http://matplotlib.org/examples/pylab_examples/custom_cmap.html

MultiVAC
  • 354
  • 1
  • 10
  • Thanks. Vote up. All these examples are either discrete or continuous. There is non with two continuous colors for two different signs. Any clues for that? – Cupitor Jun 02 '14 at 12:23
  • @Cupitor : I edited my answer with another example, which is probably more or less what you are looking for – MultiVAC Jun 02 '14 at 13:07
  • somebody gave a down vote probably because you didn't submit answer of your own :). But thanks for the last link. I amlready satisfied with the way I found and I am frustrated. But I will take a look later in details of yours since its quite long. – Cupitor Jun 02 '14 at 13:15