2

I have Sea Ice Concentration data around Antarctica that range between -40 and +40 (see attached Figure) but I would like for the values between +10 and -10 to appear white in my map and colorbar because they do not represent sea ice concentration (they appear light green and light blue in the current Figure).

I do not want to exclude them from my array but rather want to assign them a specific color (in this case, white) and keep the jet colorscale for the other values.

Map of Sea Ice Anomaly

I have looked at multiple other questions (i.e. How to change colorbar's color (in some particular value interval)?; Python matplotlib change default color for values exceeding colorbar range; **Reset default matplotlib colormap values after using 'set_under' or 'set_over')

but have not managed to apply those to my case.

I have tried to use 'set under','set over', 'set.bad' but have not managed to get what I would like. I have also tried to create my own colormap but haven't been successful either.

Would anyone be able to help?

Thanks.


UPDATE:

I have adapted the code from 'stackoverflow.com/a/41815114/5103802' (see Updated Code below) but my colors are not white for values [+10 -10] and 'jet' for above +10 and below -10 (see Figure below). The 'tmap' object seems to have messed up the colorscale. Any idea on how I could get the jet colorscale and leave the interval between -10 and +10 white?

Thanks for your help.

SIE Anomaly Update

Updated code:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
from mpl_toolkits.basemap import Basemap, cm, rcParams

HIGH_86 = a.variables['high_86'][:]

n=40 
x = 10 

lower = plt.cm.seismic(np.linspace(1-x, 0, n))
upper = plt.cm.seismic(np.linspace(0, x, n))

white1 = plt.cm.seismic(np.ones(10)*x)
white2 = plt.cm.seismic(np.ones(10)*-(x))


colors = np.vstack((lower, white1, white2, upper))
tmap = matplotlib.colors.LinearSegmentedColormap.from_list('terrain_map_white', colors)

x = HIGH_86

lats = a.variables['latitude'][:]
lons = a.variables['longitude'][:]

lons, lats = np.meshgrid(lons,lats)

fig, ax = plt.subplots()

m2 = Basemap(projection='spstere',boundinglat=-50,lon_0=180,resolution='l')

CS2 = m2.contourf(lons,lats,x,cmap=tmap,latlon=True)
cbar = m2.colorbar(CS2,location='right', pad="12%")

m2.drawparallels(np.arange(-90.,99.,60.),labels=[False,False,False,False])
m2.drawmeridians(np.arange(-180.,180.,90.),labels=[True,False,False,True])
m2.drawcoastlines()
m1.fillcontinents(color='grey')

plt.title('SIE Anomaly')

plt.show() 
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
jb16006
  • 67
  • 1
  • 10
  • How did https://stackoverflow.com/a/41815114/5103802 isn't applied to your case? Seems pretty similar to me, or have I misunderstood your question? – Vinícius Figueiredo Jul 19 '17 at 16:37
  • I haven't been able to apply this to my array. I constantly get this error message: 'ValueError: RGBA values should be within 0-1 range' – jb16006 Jul 19 '17 at 16:41
  • Matplotlib represents colors either as a single floating point number [0, 1] for grayscale, three floats for RGB, or four floats for RGBA. If you put an 8-bit style representation, e.g. (255, 255, 255), it will give you that error. Instead, you'd need (1.0, 1.0, 1.0) for white. That answer shows exactly what you need otherwise. – ahota Jul 19 '17 at 19:18
  • "have not managed to apply those to my case" is not a sufficient problem description. Although the linked question is a duplicate, we cannot close this question as such, as there is no upvote on that answer yet. In any case you would need to clearly state in how far this answer did not help you by showing a [mcve] of the issue. – ImportanceOfBeingErnest Jul 20 '17 at 10:26
  • Sorry, I should have been more clear and added the code. I have modified the question and added the code that does not fully work as well as the updated figure. Thanks for your comments and suggestions – jb16006 Jul 20 '17 at 12:37

1 Answers1

3

I assume you have read the linked question and it's answer. It clearly states

Colormaps are always ranged between 0 and 1.

and further explains how to arrive at a suitable colormap. It thus makes no sense to supply values of 10 or -9 to the colormap.

While you could directly copy the code from the answer here and would receive a decent result, you may of course also refine it to match this specific case, where one may go for 80 colors, 30 from the lower part of the colormap, 30 from the upper part and the remaining 20 in the middle to be white.

n=30
x = 0.5
lower = plt.cm.seismic(np.linspace(0, x, n))
white = plt.cm.seismic(np.ones(80-2*n)*x)
upper = plt.cm.seismic(np.linspace(1-x, 1, n))
colors = np.vstack((lower, white, upper))
tmap = matplotlib.colors.LinearSegmentedColormap.from_list('map_white', colors)

In order to get the jet colormap, which does not have white in it, an array of ones may be used in the middle

n=30
x = 0.5
cmap = plt.cm.jet
lower = cmap(np.linspace(0, x, n))
white = np.ones((80-2*n,4))
upper = cmap(np.linspace(1-x, 1, n))
colors = np.vstack((lower, white, upper))
tmap = matplotlib.colors.LinearSegmentedColormap.from_list('map_white', colors)

enter image description here

Complete code to reproduce the image above:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors

n=30
x = 0.5
cmap = plt.cm.jet
lower = cmap(np.linspace(0, x, n))
white = np.ones((80-2*n,4))
upper = cmap(np.linspace(1-x, 1, n))
colors = np.vstack((lower, white, upper))
tmap = matplotlib.colors.LinearSegmentedColormap.from_list('map_white', colors)

x = np.linspace(0,10)
X,Y = np.meshgrid(x,x)
z = np.sin(X) * np.cos(Y*0.4)*40

fig, ax = plt.subplots() 
im = ax.contourf(z, cmap=tmap, vmin=-40, vmax=40)   
plt.colorbar(im)

plt.show() 
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Thanks for your help. This is exactly what I was looking for. I think I was confused with the 'np.ones(80-2*n)*x)' line but this makes more sense. Thank you for your time and valuable help. Hope this can help other users. – jb16006 Jul 20 '17 at 17:25