Example #1
0
def null_set_range(rastlist, high_thresh = None, low_thresh = None, NoData_Value = None):
    """
    Changes values within a certain range to NoData

     similar to raster.null_define, but can take an entire range of values to set to NoData.
     useful in filtering obviously erroneous high or low values from a raster dataset.

     inputs:
       rastlist     list of files for which to set NoData values. easily created with
                    "core.list_files" function
       high_thresh  will set all values above this to  NoData
       low_thresh   will set all values below this to NoData
    """

    # sanitize filelist input
    rastlist = enf_rastlist(rastlist)

    # iterate through each file in the filelist and set nodata values
    for rastname in rastlist:
        #load raster as numpy array and save spatial referencing.
        rast, meta = to_numpy(rastname)

        if not NoData_Value == None:
            NoData_Value = meta.NoData_Value

        if not high_thresh == None:
            rast[rast >= high_thresh] = NoData_Value
        if not low_thresh == None:
            rast[rast <= low_thresh] = NoData_Value

        from_numpy(rast, meta, rastname)
        arcpy.SetRasterProperties_management(rastname, data_type="#",statistics="#",
                    stats_file = "#", nodata = "1 " + str(NoData_Value))

    return
Example #2
0
def raster_overlap(file_A, file_B, outpath, NoData_A=None, NoData_B=None):
    """
    Finds overlaping area between two raster images.
     
    this function examines two images and outputs a raster identifying pixels where both
    rasters have non-NoData values. Output raster has 1's where both images have data and
    0's where one or both images are missing data.

    inputs:
        file_A      the first file
        file_B      the second file
        outpath     the output filename for the desired output. must end in ".tif"
        NoData_A    the NoData value of file A
        NoData_B    the NoData value of file B

    This function automatically invokes
        clip_and_snap
        null_define
    """

    if not is_rast(file_A) or not is_rast(file_B):
        raise Exception(' both inputs must be rasters!')

    # load the rasters as numpy arays.
    a, metaA = to_numpy(file_A)
    b, metaB = to_numpy(file_B)

    # set no_datas
    if NoData_A is None:
        NoData_A = metaA.NoData_Value
    if NoData_B is None:
        NoData_B = metaB.NoData_Value

    # spatially match the rasters
    print('preparing input rasters!')
    clip_and_snap(file_A, file_B, outpath.replace(".shp", ".tif"), NoData_B)

    # reload the rasters as numpy arrays now that spatial matching is done
    a, metaA = to_numpy(file_A)
    b, metaB = to_numpy(file_B)

    # create work matrix and find the overlap
    print('Finding overlaping pixels!')
    Workmatrix = a.mask + b.mask
    Workmatrix = Workmatrix.astype('uint8')
    Workmatrix[Workmatrix == 1] = 2

    print('Saving overlap file!')
    metaA.numpy_datatype = 'uint8'
    from_numpy(Workmatrix,
               metaA,
               outpath.replace(".shp", ".tif"),
               NoData_Value=2)
    arcpy.RasterToPolygon_conversion(outpath.replace(".shp", ".tif"),
                                     outpath.replace(".tif", ".shp"),
                                     'NO_SIMPLIFY')

    return metaA, metaB
Example #3
0
def raster_overlap(file_A, file_B, outpath, NoData_A = None, NoData_B = None):
    """
    Finds overlaping area between two raster images. this function examines
    two images and outputs a raster identifying pixels where both rasters have
    non-NoData values. Output raster has 1's where both images have data and
    0's where one or both images are missing data.

    :param file_A:      the first file
    :param file_B:      the second file
    :param outpath:     the output filename for the desired output. must end in ".tif"
    :param NoData_A:    the NoData value of file A
    :param NoData_B:    the NoData value of file B

    :return outpath:    filepath to raster created by this function.

    This function automatically invokes
        * clip_and_snap
        * null_define
    """
    
    if not is_rast(file_A) or not is_rast(file_B):
        raise Exception('both inputs must be rasters!')


    # load the rasters as numpy arays.
    a, metaA = to_numpy(file_A)
    b, metaB = to_numpy(file_B)

    # set no_datas
    if NoData_A is None:
        NoData_A = metaA.NoData_Value
    if NoData_B is None:
        NoData_B = metaB.NoData_Value

    # spatially match the rasters
    print('preparing input rasters!')
    clip_and_snap(file_A, file_B, outpath.replace(".shp",".tif"), NoData_B)

    # reload the rasters as numpy arrays now that spatial matching is done
    a, metaA = to_numpy(file_A)
    b, metaB = to_numpy(file_B)

    # create work matrix and find the overlap
    print('Finding overlaping pixels!')
    Workmatrix = a.mask + b.mask
    Workmatrix = Workmatrix.astype('uint8')
    Workmatrix[Workmatrix == 1] = 2
                
    print('Saving overlap file!')
    metaA.numpy_datatype = 'uint8'
    from_numpy(Workmatrix, metaA, outpath.replace(".shp",".tif"), NoData_Value = 2)
    arcpy.RasterToPolygon_conversion(outpath.replace(".shp",".tif"),
                                     outpath.replace(".tif",".shp"),
                                     'NO_SIMPLIFY')
    
    return outpath
Example #4
0
def null_set_range(rastlist,
                   high_thresh=None,
                   low_thresh=None,
                   NoData_Value=None):
    """
    Changes values within a certain range to NoData. similar to ``raster.null_define``,
    but can take an entire range of values to set to NoData. useful in filtering
    obviously erroneous high or low values from a raster dataset.

    :param rastlist:     list of rasters for which to set no dta values
    :param high_thresh:  will set all values above this to  NoData
    :param low_thresh:   will set all values below this to NoData

    :return rastlist:    list of all rasters modified by this function
    """

    # sanitize filelist input
    rastlist = enf_rastlist(rastlist)

    # iterate through each file in the filelist and set nodata values
    for rastname in rastlist:

        #load raster as numpy array and save spatial referencing.
        rast, meta = to_numpy(rastname)

        if not NoData_Value is None:
            NoData_Value = meta.NoData_Value

        if not high_thresh is None:
            rast[rast >= high_thresh] = NoData_Value

        if not low_thresh is None:
            rast[rast <= low_thresh] = NoData_Value

        from_numpy(rast, meta, rastname)
        try:
            arcpy.SetRasterProperties_management(rastname,
                                                 data_type="#",
                                                 statistics="#",
                                                 stats_file="#",
                                                 nodata="1 " +
                                                 str(NoData_Value))
        except RuntimeError:
            print("failed to set nodata in {0}".format(rastname))

    return
Example #5
0
def null_set_range(rastlist,
                   high_thresh=None,
                   low_thresh=None,
                   NoData_Value=None):
    """
    Changes values within a certain range to NoData

     similar to raster.null_define, but can take an entire range of values to set to NoData.
     useful in filtering obviously erroneous high or low values from a raster dataset.

     inputs:
       rastlist     list of files for which to set NoData values. easily created with
                    "core.list_files" function
       high_thresh  will set all values above this to  NoData
       low_thresh   will set all values below this to NoData
    """

    # sanitize filelist input
    rastlist = enf_rastlist(rastlist)

    # iterate through each file in the filelist and set nodata values
    for rastname in rastlist:
        #load raster as numpy array and save spatial referencing.
        rast, meta = to_numpy(rastname)

        if not NoData_Value == None:
            NoData_Value = meta.NoData_Value

        if not high_thresh == None:
            rast[rast >= high_thresh] = NoData_Value
        if not low_thresh == None:
            rast[rast <= low_thresh] = NoData_Value

        from_numpy(rast, meta, rastname)
        arcpy.SetRasterProperties_management(rastname,
                                             data_type="#",
                                             statistics="#",
                                             stats_file="#",
                                             nodata="1 " + str(NoData_Value))

    return
Example #6
0
def null_set_range(rastlist, high_thresh = None, low_thresh = None, NoData_Value = None):
    """
    Changes values within a certain range to NoData. similar to ``raster.null_define``,
    but can take an entire range of values to set to NoData. useful in filtering
    obviously erroneous high or low values from a raster dataset.

    :param rastlist:     list of rasters for which to set no dta values
    :param high_thresh:  will set all values above this to  NoData
    :param low_thresh:   will set all values below this to NoData

    :return rastlist:    list of all rasters modified by this function
    """

    # sanitize filelist input
    rastlist = enf_rastlist(rastlist)

    # iterate through each file in the filelist and set nodata values
    for rastname in rastlist:

        #load raster as numpy array and save spatial referencing.
        rast, meta = to_numpy(rastname)

        if not NoData_Value is None:
            NoData_Value = meta.NoData_Value

        if not high_thresh is None:
            rast[rast >= high_thresh] = NoData_Value

        if not low_thresh is None:
            rast[rast <= low_thresh] = NoData_Value

        from_numpy(rast, meta, rastname)
        try:
            arcpy.SetRasterProperties_management(rastname, data_type = "#", statistics = "#",
                    stats_file = "#", nodata = "1 " + str(NoData_Value))
        except RuntimeError:
            print("failed to set nodata in {0}".format(rastname))

    return
Example #7
0
def degree_days(T_base, Max, Min, NoData_Value, outpath = False, roof = False, floor = False):
    """
    Inputs rasters for maximum and minimum temperatures, calculates Growing Degree Days

    this function is built to perform the common degree day calculation on either a pair
    of raster filepaths, a pair of numpy arrays It requires, at minimum a maximum
    temperature value, a minimum temperature value, and a base temperature. This
    equation could also be used to calculate Chill hours or anything similar.

    The equation is ``[(Max+Min)/2 + T_base]``

    where values in Max which are greater than roof are set equal to roof
    where values in Min which are less than floor are set equal to floor
    consult [https://en.wikipedia.org/wiki/Growing_degree-day] for more information.

    :param T_base:          base temperature to ADD, be mindful of sign convention.
    :param Max:             filepath, numpy array, or list of maximum temperatures
    :param Min:             filepath, numpy array, or list of minimum temperatures
    :param NoData_Value:    values to ignore (must be int or float)
    :param outpath:         filepath to which output should be saved. Only works if Max and Min inputs
                            are raster filepaths with spatial referencing.
    :param roof:            roof value above which Max temps do not mater
    :param floor:           floor value below which Min temps do not mater

    :return deg_days:       a numpy array of the output degree_days
    """

    #FIXME: doesn't fit style guide. does not operate in batch and return list of output filepaths

    output_filelist = []

    # format numerical inputs as floating point values
    T_base = float(T_base)
    if roof:
        roof  = float(roof)
    if floor:
        floor = float(floor)

    # Determine the type of input and convert to useful format for calculation
    # acceptable input formats are filepaths to rasters, numpy arrays, or lists.
    if type(Max) is list and type(Min) is list:
        
        # if the first entry in a list is a string, assume it is a filename that has
        # been placed into a list.
        if type(Max[0]) is str and type(Min[0]) is str:
            Max = Max[0]
            Min = Min[0]

            # load in the min and max files.
            highs, meta = to_numpy(Max)
            lows, meta  = to_numpy(Min)

            print('Found spatially referenced image pair!')
        else:
            highs = numpy.array(Max)
            lows  = numpy.array(Min)
            
    # if they are already numpy arrays
    elif type(Max) is numpy.ndarray:
            highs = Max
            lows  = Min
    else:
        raise Exception("invalid inputs!")
            
    # Begin to perform the degree day calculations

    # apply roof and floor corrections if they have been specified
    if roof:
        highs[highs >= roof] = roof
    if floor:
        lows[lows <=floor] = floor

    # find the shapes of high and low arrays
    xsh, ysh = highs.shape
    xsl, ysl = lows.shape

    # only continue if min and max arrays have the same shape
    if xsh == xsl and ysh == ysl:
        
        # set empty degree day matrix
        deg_days = numpy.zeros((xsh,ysh))
        
        # perform the calculation
        for x in range(xsh):
            for y in range(ysh):
                if round(highs[x,y]/NoData_Value,10) !=1 and round(lows[x,y]/NoData_Value,10) != 1:
                    deg_days[x,y] =((highs[x,y] + lows[x,y])/2) + T_base
                else:
                    deg_days[x,y] = NoData_Value
                
    # print error if the arrays are not the same size
    else:
        print('Images are not the same size!, Check inputs!')
        return False

    # if an output path was specified, save it with the spatial referencing information.
    if outpath and type(Max) is str and type(Min) is str:
        from_numpy(deg_days, meta, outpath)
        print('Output saved at : ' + outpath)
        
    return deg_days
Example #8
0
def clip_and_snap(snap_raster, rastname, outname, NoData_Value = None):
    """
    Ensures perfect coincidence between a snap_raster and any input rasters

     This script is primarily intended for calling by the "raster.spatially_match" function
     but may be called independently.

     it is designed to input a reference image and a working image. The working image must
     be in exactly the same projection and spatial resolution as the reference image. This
     script will simply ensure the tif files are perfectly coincident, and that the total image
     extents are identical. This is important when performing numpy manipulations on matrices
     derived from different datasets manipulated in different ways to ensure alignment.

     This script makes modifications to the original raster file, so save a backup if you are
     unsure how to use this.

     inputs:
       snap_raster     filepath and name of reference raster whos extent will be taken on by
                       the input rastername
       rastname        name of raster which should be snapped to the snap_raster
       NoData_Value    Value desired to represent NoData in the saved image.

     outputs:
       snap_meta       metadata of the snap_raster file as output by to_numpy
       meta            metadata of the rastername file as output by to_numpy
    """

    # grab metadata for rastname
    _,snap_meta = to_numpy(snap_raster)
    _,meta      = to_numpy(rastname)

    if NoData_Value is None:
        NoData_Value = meta.NoData_Value

    head, tail   = os.path.split(outname)
    tempdir     = os.path.join(head, 'temp')

    if not os.path.isdir(tempdir):
        os.makedirs(tempdir)

    # set the snap raster environment in arcmap
    arcpy.env.snapRaster = snap_raster

    # remove data that is outside the bounding box and snap the image
    print("Clipping {0}".format(rastname))

    tempout = os.path.join(tempdir,'tempclip.tif')
    try:
        arcpy.Clip_management(rastname, snap_meta.rectangle, tempout, "#", "#", "NONE", "MAINTAIN_EXTENT")
    except:
        arcpy.Clip_management(rastname, snap_meta.rectangle, tempout, "#", "#", "NONE")

    # load the newly clipped raster, find any residual offsets (usually a single pixel or two)
    raster, meta = to_numpy(tempout)
    xloff   = int(round((meta.Xmin - snap_meta.Xmin)/meta.cellWidth,0))
    yloff   = int(round((meta.Ymin - snap_meta.Ymin)/meta.cellHeight,0))
    xhoff   = int(round((meta.Xmax - snap_meta.Xmax)/meta.cellWidth,0))
    yhoff   = int(round((meta.Ymax - snap_meta.Ymax)/meta.cellHeight,0))

    # plop the snapped raster into the new output raster, alter the metadata, and save it
    meta.Xmin   = snap_meta.Xmin
    meta.Ymin   = snap_meta.Ymin
    meta.Xmax   = snap_meta.Xmax
    meta.Ymax   = snap_meta.Ymax

    newraster = raster[(-yloff) : (meta.Ysize - yhoff), (-xloff) : (meta.Xsize - xhoff)]

    from_numpy(newraster, meta, outname, NoData_Value)

    try:
        shutil.rmtree(tempdir)
    except: pass

    return snap_meta, meta
Example #9
0
def clip_and_snap(snap_raster, rastname, outname, NoData_Value=None):
    """
    Ensures perfect coincidence between a snap_raster and any input rasters

    This script is primarily intended for calling by the "raster.spatially_match" function
    but may be called independently.

    it is designed to input a reference image and a working image. The working image must
    be in exactly the same projection and spatial resolution as the reference image. This
    script will simply ensure the tif files are perfectly coincident, and that the total image
    extents are identical. This is important when performing numpy manipulations on matrices
    derived from different datasets manipulated in different ways to ensure alignment.

    This script makes modifications to the original raster file, so save a backup if you are
    unsure how to use this.

    :param snap_raster:     filepath and name of reference raster whos extent will be taken on by
                            the input rastername.
    :param rastname:        name of raster which should be snapped to the snap_raster
    :param NoData_Value:    Value desired to represent NoData in the saved image.

    :return snap_meta:      metadata of the snap_raster file as output by to_numpy
    :return meta:           metadata of the rastername file as output by to_numpy
    """

    # grab metadata for rastname
    _, snap_meta = to_numpy(snap_raster)
    _, meta = to_numpy(rastname)

    if NoData_Value is None:
        NoData_Value = meta.NoData_Value

    head, tail = os.path.split(outname)
    tempdir = os.path.join(head, 'temp')

    if not os.path.isdir(tempdir):
        os.makedirs(tempdir)

    # set the snap raster environment in arcmap
    arcpy.env.snapRaster = snap_raster

    # remove data that is outside the bounding box and snap the image
    print("Clipping {0}".format(rastname))

    tempout = os.path.join(tempdir, 'tempclip.tif')
    try:
        arcpy.Clip_management(rastname, snap_meta.rectangle, tempout, "#", "#",
                              "NONE", "MAINTAIN_EXTENT")
    except:
        arcpy.Clip_management(rastname, snap_meta.rectangle, tempout, "#", "#",
                              "NONE")

    # load the newly clipped raster, find any residual offsets (usually a single pixel or two)
    raster, meta = to_numpy(tempout)
    xloff = int(round((meta.Xmin - snap_meta.Xmin) / meta.cellWidth, 0))
    yloff = int(round((meta.Ymin - snap_meta.Ymin) / meta.cellHeight, 0))
    xhoff = int(round((meta.Xmax - snap_meta.Xmax) / meta.cellWidth, 0))
    yhoff = int(round((meta.Ymax - snap_meta.Ymax) / meta.cellHeight, 0))

    # plop the snapped raster into the new output raster, alter the metadata, and save it
    meta.Xmin = snap_meta.Xmin
    meta.Ymin = snap_meta.Ymin
    meta.Xmax = snap_meta.Xmax
    meta.Ymax = snap_meta.Ymax

    newraster = raster[(-yloff):(meta.Ysize - yhoff),
                       (-xloff):(meta.Xsize - xhoff)]

    from_numpy(newraster, meta, outname, NoData_Value)

    try:
        shutil.rmtree(tempdir)
    except:
        pass

    return snap_meta, meta
Example #10
0
    # check output directories and set up inputs for arcpy function
    outdir, outname = os.path.split(output_path)

    if not os.path.exists(outdir):
        os.makedirs(outdir)

    arcpy.MosaicToNewRaster_management(rasterpaths, outdir, outname,
                                        None,                # coordinate system
                                        meta.pixel_type,
                                        cell_size,
                                        str(number_of_bands),
                                        mosaic_method = mosaic_method)

    print("Created raster mosaic at {0}".format(output_path))
    return output_path



if __name__ == "__main__":

    adir = r"C:\Users\jwely\Desktop\Team_Projects\2015_sumer_CO_water\LiDAR_Format_Trial"
    outpath = os.path.join(adir, "mosaic", "test_mosaic.tif")
    new_mosaic(adir, outpath, mosaic_method = "FIRST" )

    rast, meta = to_numpy(outpath)
    rast.data[rast.data == numpy.nan] = 0
    rast.data[(2452 >= rast.data) & (rast.data >= 2450)] = numpy.nan
    rast.data[(2430 >= rast.data) & (rast.data >= 2428)] = numpy.nan
    rast.data[(2350 >= rast.data) & (rast.data >= 2348)] = numpy.nan
    from_numpy(rast, meta, outpath.replace(".tif","_gaps.tif"))
Example #11
0
def many_stats(rasterlist, outdir, outname, saves = ['AVG','NUM','STD','SUM'],
                                low_thresh = None, high_thresh = None, numtype = 'float32'):
    """
    Take statitics across many input rasters
    
     this function is used to take statistics on large groups of rasters with identical
     spatial extents. Similar to Rolling_Raster_Stats

     Inputs:
        rasterlist      list of raster filepaths for which to take statistics
        outdir          Directory where output should be stored.
        saves           which statistics to save in a raster. In addition to the options
                        supported by 
                           
                        Defaults to all three ['AVG','NUM','STD'].
        low_thresh      values below low_thresh are assumed erroneous and set to NoData
        high_thresh     values above high_thresh are assumed erroneous and set to NoData.
        numtype         type of numerical value. defaults to 32bit float.
    """

    if not os.path.isdir(outdir):
        os.makedirs(outdir)
    
    rasterlist = enf_rastlist(rasterlist)

    # build the empty numpy array based on size of first raster
    temp_rast, metadata = to_numpy(rasterlist[0])
    xs, ys              = temp_rast.shape
    zs                  = len(rasterlist)
    rast_3d             = numpy.zeros((xs,ys,zs))

    metadata.NoData_Value = numpy.nan

    # open up the initial figure
    rastfig = raster_fig(temp_rast)

    # populate the 3d matrix with values from all rasters
    for i, raster in enumerate(rasterlist):

        # print a status and open a figure
        print('working on file {0}'.format(os.path.basename(raster)))
        new_rast, new_meta  = to_numpy(raster, numtype)

        new_rast = new_rast.data

        if not new_rast.shape == (xs, ys):
            print new_rast.shape

        # set rasters to have 'nan' NoData_Value
        if new_meta.NoData_Value != metadata.NoData_Value:
            new_rast[new_rast == new_meta.NoData_Value] = metadata.NoData_Value
            
        # set values outside thresholds to nodata values
        if not low_thresh == None:
            new_rast[new_rast < low_thresh] = metadata.NoData_Value
        if not high_thresh == None:
            new_rast[new_rast > high_thresh] = metadata.NoData_Value

        new_rast = numpy.ma.masked_array(new_rast, numpy.isnan(new_rast))

        # display a figure
        rastfig.update_fig(new_rast)

        rast_3d[:,:,i] = new_rast


    # build up our statistics by masking nan values and performin matrix opperations
    rastfig.close_fig()
    rast_3d_masked  = numpy.ma.masked_array(rast_3d, numpy.isnan(rast_3d))

    if "AVG" in saves:
        avg_rast        = numpy.mean(rast_3d_masked, axis = 2)
        avg_rast        = numpy.array(avg_rast)
        rastfig         = raster_fig(avg_rast, title = "Average")

        avg_name = core.create_outname(outdir, outname, 'AVG', 'tif')
        print("Saving AVERAGE output raster as {0}".format(avg_name))
        from_numpy(avg_rast, metadata, avg_name)
        rastfig.close_fig()
        del avg_rast

    if "STD" in saves:
        std_rast        = numpy.std(rast_3d_masked, axis = 2)
        std_rast        = numpy.array(std_rast)
        rastfig         = raster_fig(std_rast, title = "Standard Deviation")

        std_name = core.create_outname(outdir, outname, 'STD', 'tif')
        print("Saving STANDARD DEVIATION output raster as {0}".format(std_name))
        from_numpy(std_rast, metadata, std_name)
        rastfig.close_fig()
        del std_rast
        
    if "NUM" in saves:
        num_rast        = (numpy.zeros((xs,ys)) + zs) - numpy.sum(rast_3d_masked.mask, axis = 2)
        num_rast        = numpy.array(num_rast)
        rastfig         = raster_fig(num_rast, title =  "Good pixel count (NUM)")
        rastfig.close_fig()

        num_name = core.create_outname(outdir, outname, 'NUM', 'tif')
        print("Saving NUMBER output raster as {0}".format(num_name))
        from_numpy(num_rast, metadata, num_name)
        rastfig.close_fig()
        del num_rast

    if "SUM" in saves:
        sum_rast        = numpy.sum(rast_3d_masked, axis = 2)
        sum_rast        = numpy.array(sum_rast)
        rastfig         = raster_fig(sum_rast, title = "Good pixel count (NUM)")
        rastfig.close_fig()

        sum_name = core.create_outname(outdir, outname, 'SUM', 'tif')
        print("Saving NUMBER output raster as {0}".format(sum_name))
        from_numpy(sum_rast, metadata, sum_name)
        rastfig.close_fig()
        del sum_rast
                   
    rastfig.close_fig()

    return
Example #12
0
    if not os.path.exists(outdir):
        os.makedirs(outdir)

    arcpy.MosaicToNewRaster_management(
        rasterpaths,
        outdir,
        outname,
        None,  # coordinate system
        meta.pixel_type,
        cell_size,
        str(number_of_bands),
        mosaic_method=mosaic_method)

    print("Created raster mosaic at {0}".format(output_path))
    return output_path


if __name__ == "__main__":

    adir = r"C:\Users\jwely\Desktop\Team_Projects\2015_sumer_CO_water\LiDAR_Format_Trial"
    outpath = os.path.join(adir, "mosaic", "test_mosaic.tif")
    new_mosaic(adir, outpath, mosaic_method="FIRST")

    rast, meta = to_numpy(outpath)
    rast.data[rast.data == numpy.nan] = 0
    rast.data[(2452 >= rast.data) & (rast.data >= 2450)] = numpy.nan
    rast.data[(2430 >= rast.data) & (rast.data >= 2428)] = numpy.nan
    rast.data[(2350 >= rast.data) & (rast.data >= 2348)] = numpy.nan
    from_numpy(rast, meta, outpath.replace(".tif", "_gaps.tif"))
Example #13
0
def degree_days(T_base,
                Max,
                Min,
                NoData_Value,
                outpath=False,
                roof=False,
                floor=False):
    """
    Inputs rasters for maximum and minimum temperatures, calculates Growing Degree Days

    this function is built to perform the common degree day calculation on either a pair
    of raster filepaths, a pair of numpy arrays It requires, at minimum a maximum
    temperature value, a minimum temperature value, and a base temperature. This
    equation could also be used to calculate Chill hours or anything similar.

    The equation is ``[(Max+Min)/2 + T_base]``

    where values in Max which are greater than roof are set equal to roof
    where values in Min which are less than floor are set equal to floor
    consult [https://en.wikipedia.org/wiki/Growing_degree-day] for more information.

    :param T_base:          base temperature to ADD, be mindful of sign convention.
    :param Max:             filepath, numpy array, or list of maximum temperatures
    :param Min:             filepath, numpy array, or list of minimum temperatures
    :param NoData_Value:    values to ignore (must be int or float)
    :param outpath:         filepath to which output should be saved. Only works if Max and Min inputs
                            are raster filepaths with spatial referencing.
    :param roof:            roof value above which Max temps do not mater
    :param floor:           floor value below which Min temps do not mater

    :return deg_days:       a numpy array of the output degree_days
    """

    #FIXME: doesn't fit style guide. does not operate in batch and return list of output filepaths

    output_filelist = []

    # format numerical inputs as floating point values
    T_base = float(T_base)
    if roof:
        roof = float(roof)
    if floor:
        floor = float(floor)

    # Determine the type of input and convert to useful format for calculation
    # acceptable input formats are filepaths to rasters, numpy arrays, or lists.
    if type(Max) is list and type(Min) is list:

        # if the first entry in a list is a string, assume it is a filename that has
        # been placed into a list.
        if type(Max[0]) is str and type(Min[0]) is str:
            Max = Max[0]
            Min = Min[0]

            # load in the min and max files.
            highs, meta = to_numpy(Max)
            lows, meta = to_numpy(Min)

            print('Found spatially referenced image pair!')
        else:
            highs = numpy.array(Max)
            lows = numpy.array(Min)

    # if they are already numpy arrays
    elif type(Max) is numpy.ndarray:
        highs = Max
        lows = Min
    else:
        raise Exception("invalid inputs!")

    # Begin to perform the degree day calculations

    # apply roof and floor corrections if they have been specified
    if roof:
        highs[highs >= roof] = roof
    if floor:
        lows[lows <= floor] = floor

    # find the shapes of high and low arrays
    xsh, ysh = highs.shape
    xsl, ysl = lows.shape

    # only continue if min and max arrays have the same shape
    if xsh == xsl and ysh == ysl:

        # set empty degree day matrix
        deg_days = numpy.zeros((xsh, ysh))

        # perform the calculation
        for x in range(xsh):
            for y in range(ysh):
                if round(highs[x, y] / NoData_Value, 10) != 1 and round(
                        lows[x, y] / NoData_Value, 10) != 1:
                    deg_days[x, y] = ((highs[x, y] + lows[x, y]) / 2) + T_base
                else:
                    deg_days[x, y] = NoData_Value

    # print error if the arrays are not the same size
    else:
        print('Images are not the same size!, Check inputs!')
        return False

    # if an output path was specified, save it with the spatial referencing information.
    if outpath and type(Max) is str and type(Min) is str:
        from_numpy(deg_days, meta, outpath)
        print('Output saved at : ' + outpath)

    return deg_days
Example #14
0
def many_stats(rasterlist,
               outdir,
               outname,
               saves=['AVG', 'NUM', 'STD', 'SUM'],
               low_thresh=None,
               high_thresh=None,
               numtype='float32'):
    """
    Take statitics across many input rasters
    
     this function is used to take statistics on large groups of rasters with identical
     spatial extents. Similar to Rolling_Raster_Stats

     Inputs:
        rasterlist      list of raster filepaths for which to take statistics
        outdir          Directory where output should be stored.
        saves           which statistics to save in a raster. In addition to the options
                        supported by 
                           
                        Defaults to all three ['AVG','NUM','STD'].
        low_thresh      values below low_thresh are assumed erroneous and set to NoData
        high_thresh     values above high_thresh are assumed erroneous and set to NoData.
        numtype         type of numerical value. defaults to 32bit float.
    """

    if not os.path.isdir(outdir):
        os.makedirs(outdir)

    rasterlist = enf_rastlist(rasterlist)

    # build the empty numpy array based on size of first raster
    temp_rast, metadata = to_numpy(rasterlist[0])
    xs, ys = temp_rast.shape
    zs = len(rasterlist)
    rast_3d = numpy.zeros((xs, ys, zs))

    metadata.NoData_Value = numpy.nan

    # open up the initial figure
    rastfig = raster_fig(temp_rast)

    # populate the 3d matrix with values from all rasters
    for i, raster in enumerate(rasterlist):

        # print a status and open a figure
        print('working on file {0}'.format(os.path.basename(raster)))
        new_rast, new_meta = to_numpy(raster, numtype)

        new_rast = new_rast.data

        if not new_rast.shape == (xs, ys):
            print new_rast.shape

        # set rasters to have 'nan' NoData_Value
        if new_meta.NoData_Value != metadata.NoData_Value:
            new_rast[new_rast == new_meta.NoData_Value] = metadata.NoData_Value

        # set values outside thresholds to nodata values
        if not low_thresh == None:
            new_rast[new_rast < low_thresh] = metadata.NoData_Value
        if not high_thresh == None:
            new_rast[new_rast > high_thresh] = metadata.NoData_Value

        new_rast = numpy.ma.masked_array(new_rast, numpy.isnan(new_rast))

        # display a figure
        rastfig.update_fig(new_rast)

        rast_3d[:, :, i] = new_rast

    # build up our statistics by masking nan values and performin matrix opperations
    rastfig.close_fig()
    rast_3d_masked = numpy.ma.masked_array(rast_3d, numpy.isnan(rast_3d))

    if "AVG" in saves:
        avg_rast = numpy.mean(rast_3d_masked, axis=2)
        avg_rast = numpy.array(avg_rast)
        rastfig = raster_fig(avg_rast, title="Average")

        avg_name = core.create_outname(outdir, outname, 'AVG', 'tif')
        print("Saving AVERAGE output raster as {0}".format(avg_name))
        from_numpy(avg_rast, metadata, avg_name)
        rastfig.close_fig()
        del avg_rast

    if "STD" in saves:
        std_rast = numpy.std(rast_3d_masked, axis=2)
        std_rast = numpy.array(std_rast)
        rastfig = raster_fig(std_rast, title="Standard Deviation")

        std_name = core.create_outname(outdir, outname, 'STD', 'tif')
        print(
            "Saving STANDARD DEVIATION output raster as {0}".format(std_name))
        from_numpy(std_rast, metadata, std_name)
        rastfig.close_fig()
        del std_rast

    if "NUM" in saves:
        num_rast = (numpy.zeros(
            (xs, ys)) + zs) - numpy.sum(rast_3d_masked.mask, axis=2)
        num_rast = numpy.array(num_rast)
        rastfig = raster_fig(num_rast, title="Good pixel count (NUM)")
        rastfig.close_fig()

        num_name = core.create_outname(outdir, outname, 'NUM', 'tif')
        print("Saving NUMBER output raster as {0}".format(num_name))
        from_numpy(num_rast, metadata, num_name)
        rastfig.close_fig()
        del num_rast

    if "SUM" in saves:
        sum_rast = numpy.sum(rast_3d_masked, axis=2)
        sum_rast = numpy.array(sum_rast)
        rastfig = raster_fig(sum_rast, title="Good pixel count (NUM)")
        rastfig.close_fig()

        sum_name = core.create_outname(outdir, outname, 'SUM', 'tif')
        print("Saving NUMBER output raster as {0}".format(sum_name))
        from_numpy(sum_rast, metadata, sum_name)
        rastfig.close_fig()
        del sum_rast

    rastfig.close_fig()

    return
Example #15
0
def degree_days_accum(rasterlist, critical_values=None, outdir=None):
    """
    Accumulates degree days in a time series rasterlist

    This function is the logical successor to calc.degree_days. Input a list of rasters
    containing daily data to be accumulated. Output raster for a given day will be the sum
    total of the input raster for that day and all preceding days. The last output raster in
    a years worth of data (image 356) would be the sum of all 365 images. The 25th output
    raster would be a sum of the first 25 days.
    Critical value rasters will also be created. Usefull for example: we wish to know on what day
    of our 365 day sequence every pixel hits a value of 100. Input 100 as a critical value
    and that output raster will be generated.

    :param rasterlist:          list of files, or directory containing rasters to accumulate
    :param critical_values:     Values at which the user wishes to know WHEN the total accumulation
                                value reaches this point. For every critical value, an output
                                raster will be created. This raster contains integer values denoting
                                the index number of the file at which the value was reached.
                                This input must be a list of ints or floats, not strings.
    :param outdir:              Desired output directory for all output files.

    :return output_filelist:    a list of all files created by this function.
    """

    output_filelist = []
    rasterlist = enf_rastlist(rasterlist)

    if critical_values:
        critical_values = core.enf_list(critical_values)

    # critical values of zero are problematic, so replace it with a small value.
    if 0 in critical_values:
        critical_values.remove(0)
        critical_values.append(0.000001)

    if outdir is not None and not os.path.exists(outdir):
        os.makedirs(outdir)

    for i, rast in enumerate(rasterlist):

        image, meta = to_numpy(rast, "float32")
        xs, ys = image.shape

        if i == 0:
            Sum = numpy.zeros((xs, ys))
            Crit = numpy.zeros((len(critical_values), xs, ys))

        if image.shape == Sum.shape:

            # only bother to proceed if at least one pixel is positive
            if numpy.max(image) >= 0:
                for x in range(xs):
                    for y in range(ys):

                        if image[x, y] >= 0:
                            Sum[x, y] = Sum[x, y] + image[x, y]

                        if critical_values is not None:
                            for z, critical_value in enumerate(
                                    critical_values):
                                if Sum[x,
                                       y] >= critical_value and Crit[z, x,
                                                                     y] == 0:
                                    Crit[z, x, y] = i
        else:
            print "Encountered an image of incorrect size! Skipping it!"

        Sum = Sum.astype('float32')
        outname = core.create_outname(outdir, rast, "Accum")
        from_numpy(Sum, meta, outname)
        output_filelist.append(outname)

        del image

    # output critical accumulation rasters using some data from the last raster in previous loop
    Crit = Crit.astype('int16')
    crit_meta = meta
    crit_meta.NoData_Value = 0
    head, tail = os.path.split(
        outname)  # place these in the last raster output location
    for z, critical_value in enumerate(critical_values):
        outname = os.path.join(
            head, "Crit_Accum_Index_Val-{0}.tif".format(str(critical_value)))
        print("Saving {0}".format(outname))
        from_numpy(Crit[z, :, :], crit_meta, outname)

    return output_filelist
Example #16
0
def degree_days_accum(rasterlist, critical_values = None, outdir = None):
    """
    Accumulates degree days in a time series rasterlist

    This function is the logical successor to calc.degree_days. Input a list of rasters
    containing daily data to be accumulated. Output raster for a given day will be the sum
    total of the input raster for that day and all preceding days. The last output raster in
    a years worth of data (image 356) would be the sum of all 365 images. The 25th output
    raster would be a sum of the first 25 days.
    Critical value rasters will also be created. Usefull for example: we wish to know on what day
    of our 365 day sequence every pixel hits a value of 100. Input 100 as a critical value
    and that output raster will be generated.

    :param rasterlist:          list of files, or directory containing rasters to accumulate
    :param critical_values:     Values at which the user wishes to know WHEN the total accumulation
                                value reaches this point. For every critical value, an output
                                raster will be created. This raster contains integer values denoting
                                the index number of the file at which the value was reached.
                                This input must be a list of ints or floats, not strings.
    :param outdir:              Desired output directory for all output files.

    :return output_filelist:    a list of all files created by this function.
    """

    output_filelist = []
    rasterlist = enf_rastlist(rasterlist)

    if critical_values:
        critical_values = core.enf_list(critical_values)

    # critical values of zero are problematic, so replace it with a small value.
    if 0 in critical_values:
        critical_values.remove(0)
        critical_values.append(0.000001)

    if outdir is not None and not os.path.exists(outdir):
        os.makedirs(outdir)

    for i, rast in enumerate(rasterlist):

        image, meta = to_numpy(rast,"float32")
        xs, ys = image.shape

        if i == 0:
            Sum  = numpy.zeros((xs,ys))
            Crit = numpy.zeros((len(critical_values),xs,ys))

        if image.shape == Sum.shape:

            # only bother to proceed if at least one pixel is positive
            if numpy.max(image) >= 0:
                for x in range(xs):
                    for y in range(ys):

                        if image[x,y] >= 0:
                            Sum[x,y] = Sum[x,y]+image[x,y]

                        if critical_values is not None:
                            for z,critical_value in enumerate(critical_values):
                                if Sum[x,y] >= critical_value and Crit[z,x,y]==0:
                                    Crit[z,x,y] = i
        else:
            print "Encountered an image of incorrect size! Skipping it!"

        Sum     = Sum.astype('float32')
        outname = core.create_outname(outdir, rast, "Accum")
        from_numpy(Sum, meta, outname)
        output_filelist.append(outname)

        del image

    # output critical accumulation rasters using some data from the last raster in previous loop
    Crit = Crit.astype('int16')
    crit_meta = meta
    crit_meta.NoData_Value = 0
    head , tail = os.path.split(outname)        # place these in the last raster output location
    for z, critical_value in enumerate(critical_values):
        outname = os.path.join(head, "Crit_Accum_Index_Val-{0}.tif".format(str(critical_value)))
        print("Saving {0}".format(outname))
        from_numpy(Crit[z,:,:], crit_meta, outname)

    return output_filelist