Пример #1
0
    def clim_from_histogram(self, **kwargs):
        '''Estimate min and max pixel values from histogram

        if ratio=1.0, simply the minimum and maximum values are returned.
        if 0 < ratio < 1.0, get the histogram of the pixel values.
        Then get rid of (1.0-ratio)/2 from the both sides and
        return the minimum and maximum values.

        Parameters
        -----------
        Any of Figure.__init__() parameters

        Returns
        --------
        clim : numpy array 2D ((3x2) or (1x2))
            minimum and maximum pixel values for each band

        '''
        # modify default values
        self._set_defaults(kwargs)
        ratio = self.ratio

        # find masked pixels if mask_array and mask_lut provided
        masked = None
        if self.mask_array is not None and self.mask_lut is not None:
            masked = np.zeros(self.mask_array.shape, 'bool')
            for lutVal in self.mask_lut:
                masked = masked + (self.mask_array == lutVal)

        # create a ratio list for each band
        if not (isinstance(ratio, float) or isinstance(ratio, int)):
            raise OptionError('Incorrect input ratio %s' % str(ratio))

        # create a ratio list for each band
        if ratio <= 0 or ratio > 1:
            raise OptionError('Incorrect input ratio %s' % str(ratio))

        # create a 2D array and set min and max values
        clim = [[0] * self.array.shape[0], [0] * self.array.shape[0]]
        for iBand in range(self.array.shape[0]):
            bandArray = self.array[iBand, :, :]
            # remove masked data
            if masked is not None:
                bandArray = bandArray[masked == 0]
            # remove nan, inf
            bandArray = bandArray[np.isfinite(bandArray)]
            # get percentile
            percentileMin = 100 * (1 - ratio) / 2.
            percentileMax = 100 * (1 - (1 - ratio) / 2.)
            if bandArray.size > 0:
                clim[0][iBand] = np.percentile(bandArray, percentileMin)
                clim[1][iBand] = np.percentile(bandArray, percentileMax)
            else:
                clim[0][iBand], clim[1][iBand] = 0, 1

        self.color_limits = clim
        return clim
Пример #2
0
    def _get_geotransform(self, extentDic):
        '''
        the new coordinates and raster size are calculated based on
        the given extentDic.

        Parameters
        -----------
        extentDic : dictionary
            includes 'te' key and 'ts' or 'tr' key

        Raises
        -------
        OptionError : occurs when maxX - minX < 0 or maxY - minY < 0
        OptionError : occurs when the given resolution is larger than
                     width or height.

        Returns
        --------
        coordinate : list with 6 float
            GeoTransform

        rasterSize : list with two int
            rasterXSize and rasterYSize

        '''
        # recalculate GeoTransform based on extent option
        minX = extentDic['te'][0]
        minY = extentDic['te'][1]
        maxX = extentDic['te'][2]
        maxY = extentDic['te'][3]
        cornerX = minX
        cornerY = maxY
        width = maxX - minX
        height = maxY - minY
        if width <= 0 or height <= 0:
            raise OptionError('The extent is illegal. '
                              '"-te xMin yMin xMax yMax" ')

        if 'tr' in extentDic.keys():
            resolutionX = extentDic['tr'][0]
            resolutionY = -(extentDic['tr'][1])
            if (width < resolutionX or height < resolutionY):
                raise OptionError('"-tr" is too large. '
                                  'width is %s, height is %s ' %
                                  (str(width), str(height)))
            rasterXSize = width / resolutionX
            rasterYSize = abs(height / resolutionY)
        else:
            rasterXSize = extentDic['ts'][0]
            rasterYSize = extentDic['ts'][1]
            resolutionX = width / rasterXSize
            resolutionY = -abs(height / rasterYSize)

        # create a list for GeoTransform
        coordinates = [cornerX, resolutionX, 0.0, cornerY, 0.0, resolutionY]

        return coordinates, int(rasterXSize), int(rasterYSize)
Пример #3
0
    def get_dataset(self, ds):
        ''' Open Dataset '''
        if ds is None:
            try:
                ds = Dataset(self.fileName)
            except:
                raise OptionError('Cannot open %s' % self.fileName)
        elif type(ds) != Dataset:
            raise OptionError('Input ds is not netCDF.Dataset!')

        return ds
Пример #4
0
    def _get_auto_ticks(self, ticks, grid):
        ''' Automatically create a list of lon or lat ticks from number of list

        Parameters
        ----------
            ticks : int or list
                number or location of ticks
            grid : ndarray
                grid with lon or lat
        Returns
        -------
            ticks : list
                location of ticks

        '''
        gridMin = grid.min()
        gridMax = grid.max()

        if type(ticks) is int:
            ticks = np.linspace(gridMin, gridMax, ticks)
        elif type(ticks) in [list, tuple]:
            newTicks = []
            for tick in ticks:
                if tick >= gridMin and tick <= gridMax:
                    newTicks.append(tick)
            ticks = newTicks
        else:
            raise OptionError('Incorrect type of ticks')

        return ticks
Пример #5
0
    def get_layer_datetime(self, date, datetimes):
        ''' Get datetime of the matching layer and layer number '''

        if len(datetimes) == 1 or date is None:
            layerNumber = 0
        else:
            # find closest layer
            datetimeResolution = np.abs(datetimes[0] - datetimes[1])
            date = np.datetime64(date).astype('M8[s]')
            matchingDateDiff = np.min(np.abs(datetimes - date))
            if matchingDateDiff > datetimeResolution:
                raise OptionError('Date %s is out of range' % date)
            layerNumber = np.argmin(np.abs(datetimes - date))

        layerDate = datetimes[layerNumber]

        return layerNumber, layerDate
Пример #6
0
    def __init__(self,
                 srs=None,
                 ext=None,
                 ds=None,
                 lon=None,
                 lat=None,
                 name='',
                 logLevel=None):
        '''Create Domain from GDALDataset or string options or lat/lon grids

        d = Domain(srs, ext)
            Size, extent and spatial reference is given by strings
        d = Domain(ds=GDALDataset):
            Size, extent and spatial reference is copied from input
            GDAL dataset
        d = Domain(srs, ds=GDALDataset):
            Spatial reference is given by srs, but size and extent is
            determined
            from input GDAL dataset
        d = Domain(lon=lonGrid, lat=latGrid)
            Size, extent and spatial reference is given by two grids

        Parameters
        ----------
        srs : PROJ4 or EPSG or WKT or NSR or osr.SpatialReference()
            Input parameter for nansat.NSR()
        ext : string
            some gdalwarp options + additional options
            [http://www.gdal.org/gdalwarp.html]
            Specifies extent, resolution / size
            Available options: (('-te' or '-lle') and ('-tr' or '-ts'))
            (e.g. '-lle -10 30 55 60 -ts 1000 1000' or
            '-te 100 2000 300 10000 -tr 300 200')
            -tr resolutionx resolutiony
            -ts sizex sizey
            -te xmin ymin xmax ymax
            -lle lonmin latmin lonmax latmax
        ds : GDAL dataset
        lat : Numpy array
            Grid with latitudes
        lon : Numpy array
            Grid with longitudes
        name : string, optional
            Name to be added to the Domain object
        logLevel : int, optional, default=30
            level of logging

        Raises
        -------
        ProjectionError : occurs when Projection() is empty
            despite it is required for creating extentDic.
        OptionError : occures when the arguments are not proper.

        Modifies
        ---------
        self.vrt.datasetset : dataset in memory
            dataset is created based on the input arguments

        See Also
        ---------
        Nansat.reproject()
        [http://www.gdal.org/gdalwarp.html]
        [http://trac.osgeo.org/proj/]
        [http://spatialreference.org/]
        [http://www.gdal.org/ogr/osr_tutorial.html]

        '''
        # set default attributes
        self.logger = add_logger('Nansat', logLevel)
        self.name = name

        self.logger.debug('ds: %s' % str(ds))
        self.logger.debug('srs: %s' % srs)
        self.logger.debug('ext: %s' % ext)

        # If too much information is given raise error
        if ds is not None and srs is not None and ext is not None:
            raise OptionError('Ambiguous specification of both '
                              'dataset, srs- and ext-strings.')

        # choose between input opitons:
        # ds
        # ds and srs
        # srs and ext
        # lon and lat

        # if only a dataset is given:
        #     copy geo-reference from the dataset
        if ds is not None and srs is None:
            self.vrt = VRT(gdalDataset=ds)

        # If dataset and srs are given (but not ext):
        #   use AutoCreateWarpedVRT to determine bounds and resolution
        elif ds is not None and srs is not None:
            srs = NSR(srs)
            tmpVRT = gdal.AutoCreateWarpedVRT(ds, None, srs.wkt)
            if tmpVRT is None:
                raise ProjectionError('Could not warp the given dataset'
                                      'to the given SRS.')
            else:
                self.vrt = VRT(gdalDataset=tmpVRT)

        # If SpatialRef and extent string are given (but not dataset)
        elif srs is not None and ext is not None:
            srs = NSR(srs)
            # create full dictionary of parameters
            extentDic = self._create_extentDic(ext)

            # convert -lle to -te
            if 'lle' in extentDic.keys():
                extentDic = self._convert_extentDic(srs, extentDic)

            # get size/extent from the created extet dictionary
            [geoTransform, rasterXSize,
             rasterYSize] = self._get_geotransform(extentDic)
            # create VRT object with given geo-reference parameters
            self.vrt = VRT(srcGeoTransform=geoTransform,
                           srcProjection=srs.wkt,
                           srcRasterXSize=rasterXSize,
                           srcRasterYSize=rasterYSize)
            self.extentDic = extentDic
        elif lat is not None and lon is not None:
            # create self.vrt from given lat/lon
            self.vrt = VRT(lat=lat, lon=lon)
        else:
            raise OptionError('"dataset" or "srsString and extentString" '
                              'or "dataset and srsString" are required')

        self.logger.debug('vrt.dataset: %s' % str(self.vrt.dataset))
Пример #7
0
    def _create_extentDic(self, extentString):
        '''Create a dictionary from extentString

        Check if extentString is proper.
            * '-te' and '-lle' take 4 numbers.
            * '-ts' and '-tr' take 2 numbers.
            * the combination should be ('-te' or '-lle') and ('-ts' or '-tr')
        If it is proper, create a dictionary
        Otherwise, raise the error.

        Parameters
        -----------
        extentString : string
            '-te xMin yMin xMax yMax',
            '-tr xResolution yResolution',
            '-ts width height',
            '-lle minlon minlat maxlon maxlat'

        Returns
        --------
        extentDic : dictionary
            has key ('te' or 'lle') and ('tr' or 'ts') and their values.

        Raises
        -------
        OptionError : occurs when the extentString is improper

        '''
        extentDic = {}

        # Find -re text
        str_tr = re.findall('-tr\s+[-+]?\d*[.\d*]*\s+[-+]?\d*[.\d*]*\s?',
                            extentString)
        if str_tr != []:
            # Check the number of -tr elements
            elm_str = str(str_tr[0].rstrip())
            elms_str = elm_str.split(None)
            if len(elms_str) != 3 or elms_str[2] == '-':
                raise OptionError('Domain._create_extentDic():'
                                  '-tr is used as'
                                  '"-tr xResolution yResolution"')
            # Add the key and value to extentDic
            extentString = extentString.replace(str_tr[0], '')
            trElem = str(str_tr).split(None)
            trkey = trElem[0].translate(string.maketrans('', ''), "[]-'")
            if trkey != '':
                elements = []
                for i in range(2):
                    elements.append(
                        float(trElem[i + 1].translate(string.maketrans('', ''),
                                                      "'[]'")))
                extentDic[trkey] = elements

        # Find -ts text
        str_ts = re.findall('-ts\s+[-+]?\d*[.\d*]*\s+[-+]?\d*[.\d*]*\s?',
                            extentString)
        if str_ts != []:
            # Check the number of -ts elements
            elm_str = str(str_ts[0].rstrip())
            elms_str = elm_str.split(None)
            if len(elms_str) != 3 or elms_str[2] == '-':
                raise OptionError('Domain._create_extentDic(): '
                                  '"-ts" is used as "-ts width height"')
            # Add the key and value to extentDic
            extentString = extentString.replace(str_ts[0], '')
            tsElem = str(str_ts).split(None)
            tskey = tsElem[0].translate(string.maketrans('', ''), "[]-'")
            if tskey != '':
                elements = []
                for i in range(2):
                    elements.append(
                        float(tsElem[i + 1].translate(string.maketrans('', ''),
                                                      "[]'")))
                extentDic[tskey] = elements

        # Find -te text
        str_te = re.findall(
            '-te\s+[-+]?\d*[.\d*]*\s+[-+]?\d*[.\d*]*\s'
            '+[-+]?\d*[.\d*]*\s+[-+]?\d*[.\d*]*\s?', extentString)
        if str_te != []:
            # Check the number of -te elements
            elm_str = str(str_te[0].rstrip())
            elms_str = elm_str.split(None)
            if len(elms_str) != 5:
                raise OptionError('Domain._create_extentDic():'
                                  '-te is used as "-te xMin yMin xMax yMax"')
            # Add the key and value to extentDic
            extentString = extentString.replace(str_te[0], '')
            teElem = str(str_te).split(None)
            tekey = teElem[0].translate(string.maketrans('', ''), "[]-'")
            if tekey != '':
                elements = []
                for i in range(4):
                    elements.append(
                        float(teElem[i + 1].translate(string.maketrans('', ''),
                                                      "[]'")))
                extentDic[tekey] = elements

        # Find -lle text
        str_lle = re.findall(
            '-lle\s+[-+]?\d*[.\d*]*\s+[-+]?\d*[.\d*]*\s'
            '+[-+]?\d*[.\d*]*\s+[-+]?\d*[.\d*]*\s?', extentString)
        if str_lle != []:
            # Check the number of -lle elements
            elm_str = str(str_lle[0].rstrip())
            elms_str = elm_str.split(None)
            if len(elms_str) != 5:
                raise OptionError('Domain._create_extentDic():'
                                  '-lle is used as '
                                  '"-lle minlon minlat maxlon maxlat"')
            # Add the key and value to extentDic
            extentString = extentString.replace(str_lle[0], '')
            lleElem = str(str_lle).split(None)
            llekey = lleElem[0].translate(string.maketrans('', ''), "[]-'")
            if llekey != '':
                elements = []
                for i in range(4):
                    elements.append(
                        float(lleElem[i + 1].translate(
                            string.maketrans('', ''), "[]'")))
                extentDic[llekey] = elements

        result = re.search('\S', extentString)
        # if there are unnecessary letters, give an error
        if result is not None:
            raise OptionError(
                'Domain._create_extentDic():'
                'extentString is not redable :', extentString)

        # check if one of '-te' and '-lle' is given
        if ('lle' not in extentDic) and ('te' not in extentDic):
            raise OptionError('Domain._create_extentDic():'
                              '"-lle" or "-te" is required.')
        elif ('lle' in extentDic) and ('te' in extentDic):
            raise OptionError('Domain._create_extentDic():'
                              '"-lle" or "-te" should be chosen.')

        # check if one of '-ts' and '-tr' is given
        if ('ts' not in extentDic) and ('tr' not in extentDic):
            raise OptionError('Domain._create_extentDic():'
                              '"-ts" or "-tr" is required.')
        elif ('ts' in extentDic) and ('tr' in extentDic):
            raise OptionError('Domain._create_extentDic():'
                              '"-ts" or "-tr" should be chosen.')
        return extentDic
Пример #8
0
    def write_kml_image(self, kmlFileName=None, kmlFigureName=None):
        '''Create KML file for already projected image

        Write Domain Image into KML-file for GoogleEarth

        Parameters
        -----------
        kmlFileName : string, optional
            Name of the KML-file to generate from the current Domain
        kmlFigureName : string, optional
            Name of the projected image stored in .png format

        Examples
        ---------
        # First of all, reproject an image into Lat/Lon WGS84
          (Simple Cylindrical) projection
        # 1. Cancel previous reprojection
        # 2. Get corners of the image and the pixel resolution
        # 3. Create Domain with stereographic projection,
        #    corner coordinates and resolution 1000m
        # 4. Reproject
        # 5. Write image
        # 6. Write KML for the image
        n.reproject() # 1.
        lons, lats = n.get_corners() # 2.
        srsString = '+proj=latlong +datum=WGS84 +ellps=WGS84 +no_defs'
        extentString = '-lle %f %f %f %f -ts 3000 3000'
        % (min(lons), min(lats), max(lons), max(lats))
        d = Domain(srs=srsString, ext=extentString) # 3.
        n.reproject(d) # 4.
        n.write_figure(fileName=figureName, bands=[3], clim=[0,0.15],
                       cmapName='gray', transparency=0) # 5.
        n.write_kml_image(kmlFileName=oPath + fileName + '.kml',
                          kmlFigureName=figureName) # 6.

        '''
        # test input options
        if kmlFileName is None:
            raise OptionError('kmlFileName(%s) is wrong' % (kmlFileName))

        if kmlFigureName is None:
            raise OptionError('kmlFigureName(%s) is not specified' %
                              (kmlFigureName))

        # open KML, write header
        kmlFile = file(kmlFileName, 'wt')
        kmlFile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
        kmlFile.write('<kml xmlns="http://www.opengis.net/kml/2.2" '
                      'xmlns:gx="http://www.google.com/kml/ext/2.2" '
                      'xmlns:kml="http://www.opengis.net/kml/2.2" '
                      'xmlns:atom="http://www.w3.org/2005/Atom">\n')
        kmlFile.write('<GroundOverlay>\n')
        kmlFile.write('    <name>%s</name>\n' % kmlFileName)
        kmlFile.write('    <Icon>\n')
        kmlFile.write('        <href>%s</href>\n' % kmlFigureName)
        kmlFile.write('        <viewBoundScale>0.75</viewBoundScale>\n')
        kmlFile.write('    </Icon>\n')

        # get corner of the domain and add to KML
        domainLon, domainLat = self.get_corners()

        kmlFile.write('    <LatLonBox>\n')
        kmlFile.write('        <north>%s</north>\n' % max(domainLat))
        kmlFile.write('        <south>%s</south>\n' % min(domainLat))
        kmlFile.write('        <east>%s</east>\n' % max(domainLon))
        kmlFile.write('        <west>%s</west>\n' % min(domainLon))
        kmlFile.write('    </LatLonBox>\n')

        # write footer and close
        kmlFile.write('</GroundOverlay>\n')
        kmlFile.write('</kml>')
        kmlFile.close()
Пример #9
0
    def write_kml(self, xmlFileName=None, kmlFileName=None):
        '''Write KML file with domains

        Convert XML-file with domains into KML-file for GoogleEarth
        or write KML-file with the current Domain

        Parameters
        -----------
        xmlFileName : string, optional
            Name of the XML-file to convert. If only this value is given
            - kmlFileName=xmlFileName+'.kml'

        kmlFileName : string, optional
            Name of the KML-file to generate from the current Domain

        '''
        # test input options
        if xmlFileName is not None and kmlFileName is None:
            # if only input XML-file is given - convert it to KML

            # open XML, get all domains
            xmlFile = file(xmlFileName, 'rb')
            kmlFileName = xmlFileName + '.kml'
            xmlDomains = ElementTree(file=xmlFile).getroot()
            xmlFile.close()

            # convert domains in XML into list of domains
            domains = []
            for xmlDomain in list(xmlDomains):
                # append Domain object to domains list
                domainName = xmlDomain.attrib['name']
                domains.append(Domain(srs=xmlFileName, ext=domainName))

        elif xmlFileName is None and kmlFileName is not None:
            # if only output KML-file is given
            # then convert the current domain to KML
            domains = [self]

        else:
            # otherwise it is potentially error
            raise OptionError('Either xmlFileName(%s)\
             or kmlFileName(%s) are wrong' % (xmlFileName, kmlFileName))

        # open KML, write header
        kmlFile = file(kmlFileName, 'wt')
        kmlFile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
        kmlFile.write('<kml xmlns="http://www.opengis.net/kml/2.2" '
                      'xmlns:gx="http://www.google.com/kml/ext/2.2" '
                      'xmlns:kml="http://www.opengis.net/kml/2.2" '
                      'xmlns:atom="http://www.w3.org/2005/Atom">\n')
        kmlFile.write('<Document>\n')
        kmlFile.write('    <name>%s</name>\n' % kmlFileName)
        kmlFile.write('        <Folder><name>%s</name><open>1</open>\n' %
                      kmlFileName)

        # get border of each domain and add to KML
        for domain in list(domains):
            kmlEntry = domain._get_border_kml()
            kmlFile.write(kmlEntry)

        # write footer and close
        kmlFile.write('        </Folder></Document></kml>\n')
        kmlFile.close()