Source code for mapio.gridbase

#!/usr/bin/env python

import abc
import numpy as np

#third party imports
from dataset import DataSet

[docs]class Grid(DataSet): """ An abstract class to represent lat/lon gridded datasets. Grids are assumed to be pixel-registered - that is, grid coordinates represent the value at the *center* of the cells. """ @abc.abstractmethod #should be a classmethod when instantiated
[docs] def getFileGeoDict(filename): """ Abstract method to return the bounding box, resolution, and shape of a file in whatever Grid format. :param filename: The path to the filename of whatever grid format this is being implemented in. :returns: A geodict specifying the bounding box, resolution, and shape of the data in a file. """ raise NotImplementedError
@abc.abstractmethod #should be a classmethod when instantiated
[docs] def getBoundsWithin(filename,geodict): """ Abstract method to return a geodict for this file that is guaranteed to be inside the input geodict defined, without resampling. :param filename: The name of the file whose resolution/extent should be used. :param geodict: The geodict which is used as the base for finding the bounds for this file guaranteed to be inside of this geodict. :raises NotImplementedError: Always in base class """ raise NotImplementedError
@classmethod def _getPadding(cls,geodict,padbounds,padvalue): xmin,xmax,ymin,ymax = padbounds gxmin,gxmax,gymin,gymax = (geodict['xmin'],geodict['xmax'],geodict['ymin'],geodict['ymax']) xdim = geodict['xdim'] ydim = geodict['ydim'] nrows,ncols = (geodict['nrows'],geodict['ncols']) padleftcols = int((gxmin - xmin)/xdim) padrightcols = int((xmax - gxmax)/xdim) padbottomrows = int((gymin - ymin)/ydim) padtoprows = int((ymax - gymax)/ydim) padleftcols = np.ceil((gxmin - xmin)/xdim) padrightcols = np.ceil((xmax - gxmax)/xdim) padbottomrows = np.ceil((gymin - ymin)/ydim) padtoprows = np.ceil((ymax - gymax)/ydim) #if any of these are negative, set them to zero if padleftcols < 0: padleftcols = 0 if padrightcols < 0: padrightcols = 0 if padbottomrows < 0: padbottomrows = 0 if padtoprows < 0: padtoprows = 0 leftpad = np.ones((nrows,padleftcols))*padvalue rightpad = np.ones((nrows,padrightcols))*padvalue ncols += padrightcols + padleftcols bottompad = np.ones((padbottomrows,ncols))*padvalue toppad = np.ones((padtoprows,ncols))*padvalue #now figure out what the new bounds are geodict['xmin'] = gxmin - padleftcols*xdim geodict['xmax'] = gxmax + padrightcols*xdim geodict['ymin'] = gymin - padbottomrows*ydim geodict['ymax'] = gymax + padtoprows*ydim geodict['ncols'] = geodict['ncols'] + leftpad.shape[1] + rightpad.shape[1] geodict['nrows'] = geodict['nrows'] + bottompad.shape[0] + toppad.shape[0] return (leftpad,rightpad,bottompad,toppad,geodict) @classmethod
[docs] def checkGeoDict(cls,geodict): reqfields = set(['xmin','xmax','ymin','ymax','xdim','ydim','nrows','ncols']) if not reqfields.issubset(set(geodict.keys())): return False return True
@classmethod
[docs] def fixGeoDict(cls,bounds,xdim,ydim,nrows,ncols,preserve='dims'): xmin,xmax,ymin,ymax = bounds mcross = False if xmin > xmax: xmax += 360 mcross = True if preserve == 'dims': ncols = int((xmax-xmin)/xdim) xmax = xmin + ncols*xdim xvar = np.arange(xmin,xmax+(xdim*0.1),xdim) ncols = len(xvar) xdiff = np.abs(xmax - xvar[-1]) #xmax is not guaranteed to be exactly the same as what we just calculated... if mcross: xmax -= 360 nrows = int((ymax-ymin)/ydim) ymax = ymin + nrows*ydim yvar = np.arange(ymin,ymax+(ydim*0.1),ydim) nrows = len(yvar) ydiff = np.abs(ymax - yvar[-1]) #ymax is not guaranteed to be exactly the same as what we just calculated... elif preserve == 'shape': #preserve rows and columns xvar,xdim = np.linspace(xmin,xmax,num=ncols,retstep=True) yvar,ydim = np.linspace(ymin,ymax,num=nrows,retstep=True) xmin = xvar[0] xmax = xvar[-1] ymin = yvar[0] ymax = yvar[-1] else: raise Exception('%s not supported' % preserve) geodict = {'xmin':xmin,'xmax':xmax,'ymin':ymin,'ymax':ymax,'xdim':xdim,'ydim':ydim,'nrows':nrows,'ncols':ncols} return geodict
@abc.abstractmethod
[docs] def blockmean(self,geodict): """ Abstract method to calculate average values for cells of larger size than the current grid. :param geodict: Geodict that defines the new coarser grid. """ raise NotImplementedError
@abc.abstractmethod #should be a classmethod when instantiated
[docs] def loadFromCloud(cls,cloud,geodict): """ Create a grid from a Cloud instance (scattered XY data). :param cloud: A Cloud instance containing scattered XY data. :param geodict: A geodict object where nrows/ncols are optional (will be calculated from bounds/cell dimensions) :returns: An instance of a Grid object. """ raise NotImplementedError
@staticmethod
[docs] def getLatLonMesh(geodict): lons = np.linspace(geodict['xmin'],geodict['xmax'],num=geodict['ncols']) lats = np.linspace(geodict['ymin'],geodict['ymax'],num=geodict['nrows']) lon,lat = np.meshgrid(lons,lats) return (lat,lon)
@abc.abstractmethod
[docs] def getGeoDict(self): """ Return a reference to the geodict inside the Grid :returns: A reference to a dictionary (see constructor). """ raise NotImplementedError('getGeoDict method not implemented in base class')
@abc.abstractmethod
[docs] def getLatLon(self,row,col): """Return geographic coordinates (lat/lon decimal degrees) for given data row and column. :param row: Row dimension index into internal data array. :param col: Column dimension index into internal data array. :returns: Tuple of latitude and longitude. """ raise NotImplementedError('getLatLon method not implemented in base class')
@abc.abstractmethod
[docs] def getRowCol(self,lat,lon,returnFloat=False): """Return data row and column from given geographic coordinates (lat/lon decimal degrees). :param lat: Input latitude. :param lon: Input longitude. :param returnFloat: Boolean indicating whether floating point row/col coordinates should be returned. :returns: Tuple of row and column. """ raise NotImplementedError('getRowCol method not implemented in base class')