Skip to content

Instantly share code, notes, and snippets.

@gbrunner
Last active July 12, 2019 17:18
Show Gist options
  • Save gbrunner/daa71e15d9d832a5f376ca680ccfa614 to your computer and use it in GitHub Desktop.
Save gbrunner/daa71e15d9d832a5f376ca680ccfa614 to your computer and use it in GitHub Desktop.
Python Raster Function Enhancements

Python Raster Function Enhanacements

A GUI to setup a raster function

We need a GUI to configure the Python Raster Funciton. These initialization def __init__(self):, parameter definaition def getParameterInfo(self):, configuration setting def getConfiguration(self, **scalars):, and Raster Metadata Updating def updateRasterInfo(self, **kwargs): should not look as complicated as the following:

def __init__(self):
        self.name = "Compound Topographic Index"
        self.description = ("Computes the compound topographic index (CTI), also "
                            "known as the topographic wetness index (TWI).  "
                            "This is calculated from an input slope raster and flow "
                            "accumulation surface and is meant to be used in "
                            "a raster function chain.")

    def getParameterInfo(self):
        return [
            {
                'name': 'slope',
                'dataType': 'raster',
                'value': None,
                'required': True,
                'displayName': "Slope Raster",
                'description': "A slope raster (in degrees) derived from a digital elevation model (DEM)."
            },
            {
                'name': 'flow',
                'dataType': 'raster',
                'value': None,
                'required': True,
                'displayName': "Flow Accumulation Raster",
                'description': "A raster representing flow accumulation."
            }
        ]

    def getConfiguration(self, **scalars):
        return {
            'compositeRasters': False,
            'inheritProperties': 1 | 2 | 4 | 8,     # inherit all from the raster
            'invalidateProperties': 2 | 4 | 8,      # reset stats, histogram, key properties
            'inputMask': False
        }

    def updateRasterInfo(self, **kwargs):
        # repeat stats for all output raster bands
        kwargs['output_info']['bandCount'] = 1
        kwargs['output_info']['statistics'] = ({'minimum': 0, 'maximum': 25.0}, )
        kwargs['output_info']['histogram'] = ()  # reset histogram
        kwargs['output_info']['pixelType'] = 'f4'
        self.dem_cellsize = kwargs['slope_info']['cellSize']
        return kwargs

I don't like how we have to define bits in the inheritProperties and invalidateProperties. The kwargs params are mysterious. This is all just overly complicated and unclear.

Make it easier to write a Python function to process pixels

The def updatePixels(self, tlc, shape, props, **pixelBlocks): block does the actual pixel processing. The pixelBlocks are a multidimmensional numpy array of pixel values over a given extent. This syntax is pecluliar and unclear.

If you take a look at this CTI Raster Function, it takes in two input raster datasets: slope(Slope Raster) and flow(Flow Direction Raster). Those rasters become:

inBlock_slope = pixelBlocks['slope_pixels']
inBlock_flow = pixelBlocks['flow_pixels']

How do we make it easier? Why can't this function look more like def updatePixels(slope, flow):?

Developing the raster functions is challenging

If you look at some of the more recent raster functions that I have developed, for example, LandsatImageSynthesis.py, in the updatePixels block, there are print statements and pickle exports.

#fname = '{:%Y_%b_%d_%H_%M_%S}_t.txt'.format(datetime.datetime.now())
#filename = os.path.join(debug_logs_directory, fname)

#file = open(filename,"w")
#file.write("File Open.\n")

#pickle_filename = os.path.join(debug_logs_directory, fname)
#pickle.dump(pix_time, open(pickle_filename[:-4]+'pix_time.p',"wb"))

I do this becuase in order to develop the function, I need to pull out a sample pixelBlock and develop the python function against it. Not many people understand this workflow and even if they do, they think it's too complicated of a process just to develop some python image processing code. Can we make it easier to develop these functions?

Interactively write a Python Raster Function in a Jupyter Notebook

With these comments in mind, is there anyway we can use Jupyter to write a Python Raster Function? Can we get the pixelBlocks into a Notebook in order to prototype it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment