|
From: Ian T. <ian...@gm...> - 2012-11-17 14:32:54
|
On 16 November 2012 15:38, Bror Jonsson <bro...@gm...> wrote: > > Oh, I left out a line in the code, very sorry for that. Here is a full > example: > > import numpy as np > import pylab as pl > > #Generate a matrix populated with 1's > fld = np.ones((4,4)) > #Set one corner of the matrix to NaN > fld[:2,:2] = np.nan > #Plot the contourf plot of the matrix > pl.contourf(arange(4),arange(4),fld,colors='b') > #Create a mask where the NaN's are reversed. > mask = np.isnan(fld).astype(np.float) > mask[mask==0] = np.nan > #Plot the contourf of the mask > contourf(arange(4),arange(4),mask,colors='r') > > The cells with values in mask covers the cells with nan's in fld exactly: > > In [102]: print fld > Out[102]: > array([[ nan, nan, 1., 1.], > [ nan, nan, 1., 1.], > [ 1., 1., 1., 1.], > [ 1., 1., 1., 1.]]) > > > In [101]: print mask > Out[101]: > array([[ 1., 1., nan, nan], > [ 1., 1., nan, nan], > [ nan, nan, nan, nan], > [ nan, nan, nan, nan]]) > > > There are, however, a gap between the red and the blue areas in the > figure. Is there a way to make contourf plot mask so that the red patch > extends to 2,2 and covers all cells with 1's in mask? > > Many thanks! > > :-)Bror > Bror, The key to understanding this behaviour is to realise that your fld and mask values are defined at grid points, whereas contour deals with the quads that connect these grid points. If a single grid point is masked out, all 4 quads that the point is a corner of are masked out as far as contour is concerned as you cannot contour a quad that doesn't have all 4 points defined. You could solve your problem using contour but you would have to expand the mask so that each masked point [j,i] was expanded to [j-1:j+1, i-1:i+1]. I cannot think of a cunning numpy way of doing this whilst handling all the edge cases and would have to resort to explicit looping over the indices. There is a better way. From the point mask create a quad mask which is one smaller in each direction. Then use pcolor rather than contour as pcolor takes a quad-centric view of the world. Also, when dealing with masks I use numpy.ma rather than having to handle NaNs. Here is the simplest modification of your code that I can come up with to do what you want: import numpy as np import pylab as pl #Generate a matrix populated with 1's fld = np.ones((4,4)) #Set one corner of the matrix to NaN fld[:2,:2] = np.nan #Create a mask. mask = np.isnan(fld) #Expand mask so that it is a quad mask. mask = 1 - (mask[:-1,:-1] | mask[:-1,1:] | mask[1:,:-1] | mask[1:,1:]) #Create masked array. maskedArray = np.ma.array(np.zeros_like(mask), mask=mask) #Note mask is one smaller than fld in each direction. print 'fld.shape', fld.shape, 'mask.shape', mask.shape pl.contourf(np.arange(4), np.arange(4), fld, colors='b') #pcolor does what you want. Any colormap is chosen that has red as its first color. pl.pcolor(np.arange(4), np.arange(4), maskedArray, cmap='autumn') pl.show() Ian |