1

I'm trying to produce a plot which uses the same colorscale as the Met Office, so I can easily compare my plots to theirs. An example of theirs is at Here

My current closest effort is here: Here

I appreciate my code is messy - I couldn't find a way to set a color for values above a certain threshold (otherwise it goes white),hence the loop.

I would upload the NetCDF File but I haven't got a high enough rep to do this.

Many, many thanks in advance for any help.

My code for plotting is shown below;

from Scientific.IO.NetCDF import NetCDFFile                     
from mpl_toolkits.basemap import Basemap                     
from matplotlib import pyplot as plt                      
import numpy as np


myfile = NetCDFFile('ERA_Dec_89-94.nc', 'r')   
Lat = NetCDFFile('/home/james/Documents/Lat_Lon_NC_Files/latitudes_d02.nc','r')
Long = NetCDFFile('/home/james/Documents/Lat_Lon_NC_Files/longitudes_d02.nc','r')


XLAT = Lat.variables['XLAT'][:]     
XLONG = Long.variables['XLONG'][:]      
ERA_Data = myfile.variables['Monthlyrain'][:]

plot = np.zeros([1000,1730])

plot[:,:] = np.average(ERA_Data[:,:,:],axis=0)

m = Basemap(projection='merc',resolution='f',llcrnrlat=49,llcrnrlon=-11,urcrnrlat=61,urcrnrlon=3)
m.drawparallels(np.arange(-90., 91., 5.), labels=[1,0,0,0], fontsize=11)
m.drawmeridians(np.arange(-180., 181., 5.), labels=[0,0,0,1], fontsize=11)
m.drawcoastlines()


X, Y = m(XLONG, XLAT)

for i in range(0,1729):
    for j in range(0,999):
         if plot[j,i] >250:
             plot[j,i] = 250.001
         if plot[j,i] < 40:
             plot[j,i] = 40

scale = [40,40.001,60,80,100,125,150,200,250, 250.001]
cs = m.contourf(X,Y,plot,scale, cmap='PuOr')
cbar = m.colorbar(cs, ticks=  [40.0005,50,70,90,112.5,137.5,175,225,250.0005])
cbar.set_ticklabels(['<40','40-60', '60-80', '80-100', '100-125', '125-150', '150-200', '200-250', '>250'])

plt.title('Some Title')
cbar.set_label('Monthly average rainfall (mm)')

print "Finished"

plt.show()
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
J W
  • 617
  • 1
  • 9
  • 28
  • What exactly is the problem? Do you want the colors to match more closely? Do you want to restrict plotting to the land mass? Something else, entirely? The more specific your questions the higher the chance someone has a good answer... – MB-F Feb 08 '16 at 12:20
  • Sorry - the two components I needed help were with the colors to match more closely (I think xnx answered so I'll give this a go), and also how to assign a color to any value that exceeds a threshold (eradicating the need for the loop) – J W Feb 08 '16 at 13:14

2 Answers2

1

If the issue is simply the colormap, you can pick the RGB components of the colors off your screen and turn them into a ListedColormap, mapped to the boundaries of the rainfall in the chart you give as an example. For example,

bounds = [0, 40, 60, 80, 100, 125, 150, 200, 250, 1000]
rgblist = [(51,0,0), (102,51,0), (153,102,51), (204,153,102), (255, 255, 255),
           (204,204,255), (153,153,255), (51,102,255), (0,0,153)]
clist = [[c/255 for  c in rgb] for rgb in rgblist]

from matplotlib import colors
cmap = colors.ListedColormap(clist)
norm = colors.BoundaryNorm(bounds, cmap.N)

ax.imshow(arr, cmap=cmap, norm=norm)
plt.show()
xnx
  • 24,509
  • 11
  • 70
  • 109
  • Thanks for the answer - I'll give this a go! – J W Feb 08 '16 at 13:15
  • Question - where can I find the numbers for each colour? How do I know what values to use for RGBlist? Thanks – J W Feb 08 '16 at 16:46
  • There are lots of tools for doing this. eg on a Mac, in Applications/Utilities/Digital Color Meter is an application for determining the RGB components of the pixel under the cursor. – xnx Feb 08 '16 at 16:56
  • Unfortunately It produces this kind of plot. https://onedrive.live.com/redir?resid=4A445014A6259A95!153585&authkey=!ABQ6TMN4lDKrtTc&v=3&ithint=photo%2cpng – J W Feb 08 '16 at 17:25
  • 'plot = np.clip(plot,40,250) bounds = [0, 40, 60, 80, 100, 125, 150, 200, 250, 300] rgblist = [(51,25,0), (102,51,0), (153,76,0), (239,159,80), (255, 255, 255), (153,204,255), (51,153,255), (0,102,204), (2,2,128)] clist = [[c/255 for c in rgb] for rgb in rgblist] cmap = colors.ListedColormap(clist) norm = colors.BoundaryNorm(bounds, cmap.N) cs = m.contourf(X,Y,plot,bounds, cmap=cmap, norm=norm) cbar = m.colorbar(cs, ticks=[20,50,70,90,112.5,137.5,175,225,275]) cbar.set_ticklabels(['<40','40-60', '60-80', '80-100', '100-125', '125-150', '150-200', '200-250', '>250'])' – J W Feb 08 '16 at 17:26
  • solved - issue was 255 needed to be 255. to avoid division errors in Python 2.x – J W Feb 08 '16 at 21:53
  • Sorry about that - I had my Python 3 hat on. Glad it was helpful. – xnx Feb 09 '16 at 11:48
0

The first part (getting the colors right) was already answered. In order to restrict the values to a certain range you have several options.

  • Use cmap.set_over and cmap.set_under to set out-of-bounds colors, as described here

  • use np.clip instead of the loop to restrict the values to a certian range:

    plot = np.clip(plot, 40, 250)

Community
  • 1
  • 1
MB-F
  • 22,770
  • 4
  • 61
  • 116