def updateRasterInfo(self, **kwargs): self.ztMap = None self.whereClause = None ztStr = kwargs.get('ztable', None) ztStr = ztStr.strip() if ztStr else "{}" try: self.ztMap = loadJSON(ztStr) if ztStr else {} except ValueError as e: self.ztMap = None attribs = kwargs.get('attribs', "") attribs = (attribs if attribs else "").split(",") self.M = len(attribs) if self.ztMap is None: self.ztMap = {} self.ztTable = ZonalAttributesTable(tableUri=ztStr, idField=self.zid, attribList=attribs) self.background = kwargs.get('background', None) self.background = int(self.background) if self.background else 0 self.whereClause = kwargs.get('where', None) kwargs['output_info']['bandCount'] = 1 + self.M kwargs['output_info']['statistics'] = () kwargs['output_info']['histogram'] = () kwargs['output_info']['colormap'] = () return kwargs
def updateRasterInfo(self, **kwargs): self.ztMap = None self.whereClause = None ztStr = kwargs.get('ztable', None) ztStr = ztStr.strip() or "{}" try: self.ztMap = loadJSON(ztStr) if ztStr else {} except ValueError as e: self.ztMap = None if self.ztMap is None: self.ztMap = {} self.ztTable = ZonalAttributesTable(tableUri=ztStr, idField=kwargs.get( 'zid', None), attribList=[ kwargs.get('zmin', None), kwargs.get('zmax', None), kwargs.get('zval', None) ]) self.background = int(kwargs.get('background', None) or 0) self.defaultTarget = int(kwargs.get('defzval', None) or 255) self.whereClause = kwargs.get('where', None) kwargs['output_info']['bandCount'] = 1 kwargs['output_info']['statistics'] = () kwargs['output_info']['histogram'] = () kwargs['output_info']['colormap'] = () return kwargs
def updateRasterInfo(self, **kwargs): self.ztMap = None self.whereClause = None ztStr = kwargs.get('ztable', None) ztStr = ztStr.strip() or "{}" try: self.ztMap = loadJSON(ztStr) if ztStr else {} except ValueError as e: self.ztMap = None if self.ztMap is None: self.ztMap = {} self.ztTable = ZonalAttributesTable(tableUri=ztStr, idField=kwargs.get('zid', None), attribList=[kwargs.get('zmin', None), kwargs.get('zmax', None), kwargs.get('zval', None)]) self.background = int(kwargs.get('background', None) or 0) self.defaultTarget = int(kwargs.get('defzval', None) or 255) self.whereClause = kwargs.get('where', None) kwargs['output_info']['bandCount'] = 1 kwargs['output_info']['statistics'] = () kwargs['output_info']['histogram'] = () kwargs['output_info']['colormap'] = () return kwargs
class RasterizeAttributes(): def __init__(self): self.name = "Rasterize Attributes" self.description = ("Enriches a raster through additional bands derived from values of specified attributes " "of an external table or a feature service. You can optionally specify a zone raster " "and the associated zone ID attribute to enable region-based look-up. ") self.ztMap = {} # zonal thresholds { zoneId:[f1,f2,...,fn], ... } self.ztTable = None # valid only if parameter 'ztable' is not a JSON string (but path or URL) self.background = 0 self.whereClause = None self.M = 0 # number of attribute names == additional bands in the output self.zid = None def getParameterInfo(self): return [ { 'name': 'vraster', 'dataType': 'raster', 'value': None, 'required': True, 'displayName': "Input Raster", 'description': "The primary input raster." }, { 'name': 'zraster', 'dataType': 'raster', 'value': None, 'required': False, 'displayName': "Zone Raster", 'description': ("An optional single-band zone raster where each pixel contains " "the zone ID associated with the location. The zone ID is used for " "looking up rows in the zonal attributes table for zone-specific ingestion. " "Leave this parameter unspecified to simply import attribute") }, { 'name': 'ztable', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Zonal Attributes Table", 'description': ("The zonal attributes specified as a JSON string, " "a path to a local feature class or table, or the URL to a feature service layer. " "In JSON, it's described as a collection of mapping from zone IDs to an " "an array of integers, " "like this: { zoneId:[f1,f2,...,fn], ... } ") }, { 'name': 'zid', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Zone ID Field Name", 'description': ("Name of the field containing the Zone ID values. " "This is only applicable if the 'Zonal Attributes Table' parameter contains path to a table " "or a URL to a feature service.") }, { 'name': 'attribs', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Attribute Field Names", 'description': ("List of fields in the zonal attributes table separated by a comma. Values in each field will be represented by a band in the output raster.") }, { 'name': 'background', 'dataType': 'numeric', 'value': 0, 'required': False, 'displayName': "Background Value", 'description': ("The initial pixel value of the output raster--before input pixels are remapped.") }, { 'name': 'where', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Where Clause", 'description': ("Additional query applied on Zonal Attributes table.") }, ] def getConfiguration(self, **scalars): self.zid = (scalars.get('zid', "") or "").strip() self.zid = self.zid if len(self.zid) else None return { 'inheritProperties': 2 | 4 | 8, 'invalidateProperties': 2 | 4 | 8, # invalidate statistics & histogram on the parent dataset. 'inputMask': False # Don't need input raster mask in .updatePixels(). } def selectRasters(self, tlc, shape, props): return ('vraster', 'zraster') if self.zid else ('vraster',) def updateRasterInfo(self, **kwargs): self.ztMap = None self.whereClause = None ztStr = kwargs.get('ztable', None) ztStr = ztStr.strip() if ztStr else "{}" try: self.ztMap = loadJSON(ztStr) if ztStr else {} except ValueError as e: self.ztMap = None attribs = kwargs.get('attribs', "") attribs = (attribs if attribs else "").split(",") self.M = len(attribs) if self.ztMap is None: self.ztMap = {} self.ztTable = ZonalAttributesTable(tableUri=ztStr, idField=self.zid, attribList=attribs) self.background = kwargs.get('background', None) self.background = int(self.background) if self.background else 0 self.whereClause = kwargs.get('where', None) kwargs['output_info']['bandCount'] = 1 + self.M kwargs['output_info']['statistics'] = () kwargs['output_info']['histogram'] = () kwargs['output_info']['colormap'] = () return kwargs def updatePixels(self, tlc, shape, props, **pixelBlocks): zoneIds = None v = pixelBlocks['vraster_pixels'][0] z = pixelBlocks.get('zraster_pixels', None) if self.zid else None if z is not None: # zone raster is optional z = z[0] zoneIds = np.unique(z) #TODO: handle no-data and mask in zone raster ZT = self.ztTable.query(idList=zoneIds, where=self.whereClause, extent=props['extent'], sr=props['spatialReference']) if self.ztTable else self.ztMap # output pixels initialized to background color p = np.full(shape=(1 + self.M,) + v.shape, # band dimension is 1 more than #attributes fill_value=self.background, dtype=props['pixelType']) np.copyto(p[0], v, casting='unsafe') ones = np.ones(v.shape, dtype=bool) # use zonal attributes to update output pixels... if ZT is not None and len(ZT.keys()): for k in (zoneIds if zoneIds is not None else [None]): T = ZT.get(k, None) # k from z might not be in ztMap if not T or not len(T): continue I = (z == k) if z is not None else ones for b,t in enumerate(T[0], 1): # first band of p is v, skip it. if t is not None: p[b][I] = t pixelBlocks['output_pixels'] = p return pixelBlocks
class RasterizeAttributes(): def __init__(self): self.name = "Rasterize Attributes" self.description = ( "Enriches a raster through additional bands derived from values of specified attributes " "of an external table or a feature service. You can optionally specify a zone raster " "and the associated zone ID attribute to enable region-based look-up. " ) self.ztMap = {} # zonal thresholds { zoneId:[f1,f2,...,fn], ... } self.ztTable = None # valid only if parameter 'ztable' is not a JSON string (but path or URL) self.background = 0 self.whereClause = None self.M = 0 # number of attribute names == additional bands in the output self.zid = None def getParameterInfo(self): return [ { 'name': 'vraster', 'dataType': 'raster', 'value': None, 'required': True, 'displayName': "Input Raster", 'description': "The primary input raster." }, { 'name': 'zraster', 'dataType': 'raster', 'value': None, 'required': False, 'displayName': "Zone Raster", 'description': ("An optional single-band zone raster where each pixel contains " "the zone ID associated with the location. The zone ID is used for " "looking up rows in the zonal attributes table for zone-specific ingestion. " "Leave this parameter unspecified to simply import attribute") }, { 'name': 'ztable', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Zonal Attributes Table", 'description': ("The zonal attributes specified as a JSON string, " "a path to a local feature class or table, or the URL to a feature service layer. " "In JSON, it's described as a collection of mapping from zone IDs to an " "an array of integers, " "like this: { zoneId:[f1,f2,...,fn], ... } ") }, { 'name': 'zid', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Zone ID Field Name", 'description': ("Name of the field containing the Zone ID values. " "This is only applicable if the 'Zonal Attributes Table' parameter contains path to a table " "or a URL to a feature service.") }, { 'name': 'attribs', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Attribute Field Names", 'description': ("List of fields in the zonal attributes table separated by a comma. Values in each field will be represented by a band in the output raster." ) }, { 'name': 'background', 'dataType': 'numeric', 'value': 0, 'required': False, 'displayName': "Background Value", 'description': ("The initial pixel value of the output raster--before input pixels are remapped." ) }, { 'name': 'where', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Where Clause", 'description': ("Additional query applied on Zonal Attributes table.") }, ] def getConfiguration(self, **scalars): self.zid = (scalars.get('zid', "") or "").strip() self.zid = self.zid if len(self.zid) else None return { 'inheritProperties': 2 | 4 | 8, 'invalidateProperties': 2 | 4 | 8, # invalidate statistics & histogram on the parent dataset. 'inputMask': False # Don't need input raster mask in .updatePixels(). } def selectRasters(self, tlc, shape, props): return ('vraster', 'zraster') if self.zid else ('vraster', ) def updateRasterInfo(self, **kwargs): self.ztMap = None self.whereClause = None ztStr = kwargs.get('ztable', None) ztStr = ztStr.strip() if ztStr else "{}" try: self.ztMap = loadJSON(ztStr) if ztStr else {} except ValueError as e: self.ztMap = None attribs = kwargs.get('attribs', "") attribs = (attribs if attribs else "").split(",") self.M = len(attribs) if self.ztMap is None: self.ztMap = {} self.ztTable = ZonalAttributesTable(tableUri=ztStr, idField=self.zid, attribList=attribs) self.background = kwargs.get('background', None) self.background = int(self.background) if self.background else 0 self.whereClause = kwargs.get('where', None) kwargs['output_info']['bandCount'] = 1 + self.M kwargs['output_info']['statistics'] = () kwargs['output_info']['histogram'] = () kwargs['output_info']['colormap'] = () return kwargs def updatePixels(self, tlc, shape, props, **pixelBlocks): zoneIds = None v = pixelBlocks['vraster_pixels'][0] z = pixelBlocks.get('zraster_pixels', None) if self.zid else None if z is not None: # zone raster is optional z = z[0] zoneIds = np.unique( z) #TODO: handle no-data and mask in zone raster ZT = self.ztTable.query( idList=zoneIds, where=self.whereClause, extent=props['extent'], sr=props['spatialReference']) if self.ztTable else self.ztMap # output pixels initialized to background color p = np.full( shape=(1 + self.M, ) + v.shape, # band dimension is 1 more than #attributes fill_value=self.background, dtype=props['pixelType']) np.copyto(p[0], v, casting='unsafe') ones = np.ones(v.shape, dtype=bool) # use zonal attributes to update output pixels... if ZT is not None and len(ZT.keys()): for k in (zoneIds if zoneIds is not None else [None]): T = ZT.get(k, None) # k from z might not be in ztMap if not T or not len(T): continue I = (z == k) if z is not None else ones for b, t in enumerate(T[0], 1): # first band of p is v, skip it. if t is not None: p[b][I] = t pixelBlocks['output_pixels'] = p return pixelBlocks
class ZonalRemap(): def __init__(self): self.name = "Zonal Remap" self.description = ("Remap pixels in a raster based on spatial zones " "defined by another raster, and a zone-dependent " "value mapping defined by a table.") self.ztMap = { } # zonal thresholds { zoneId:[[zMin,zMax,zVal], ...], ... } self.ztTable = None # valid only if parameter 'ztable' is not a JSON string (but path or URL) self.background = 0 self.defaultTarget = 255 self.whereClause = None def getParameterInfo(self): return [ { 'name': 'vraster', 'dataType': 'raster', 'value': None, 'required': True, 'displayName': "Input Raster", 'description': "The primary single-band input raster." }, { 'name': 'zraster', 'dataType': 'raster', 'value': None, 'required': False, 'displayName': "Zone Raster", 'description': ("An optional single-band zone raster where each pixel contains " "the zone ID associated with the location. The zone ID is used for " "looking up rows in the zonal threshold table for zone-specific mapping. " "Leave this parameter unspecified to perform zone-independent remapping " "based only on the input pixel value.") }, { 'name': 'ztable', 'dataType': 'string', 'value': None, 'required': True, 'displayName': "Zonal Thresholds Table", 'description': ("The threshold map specified as a JSON string, " "a path to a local feature class or table, or a URL to a feature service layer. " "In JSON, it's described as a collection of mapping from zone IDs to an " "array of 3-tuples representing the interval (zmin-zmax) and the corresponding output value (zval), " "like this: { zoneId:[[zmin,zmax,zval], ...], ... }.") }, { 'name': 'zid', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Zone ID Field Name", 'description': ("Name of the field containing the Zone ID values. " "This is only applicable if the 'Zonal Thresholds' parameter contains path to a table " "or a URL to a feature service.") }, { 'name': 'zmin', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Minimum Value Field Name", 'description': ("Name of the field containing the minimum value above which an input pixel gets remapped. " "If left unspecified--or if the field value is null--pixel values are not tested for minimum. " "This is only applicable if the 'Zonal Thresholds Table' parameter contains path to a table " "or a URL to a feature service.") }, { 'name': 'zmax', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Maximum Value Field Name", 'description': ("Name of the field containing the maximum value below which an input pixel gets remapped. " "If left unspecified--or if the field value is null--pixel values are not tested for maximum. " "This is only applicable if the 'Zonal Thresholds Table' parameter contains path to a table " "or a URL to a feature service.") }, { 'name': 'zval', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Output Value Field Name", 'description': ("Name of the field containing the output value to which an input pixel gets remapped. " "If left unspecified--or if the field value is null--remapped pixel values are set " "to the 'Default Output Value'. " "This is only applicable if the 'Zonal Thresholds Table' parameter contains path to a table " "or a URL to a feature service.") }, { 'name': 'background', 'dataType': 'numeric', 'value': 0, 'required': False, 'displayName': "Background Value", 'description': ("The initial pixel value of the output raster--before input pixels are remapped." ) }, { 'name': 'defzval', 'dataType': 'numeric', 'value': 255, 'required': False, 'displayName': "Default Output Value", 'description': ("The default remap/target value of threshold. " "This is the value of the output pixel if either the 'Output Value Field Name' " "parameter is left unspecified or if the output value of the corresponding " "zonal threshold is left unspecified in the Zonal Thresholds Table." ) }, { 'name': 'where', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Where Clause", 'description': ("Additional query applied on the Zonal Thresholds Table. " "Only the rows that satisfy this criteria participate in the zonal remapping." ) }, ] def getConfiguration(self, **scalars): return { 'inheritProperties': 2 | 4 | 8, 'invalidateProperties': 2 | 4 | 8, # invalidate statistics & histogram on the parent dataset. 'inputMask': False # Don't need input raster mask in .updatePixels(). } def updateRasterInfo(self, **kwargs): self.ztMap = None self.whereClause = None ztStr = kwargs.get('ztable', None) ztStr = ztStr.strip() or "{}" try: self.ztMap = loadJSON(ztStr) if ztStr else {} except ValueError as e: self.ztMap = None if self.ztMap is None: self.ztMap = {} self.ztTable = ZonalAttributesTable(tableUri=ztStr, idField=kwargs.get( 'zid', None), attribList=[ kwargs.get('zmin', None), kwargs.get('zmax', None), kwargs.get('zval', None) ]) self.background = int(kwargs.get('background', None) or 0) self.defaultTarget = int(kwargs.get('defzval', None) or 255) self.whereClause = kwargs.get('where', None) kwargs['output_info']['bandCount'] = 1 kwargs['output_info']['statistics'] = () kwargs['output_info']['histogram'] = () kwargs['output_info']['colormap'] = () return kwargs def updatePixels(self, tlc, shape, props, **pixelBlocks): v = pixelBlocks['vraster_pixels'][0] zoneIds = None z = pixelBlocks.get('zraster_pixels', None) if z is not None: # zone raster is optional z = z[0] zoneIds = np.unique( z) #TODO: handle no-data and mask in zone raster ZT = self.ztTable.query( idList=zoneIds, where=self.whereClause, extent=props['extent'], sr=props['spatialReference']) if self.ztTable else self.ztMap # output pixels initialized to background color p = np.full(v.shape, self.background, dtype=props['pixelType']) # use zonal thresholds to update output pixels... if ZT is not None and len(ZT.keys()): for k in (zoneIds or [None]): T = ZT.get(k, None) # k from z might not be in ztMap if not T: continue for t in T: I = (z == k) if z is not None else np.ones(v.shape, dtype=bool) if t[0] and t[1]: # min and max are both available I = I & (v > t[0]) & (v < t[1]) elif t[0]: I = I & (v > t[0]) elif t[1]: I = I & (v < t[1]) p[I] = (t[2] if t[2] is not None else self.defaultTarget) pixelBlocks['output_pixels'] = p return pixelBlocks
class ZonalRemap(): def __init__(self): self.name = "Zonal Remap" self.description = ("Remap pixels in a raster based on spatial zones " "defined by another raster, and a zone-dependent " "value mapping defined by a table.") self.ztMap = {} # zonal thresholds { zoneId:[[zMin,zMax,zVal], ...], ... } self.ztTable = None # valid only if parameter 'ztable' is not a JSON string (but path or URL) self.background = 0 self.defaultTarget = 255 self.whereClause = None def getParameterInfo(self): return [ { 'name': 'vraster', 'dataType': 'raster', 'value': None, 'required': True, 'displayName': "Input Raster", 'description': "The primary single-band input raster." }, { 'name': 'zraster', 'dataType': 'raster', 'value': None, 'required': False, 'displayName': "Zone Raster", 'description': ("An optional single-band zone raster where each pixel contains " "the zone ID associated with the location. The zone ID is used for " "looking up rows in the zonal threshold table for zone-specific mapping. " "Leave this parameter unspecified to perform zone-independent remapping " "based only on the input pixel value.") }, { 'name': 'ztable', 'dataType': 'string', 'value': None, 'required': True, 'displayName': "Zonal Thresholds Table", 'description': ("The threshold map specified as a JSON string, " "a path to a local feature class or table, or a URL to a feature service layer. " "In JSON, it's described as a collection of mapping from zone IDs to an " "array of 3-tuples representing the interval (zmin-zmax) and the corresponding output value (zval), " "like this: { zoneId:[[zmin,zmax,zval], ...], ... }.") }, { 'name': 'zid', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Zone ID Field Name", 'description': ("Name of the field containing the Zone ID values. " "This is only applicable if the 'Zonal Thresholds' parameter contains path to a table " "or a URL to a feature service.") }, { 'name': 'zmin', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Minimum Value Field Name", 'description': ("Name of the field containing the minimum value above which an input pixel gets remapped. " "If left unspecified--or if the field value is null--pixel values are not tested for minimum. " "This is only applicable if the 'Zonal Thresholds Table' parameter contains path to a table " "or a URL to a feature service.") }, { 'name': 'zmax', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Maximum Value Field Name", 'description': ("Name of the field containing the maximum value below which an input pixel gets remapped. " "If left unspecified--or if the field value is null--pixel values are not tested for maximum. " "This is only applicable if the 'Zonal Thresholds Table' parameter contains path to a table " "or a URL to a feature service.") }, { 'name': 'zval', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Output Value Field Name", 'description': ("Name of the field containing the output value to which an input pixel gets remapped. " "If left unspecified--or if the field value is null--remapped pixel values are set " "to the 'Default Output Value'. " "This is only applicable if the 'Zonal Thresholds Table' parameter contains path to a table " "or a URL to a feature service.") }, { 'name': 'background', 'dataType': 'numeric', 'value': 0, 'required': False, 'displayName': "Background Value", 'description': ("The initial pixel value of the output raster--before input pixels are remapped.") }, { 'name': 'defzval', 'dataType': 'numeric', 'value': 255, 'required': False, 'displayName': "Default Output Value", 'description': ("The default remap/target value of threshold. " "This is the value of the output pixel if either the 'Output Value Field Name' " "parameter is left unspecified or if the output value of the corresponding " "zonal threshold is left unspecified in the Zonal Thresholds Table.") }, { 'name': 'where', 'dataType': 'string', 'value': None, 'required': False, 'displayName': "Where Clause", 'description': ("Additional query applied on the Zonal Thresholds Table. " "Only the rows that satisfy this criteria participate in the zonal remapping.") }, ] def getConfiguration(self, **scalars): return { 'inheritProperties': 2 | 4 | 8, 'invalidateProperties': 2 | 4 | 8, # invalidate statistics & histogram on the parent dataset. 'inputMask': False # Don't need input raster mask in .updatePixels(). } def updateRasterInfo(self, **kwargs): self.ztMap = None self.whereClause = None ztStr = kwargs.get('ztable', None) ztStr = ztStr.strip() or "{}" try: self.ztMap = loadJSON(ztStr) if ztStr else {} except ValueError as e: self.ztMap = None if self.ztMap is None: self.ztMap = {} self.ztTable = ZonalAttributesTable(tableUri=ztStr, idField=kwargs.get('zid', None), attribList=[kwargs.get('zmin', None), kwargs.get('zmax', None), kwargs.get('zval', None)]) self.background = int(kwargs.get('background', None) or 0) self.defaultTarget = int(kwargs.get('defzval', None) or 255) self.whereClause = kwargs.get('where', None) kwargs['output_info']['bandCount'] = 1 kwargs['output_info']['statistics'] = () kwargs['output_info']['histogram'] = () kwargs['output_info']['colormap'] = () return kwargs def updatePixels(self, tlc, shape, props, **pixelBlocks): v = pixelBlocks['vraster_pixels'][0] zoneIds = None z = pixelBlocks.get('zraster_pixels', None) if z is not None: # zone raster is optional z = z[0] zoneIds = np.unique(z) #TODO: handle no-data and mask in zone raster ZT = self.ztTable.query(idList=zoneIds, where=self.whereClause, extent=props['extent'], sr=props['spatialReference']) if self.ztTable else self.ztMap # output pixels initialized to background color p = np.full(v.shape, self.background, dtype=props['pixelType']) # use zonal thresholds to update output pixels... if ZT is not None and len(ZT.keys()): for k in (zoneIds if zoneIds is not None else [None]): T = ZT.get(k, None) # k from z might not be in ztMap if not T: continue for t in T: I = (z == k) if z is not None else np.ones(v.shape, dtype=bool) if t[0] and t[1]: # min and max are both available I = I & (v > t[0]) & (v < t[1]) elif t[0]: I = I & (v > t[0]) elif t[1]: I = I & (v < t[1]) p[I] = (t[2] if t[2] is not None else self.defaultTarget) pixelBlocks['output_pixels'] = p return pixelBlocks