Jeff and others,

I have a working solution and a non-working solution. I'm wondering
whether someone can help me understand the problems in the latter.
Please forgive in advance the long post, but all of my code is here.

First, you can get a dataset from :
ftp://sidads.colorado.edu/pub/DATASETS/seaice/polar-stereo/nasateam/near-real-time/north/

and the projection files here:
http://nsidc.org/data/polar_stereo/tools_geo_pixel.html#psn25_pss25_lats

I've made a class for handling this data:
<code>
class NSIDC(object):
    """ Maybe a set of functions for NSIDC data """


    def __init__(self,infile):
        self.infile = infile
        self.data = self.readseaice()

    def readseaice(self):
        """ reads the binary sea ice data and returns
            the header and the data
            see: http://nsidc.org/data/docs/daac/nsidc0051_gsfc_seaice.gd.html
        """
        #use the BinaryFile class to access data
        from pflexpart import BinaryFile
        raw = BinaryFile(self.infile,'r')

        #start reading header values
        """
        File Header
        Bytes    Description
        1-6    Missing data integer value
        7-12    Number of columns in polar stereographic grid
        13-18    Number of rows in polar stereographic grid
        19-24    Unused/internal
        25-30    Latitude enclosed by pointslar stereographic grid
        31-36    Greenwich orientation of polar stereographicic grid
        37-42    Unused/internal
        43-48    J-coordinate of the grid intersection at the pole
        49-54    I-coordinate of the grid intersection at the pole
        55-60    Five-character instrument descriptor (SMMR, SSM/I)
        61-66    Two descriptionriptors of two characters each that
describe the data;
            for example, 07 cn = Nimbus-7 SMMR ice concentration
        67-72    Starting Julian day of grid dayta
        73-78    Starting hour of grid data (if available)
        79-84    Starting minute of grid data (if available)
        85-90    Ending Julian day of grid data
        91-916    Ending hour of grid data (if available)
        97-102    Ending minute of grid             data (if available)
        103-108    Year of grid data
        109-114    Julian day of gridarea(xld data
        115-120    Three-digit channel descriptor (000 for ice concentrationns)
        121-126    Integer scaling factor
        127-150    24-character file name
        151-24    Unused3080-character image title
        231-300   70-character data information (creation date, data
source, etc.)
        """
        hdr = raw.read(np.dtype('a1'),(300))
        header = {}
        header['baddata'] = int(''.join(hdr[:6]))
        header['COLS'] = int(''.join(hdr[6:12]))
        header['ROWS'] = int(''.join(hdr[12:18]))
        header['lat'] = float(''.join(hdr[24:30]))
        header['lon0'] = float(''.join(hdr[30:36]))
        header['jcoord'] = float(''.join(hdr[42:48]))
        header['icoord'] = float(''.join(hdr[48:54]))
        header['instrument'] = ''.join(hdr[54:60])
        header['descr'] = ''.join(hdr[60:66])
        header['startjulday'] = int(''.join(hdr[66:72]))
        header['starthour'] = int(''.join(hdr[72:78]))
        header['startminute'] = int(''.join(hdr[78:84]))
        header['endjulday'] = int(''.join(hdr[84:90]))
        header['endhour'] = int(''.join(hdr[90:96]))
        header['endminute'] = int(''.join(hdr[96:102]))
        header['year'] = int(''.join(hdr[102:108]))
        header['julday'] = int(''.join(hdr[108:114]))
        header['chan'] = int(''.join(hdr[114:120]))
        header['scale'] = int(''.join(hdr[120:126]))
        header['filename'] = ''.join(hdr[126:150])
        header['imagetitle'] = ''.join(hdr[150:230])
        header['datainfo'] = ''.join(hdr[230:300])

        #pdb.set_trace()


        seaiceconc = raw.read(np.uint8,(header['COLS'],header['ROWS']))
        seaiceconc = seaiceconc.T

        return {'header':header,'data':seaiceconc}

    def conv2percentage(self):
        self.seaicepercentage = self.data['data']/2.5

    def classify(self):
        """ classify the data into land, coast, missing, hole """
        data = self.data['data']
        self.header = self.data['header']

        for a in [('land',254),('coast',253),('hole',251),('missing',255)]:
            zeros = np.zeros(data.shape)
            zeros[np.where(data==a[1])] = 1
            exec('self.%s = zeros' % a[0])

        #filter data
        data[data>250] = 0
        self.ice = data

    def geocoordinate(self):
        """ use NSIDC grid files to assign lats/lons to grid.
        see: 
http://nsidc.org/data/polar_stereo/tools_geo_pixel.html#psn25_pss25_lats
        """

        try:
            ROWS = self.header['ROWS']
            COLS = self.header['COLS']
        except:
            raise AttributeError('object needs to have header, \
                    did you run self.classify?')

        datadir =
'/flex_wrk/jfb/RESEARCH_ARCTIC/SEAICE/nsidc0081_ssmi_nrt_seaice'

        lonfile = os.path.join(datadir,'psn25lons_v2.dat')
        lons = np.fromfile(lonfile,dtype=np.dtype('i4'))/100000.
        self.lons = lons.reshape(ROWS,COLS)

        latfile = os.path.join(datadir,'psn25lats_v2.dat')
        lats = np.fromfile(latfile,dtype=np.dtype('i4'))/100000.
        self.lats = lats.reshape(ROWS,COLS)

        areafile = os.path.join(datadir,'psn25area_v2.dat')
        area = np.fromfile(latfile,dtype=np.dtype('i4'))/100000.
        self.area = area.reshape(ROWS,COLS)

    def regrid2globe(self,dres=0.5):
        """ use parameters from http://nsidc.org/data/polar_stereo/ps_grids.html
        to regrid the data onto a lat/lon grid with degree resolution of dres
        """
        a = 6378.273e3
        ec = 0.081816153
        b = a*np.sqrt(1.-ec**2)

        map = Basemap(projection='stere',lat_0=90,lon_0=-45,lat_ts=70,\
                      llcrnrlat=33.92,llcrnrlon=279.96,\
                      urcrnrlon=102.34,urcrnrlat=31.37,\
                      rsphere=(a,b))
        # Basemap coordinate system starts with 0,0 at lower left corner
        nx = self.lons.shape[1]
        ny = self.lats.shape[0]
        xin = np.linspace(map.xmin,map.xmax,nx) # nx is the number of
x points on the grid
        yin = np.linspace(map.ymin,map.ymax,ny) # ny in the number of
y points on the grid
        # 0.5 degree grid
        lons = np.arange(-180,180,0.5)
        lats  = np.arange(-90,90,0.5)
        lons, lats = np.meshgrid(lons,lats)
        xout,yout = map(lons, lats)
        # datain is the data on the nx,ny stereographic grid.
        # masked=True returns masked values for points outside projection grid
        dataout = interp(self.ice, xin, yin,\
                  xout, yout, masked=True)

        x,y = np.meshgrid(xin,yin) # xin, yin are 1-d, x,y are 2-d
(same shape as data)
        map.contourf(x,y,np.flipud(self.ice),clevs=np.arange(0,250,1))

        self.iceglobe = dataout
        self.m = map

</code>

You can use this as follows:

import NSIDC
d = NSIDC('nt_20080827_f17_nrt_n.bin')
d.classify()
d.geocoordinate()
d.regrid2globe()
d.m.drawcoastlines()

This should produce a plot.

QUESTION ONE: It seems possibly I'm slightly off (look at the great
lakes). Any suggestions as to why?

QUESTION TWO: Please, suggested improvements, code review or
simplification is welcome.

Now, on to the NON-WORKING example. I have a function (it's not too
pretty, but it basically takes a bunch of pre-defined regions and
plots a 'grid' of data to them. I've tried to make the necessary edits
so you can use the code as is.

data = d.iceglobe # using the d from the above example
lons = np.arange(-180,180,0.5)
lats = np.arange(-90,90,0.5)

fig,m = plot_grid((lons,lats,data),region=None)


QUESTION THREE: Notice that I'm quite sure the grid is upside down
(you can see again the great lakes and Hudson bay outline in the top
left). However, I've tried a variety of np.fliplr / np.flipud / data.T
combinations, but I can't seem to get it projected properly. Any ideas
here??

QUESTION FOUR: As above in Q2.

<code>

def plot_grid(D,region=None,dres=0.5,
              transform=True,figname=None,fillcontinents=False,
              points=False):
    """ plot an array over a basemap. The required argument "D" is
    either:
    * a tuple of (x,y,z)
    * a tuple with (lon,lat,grid)
    * a tuple with (grid,)

    Usage::

        > FIG = plot_grid(D,**kwargs)

    ===============     ========================================
    keyword             description
    ===============     ========================================
    dres                resolution of the grid
    fillcontinents      fills continents if True
    plotargs            dictionary of plot arguments
    figname             A figurename, if passed will save the
                        figure with figname
    points              set to True if passing a x,y,z matrix of
                        points
    region              A region from :func:`get_base1`
    ===============     ========================================


    """
    print "length of D: %s" % len(D)


    if isinstance(D,np.ndarray):
        assert len(D.shape) == 2, "D grid must be 2d"
    #if len(D)==1:
        #assume full earth grid with dres
        print 'received grid of shape:', D.shape
        if D.shape[0] == 720:
            lons = np.arange(-180,180,dres)
        elif D.shape[0] == 721:
            lons = np.arange(-180,180.01,dres)
        if D.shape[1] == 360:
            lats = np.arange(-90,90,dres)
        elif D.shape[1] == 361:
            lats = np.arange(-90,90.01,dres)
        points = False
        z = D.T

    elif len(D)==3:
        points = True
        x = D[0]
        y = D[1]
        z = D[2]

        if len(z.shape) > 1:
            points = False
            lons = x
            lats = y

    #Set up a basemap

    ## CHANGED THIS HERE FOR THE CODEX ##
    ## Be sure to set region=None                          ##
    if isinstance(region,str):
        print "getting basemap with region: %s" % region
        fig,m = get_base1(region=region)
    else:
        fig = plt.figure()
        ax = fig.add_axes()
        a = 6378.273e3
        ec = 0.081816153
        b = a*np.sqrt(1.-ec**2)
        m = Basemap(projection='stere',lat_0=90,lon_0=-45,lat_ts=70,\
                      llcrnrlat=33.92,llcrnrlon=279.96,\
                      urcrnrlon=102.34,urcrnrlat=31.37,\
                      rsphere=(a,b))

        m.drawcoastlines()




    if points == True:
    # Plot individual data points
        norm = colors.normalize(z.min(),z.max())
        for i in range(len(y)):
            xpt,ypt = m(x[i],y[i])
            cmap = cm.jet(norm(z[i]))
            #cmap = 'k'
            m.plot([xpt],[ypt],'.',color=cmap,markersize=2)
            #plt.plot(x[i],y[i],'.',color=cmap,markersize=2)

    if points == False:
        #transform Z data into projection
        #transform to nx x ny regularly spaced native projection grid
        dx = 2.*np.pi*m.rmajor/len(lons)
        nx = int((m.xmax-m.xmin)/dx)+1; ny = int((m.ymax-m.ymin)/dx)+1
        if transform:
            # Need this if we choose lon,lat approach
            Zt,xx,yy = m.transform_scalar(z,lons,lats,nx,ny,returnxy=True)
        else:
            Zt = z
        print m.projection

        m.imshow(Zt)
        if fillcontinents:
            m.fillcontinents()
        plt.colorbar()
        #plt.imshow(Z)
    if figname != None:
        #plt.ylim([40,90])
        #plt.title('data locations on mercator grid')
        plt.savefig(figname)
    else:
        plt.show()

</code>

------------------------------------------------------------------------------
Nokia and AT&T present the 2010 Calling All Innovators-North America contest
Create new apps & games for the Nokia N8 for consumers in  U.S. and Canada
$10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing
Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store 
http://p.sf.net/sfu/nokia-dev2dev
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Reply via email to