0

I have a 2d array that I am trying to plot. Im currently using imshow and matplotlib. The array contains values from -4000 to 1. There are no zeros (and nothing closer to zero than 1). Basically it can be imagined as a relief/topography, negative values for beneath ocean level, positive for land.

Now I would like to plot all negative values with a blue colormap (something like the 'Blues' colormap in matplotlib https://matplotlib.org/stable/tutorials/colors/colormaps.html ) and something like 'Oranges' for positive values. So the desired result is an image with all negative values blue, the darker the more negative, and all positive values colored orange with a clear distinction in color, i.e. if possible the cmap should not go all the way to white like 'Blues' but only to a light blue.

I have tried this Colorplot that distinguishes between positive and negative values but I was not able to achieve the desired result. I also checked this https://matplotlib.org/stable/gallery/color/custom_cmap.html#sphx-glr-gallery-color-custom-cmap-py but again it did not result in what I wanted. Another solution I had in mind was turning my array into two arrays, one for positive and one for negative values, and then plot them in the same fig with different cmaps but it always takes the same cmap.

Edit: Here are a few snippets of my attempts, incl. the two suggestions by Jody Klymak and JohanC. The two suggested solutions work pretty well, the only problem I am still getting is that contiguous regions of land=1 are not filled with one color but have white squares in them or are only dotted with orange.

current_cmap = mpl.cm.get_cmap('Blues_r').copy()  
new_cmap = current_cmap
maee = np.ma.masked_where(GD1 == 1, GD1)
new_cmap.set_bad(color='brown')
plt.imshow(maee, cmap=blue_red3, interpolation='bilinear')
plt.colorbar()
plt.show()
plt.clf()

norm = colors.TwoSlopeNorm(vmin=-4000., vcenter=0., vmax=1)
cmap1 = mpl.cm.get_cmap('Blues_r').copy()
cmap1.set_over(color='brown')
plt.imshow(GD1, cmap=cmap1, interpolation='bilinear', vmax=-5)
plt.colorbar()
plt.show()
plt.clf()

cmap = LinearSegmentedColormap.from_list('custom blue', ['blue','lightblue'], N=256)
cmap.set_over('brown')
plt.imshow(GD1, cmap=cmap, vmax=-5)
plt.colorbar()
plt.show()
plt.clf()

plt.contourf(GD1, cmap=cmap1, vmax=-5)
plt.colorbar()
plt.show()
plt.clf()

GD1[GD1 == 1] = 4000
plt.imshow(GD1, cmap='RdBu_r', vmax=4000, vmin=-4000, interpolation='bilinear')
plt.colorbar()
plt.show()
plt.clf()

m1 = np.ma.masked_where(GD1 > 0, GD1)
cmap2 = mpl.cm.get_cmap('Blues_r').copy()
cmap2.set_bad('brown')
plt.imshow(m1, cmap=cmap2, interpolation='bilinear', norm=norm)
plt.colorbar()
plt.show()
plt.clf()

My data comes from datasets that are then put into an array. Sort of along these lines (this can not reproduce my problem):

shape = (180, 360)

# a = np.random.randint(-4000,1,shape).astype(float)
# a[a>-3500] = np.nan
a=np.empty(shape)
a[:] = np.nan
a[0:10,0:360] = 1
a[10:75,100:250] = 1
a[50:75,100:125] = np.nan
a[10:100,50:51] = -4000
a[100:150,60:65] = -500
a[150:152,100:300] = -500


plt.imshow(a,interpolation='nearest')
plt.colorbar()
plt.show()

array = np.ma.masked_invalid(a)

x = np.arange(0, array.shape[1])
y = np.arange(0, array.shape[0])

xx, yy = np.meshgrid(x, y)
x1 = xx[~array.mask]
y1 = yy[~array.mask]
newarr = array[~array.mask]

GD1 = interpolate.griddata((x1, y1), newarr.ravel(), (xx, yy), method='linear')

(interpolation taken from interpolate missing values 2d python). I also had the thought that the interpolation was the problem and not the plotting but when I save the array as a csv and go through the said regions, they don't have any holes, i.e. the regions are filled contiguously with 1s.

paul
  • 21
  • 5
  • 2
    Create a blues colormap to your specification, set vmax to 0 and set the over color to orange to catch all the 1 values. – Jody Klymak Jan 15 '22 at 11:03
  • 2
    You could also use a TwoSlopeNorm, but it really seems you want land to just be one color, so I would just set the over property – Jody Klymak Jan 15 '22 at 11:13
  • Note that writing *"but I was not able to achieve the desired result"* doesn't help people trying to help you. Could you show your best-effort code together with the obtained result. Try to create a minimum reproducible example. `cmap = LinearSegmentedColormap.from_list('custom blue', ['blue','lightblue'], N=256); cmap.set_over('orange'); plt.imshow(..., cmap=cmap, vmax=0)` could work in your case, as suggested by Jody Klymak – JohanC Jan 15 '22 at 15:36
  • Thanks for the suggestions, they are the best I've got so far! – paul Jan 16 '22 at 14:31

0 Answers0