def layer_changed(self, layer): """Enable or disable keywords editor icon when active layer changes. :param layer: The layer that is now active. :type layer: QgsMapLayer """ if not layer: self._disable_keyword_tools() return if not hasattr(layer, 'providerType'): self._disable_keyword_tools() return if layer.providerType() == 'wms': self._disable_keyword_tools() return if is_raster_layer(layer) and layer.bandCount() > 1: self._disable_keyword_tools() return self.action_keywords_dialog.setEnabled(True) self.action_keywords_wizard.setEnabled(True)
def calculate_zonal_stats(raster_layer, polygon_layer): """Calculate zonal statics given two layers. :param raster_layer: A QGIS raster layer. :type raster_layer: QgsRasterLayer :param polygon_layer: A QGIS vector layer containing polygons. :type polygon_layer: QgsVectorLayer, QgsMapLayer :returns: A data structure containing sum, mean, min, max, count of raster values for each polygonal area. :rtype: dict :raises: InvalidParameterError, InvalidGeometryError Note: * InvalidParameterError if incorrect inputs are received. * InvalidGeometryError if none geometry is found during calculations. * Any other exceptions are propagated. Example of output data structure: { 1: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}, 2: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}, 3 {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}} The key in the outer dict is the feature id .. note:: This is a python port of the zonal stats implementation in QGIS . See https://github.com/qgis/Quantum-GIS/blob/master/src/analysis/ vector/qgszonalstatistics.cpp .. note:: Currently not projection checks are made to ensure that both layers are in the same CRS - we assume they are. """ if not is_polygon_layer(polygon_layer): raise InvalidParameterError( tr('Zonal stats needs a polygon layer in order to compute ' 'statistics.')) if not is_raster_layer(raster_layer): raise InvalidParameterError( tr('Zonal stats needs a raster layer in order to compute statistics.' )) LOGGER.debug('Calculating zonal stats for:') LOGGER.debug('Raster: %s' % raster_layer.source()) LOGGER.debug('Vector: %s' % polygon_layer.source()) myResults = {} myRasterSource = raster_layer.source() myFid = gdal.Open(str(myRasterSource), gdal.GA_ReadOnly) myGeoTransform = myFid.GetGeoTransform() myColumns = myFid.RasterXSize myRows = myFid.RasterYSize # Get first band. myBand = myFid.GetRasterBand(1) myNoData = myBand.GetNoDataValue() #print 'No data %s' % myNoData myCellSizeX = myGeoTransform[1] if myCellSizeX < 0: myCellSizeX = -myCellSizeX myCellSizeY = myGeoTransform[5] if myCellSizeY < 0: myCellSizeY = -myCellSizeY myRasterBox = QgsRectangle(myGeoTransform[0], myGeoTransform[3] - (myCellSizeY * myRows), myGeoTransform[0] + (myCellSizeX * myColumns), myGeoTransform[3]) rasterGeom = QgsGeometry.fromRect(myRasterBox) # Get vector layer myProvider = polygon_layer.dataProvider() if myProvider is None: myMessage = tr('Could not obtain data provider from layer "%s"') % ( polygon_layer.source()) raise Exception(myMessage) myRequest = QgsFeatureRequest() crs = osr.SpatialReference() crs.ImportFromProj4(str(polygon_layer.crs().toProj4())) myCount = 0 for myFeature in myProvider.getFeatures(myRequest): myGeometry = myFeature.geometry() if myGeometry is None: myMessage = tr('Feature %d has no geometry or geometry is invalid' ) % (myFeature.id()) raise InvalidGeometryError(myMessage) myCount += 1 myFeatureBox = myGeometry.boundingBox().intersect(myRasterBox) print 'NEW AGGR: %s' % myFeature.id() #print 'Raster Box: %s' % myRasterBox.asWktCoordinates() #print 'Feature Box: %s' % myFeatureBox.asWktCoordinates() myOffsetX, myOffsetY, myCellsX, myCellsY = intersection_box( myRasterBox, myFeatureBox, myCellSizeX, myCellSizeY) # If the poly does not intersect the raster just continue if None in [myOffsetX, myOffsetY, myCellsX, myCellsY]: continue # avoid access to cells outside of the raster (may occur because of # rounding) if (myOffsetX + myCellsX) > myColumns: myOffsetX = myColumns - myOffsetX if (myOffsetY + myCellsY) > myRows: myCellsY = myRows - myOffsetY myIntersectedGeom = rasterGeom.intersection(myGeometry) mySum, myCount = numpy_stats(myBand, myIntersectedGeom, myGeoTransform, myNoData, crs) if myCount <= 1: # The cell resolution is probably larger than the polygon area. # We switch to precise pixel - polygon intersection in this case mySum, myCount = precise_stats(myBand, myGeometry, myOffsetX, myOffsetY, myCellsX, myCellsY, myCellSizeX, myCellSizeY, myRasterBox, myNoData) #print mySum, myCount if myCount == 0: myMean = 0 else: myMean = mySum / myCount myResults[myFeature.id()] = { 'sum': mySum, 'count': myCount, 'mean': myMean } # noinspection PyUnusedLocal myFid = None # Close return myResults
def calculate_zonal_stats(raster_layer, polygon_layer): """Calculate zonal statics given two layers. :param raster_layer: A QGIS raster layer. :type raster_layer: QgsRasterLayer :param polygon_layer: A QGIS vector layer containing polygons. :type polygon_layer: QgsVectorLayer :returns: A data structure containing sum, mean, min, max, count of raster values for each polygonal area. :rtype: dict :raises: InvalidParameterError, InvalidGeometryError Note: * InvalidParameterError if incorrect inputs are received. * InvalidGeometryError if none geometry is found during calculations. * Any other exceptions are propagated. Example of output data structure: { 1: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}, 2: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}, 3 {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}} The key in the outer dict is the feature id .. note:: This is a python port of the zonal stats implementation in QGIS . See https://github.com/qgis/Quantum-GIS/blob/master/src/analysis/ vector/qgszonalstatistics.cpp .. note:: Currently not projection checks are made to ensure that both layers are in the same CRS - we assume they are. """ if not is_polygon_layer(polygon_layer): raise InvalidParameterError(tr("Zonal stats needs a polygon layer in order to compute " "statistics.")) if not is_raster_layer(raster_layer): raise InvalidParameterError(tr("Zonal stats needs a raster layer in order to compute statistics.")) LOGGER.debug("Calculating zonal stats for:") LOGGER.debug("Raster: %s" % raster_layer.source()) LOGGER.debug("Vector: %s" % polygon_layer.source()) myResults = {} myRasterSource = raster_layer.source() myFid = gdal.Open(str(myRasterSource), gdal.GA_ReadOnly) myGeoTransform = myFid.GetGeoTransform() myColumns = myFid.RasterXSize myRows = myFid.RasterYSize # Get first band. myBand = myFid.GetRasterBand(1) myNoData = myBand.GetNoDataValue() # print 'No data %s' % myNoData myCellSizeX = myGeoTransform[1] if myCellSizeX < 0: myCellSizeX = -myCellSizeX myCellSizeY = myGeoTransform[5] if myCellSizeY < 0: myCellSizeY = -myCellSizeY myRasterBox = QgsRectangle( myGeoTransform[0], myGeoTransform[3] - (myCellSizeY * myRows), myGeoTransform[0] + (myCellSizeX * myColumns), myGeoTransform[3], ) rasterGeom = QgsGeometry.fromRect(myRasterBox) # Get vector layer myProvider = polygon_layer.dataProvider() if myProvider is None: myMessage = tr('Could not obtain data provider from layer "%s"') % (polygon_layer.source()) raise Exception(myMessage) myRequest = QgsFeatureRequest() crs = osr.SpatialReference() crs.ImportFromProj4(str(polygon_layer.crs().toProj4())) myCount = 0 for myFeature in myProvider.getFeatures(myRequest): myGeometry = myFeature.geometry() if myGeometry is None: myMessage = tr("Feature %d has no geometry or geometry is invalid") % (myFeature.id()) raise InvalidGeometryError(myMessage) myCount += 1 myFeatureBox = myGeometry.boundingBox().intersect(myRasterBox) print "NEW AGGR: %s" % myFeature.id() # print 'Raster Box: %s' % myRasterBox.asWktCoordinates() # print 'Feature Box: %s' % myFeatureBox.asWktCoordinates() myOffsetX, myOffsetY, myCellsX, myCellsY = intersection_box(myRasterBox, myFeatureBox, myCellSizeX, myCellSizeY) # If the poly does not intersect the raster just continue if None in [myOffsetX, myOffsetY, myCellsX, myCellsY]: continue # avoid access to cells outside of the raster (may occur because of # rounding) if (myOffsetX + myCellsX) > myColumns: myOffsetX = myColumns - myOffsetX if (myOffsetY + myCellsY) > myRows: myCellsY = myRows - myOffsetY myIntersectedGeom = rasterGeom.intersection(myGeometry) mySum, myCount = numpy_stats(myBand, myIntersectedGeom, myGeoTransform, myNoData, crs) if myCount <= 1: # The cell resolution is probably larger than the polygon area. # We switch to precise pixel - polygon intersection in this case mySum, myCount = precise_stats( myBand, myGeometry, myOffsetX, myOffsetY, myCellsX, myCellsY, myCellSizeX, myCellSizeY, myRasterBox, myNoData, ) # print mySum, myCount if myCount == 0: myMean = 0 else: myMean = mySum / myCount myResults[myFeature.id()] = {"sum": mySum, "count": myCount, "mean": myMean} # noinspection PyUnusedLocal myFid = None # Close return myResults
def calculate_zonal_stats(raster_layer, polygon_layer): """Calculate zonal statics given two layers. :param raster_layer: A QGIS raster layer. :type raster_layer: QgsRasterLayer, QgsMapLayer :param polygon_layer: A QGIS vector layer containing polygons. :type polygon_layer: QgsVectorLayer, QgsMapLayer :returns: A data structure containing sum, mean, min, max, count of raster values for each polygonal area. :rtype: dict :raises: InvalidParameterError, InvalidGeometryError Note: * InvalidParameterError if incorrect inputs are received. * InvalidGeometryError if none geometry is found during calculations. * Any other exceptions are propagated. Example of output data structure: { 1: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}, 2: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}, 3 {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}} The key in the outer dict is the feature id .. note:: This is a python port of the zonal stats implementation in QGIS . See https://github.com/qgis/Quantum-GIS/blob/master/src/analysis/ vector/qgszonalstatistics.cpp .. note:: Currently not projection checks are made to ensure that both layers are in the same CRS - we assume they are. """ if not is_polygon_layer(polygon_layer): raise InvalidParameterError( tr('Zonal stats needs a polygon layer in order to compute ' 'statistics.')) if not is_raster_layer(raster_layer): raise InvalidParameterError( tr('Zonal stats needs a raster layer in order to compute statistics.' )) LOGGER.debug('Calculating zonal stats for:') LOGGER.debug('Raster: %s' % raster_layer.source()) LOGGER.debug('Vector: %s' % polygon_layer.source()) results = {} raster_source = raster_layer.source() feature_id = gdal.Open(str(raster_source), gdal.GA_ReadOnly) geo_transform = feature_id.GetGeoTransform() columns = feature_id.RasterXSize rows = feature_id.RasterYSize # Get first band. band = feature_id.GetRasterBand(1) no_data = band.GetNoDataValue() #print 'No data %s' % no_data cell_size_x = geo_transform[1] if cell_size_x < 0: cell_size_x = -cell_size_x cell_size_y = geo_transform[5] if cell_size_y < 0: cell_size_y = -cell_size_y raster_box = QgsRectangle(geo_transform[0], geo_transform[3] - (cell_size_y * rows), geo_transform[0] + (cell_size_x * columns), geo_transform[3]) #noinspection PyCallByClass,PyTypeChecker,PyArgumentList raster_geometry = QgsGeometry.fromRect(raster_box) # Get vector layer provider = polygon_layer.dataProvider() if provider is None: message = tr('Could not obtain data provider from layer "%s"') % ( polygon_layer.source()) raise Exception(message) request = QgsFeatureRequest() crs = osr.SpatialReference() crs.ImportFromProj4(str(polygon_layer.crs().toProj4())) count = 0 for myFeature in provider.getFeatures(request): geometry = myFeature.geometry() if geometry is None: message = tr('Feature %d has no geometry or geometry is invalid' ) % (myFeature.id()) raise InvalidGeometryError(message) count += 1 feature_box = geometry.boundingBox().intersect(raster_box) print 'NEW AGGR: %s' % myFeature.id() #print 'Raster Box: %s' % raster_box.asWktCoordinates() #print 'Feature Box: %s' % feature_box.asWktCoordinates() offset_x, offset_y, cells_x, cells_y = intersection_box( raster_box, feature_box, cell_size_x, cell_size_y) # If the poly does not intersect the raster just continue if None in [offset_x, offset_y, cells_x, cells_y]: continue # avoid access to cells outside of the raster (may occur because of # rounding) if (offset_x + cells_x) > columns: offset_x = columns - offset_x if (offset_y + cells_y) > rows: cells_y = rows - offset_y intersected_geometry = raster_geometry.intersection(geometry) geometry_sum, count = numpy_stats(band, intersected_geometry, geo_transform, no_data, crs) if count <= 1: # The cell resolution is probably larger than the polygon area. # We switch to precise pixel - polygon intersection in this case geometry_sum, count = precise_stats(band, geometry, offset_x, offset_y, cells_x, cells_y, cell_size_x, cell_size_y, raster_box, no_data) #print geometry_sum, count if count == 0: mean = 0 else: mean = geometry_sum / count results[myFeature.id()] = { 'sum': geometry_sum, 'count': count, 'mean': mean } # noinspection PyUnusedLocal feature_id = None # Close return results
def calculateZonalStats(theRasterLayer, thePolygonLayer): """Calculate zonal statics given two layers. :param theRasterLayer: A QGIS raster layer. :type theRasterLayer: QgsRasterLayer :param thePolygonLayer: A QGIS vector layer containing polygons. :type thePolygonLayer: QgsVectorLayer :returns: A data structure containing sum, mean, min, max, count of raster values for each polygonal area. :rtype: dict :raises: InvalidParameterError Note: * InvalidParameterError if incorrect inputs are received. * Any other exceptions are propogated. Example of output data structure: { 1: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}, 2: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}, 3 {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}} The key in the outer dict is the feature id .. note:: This is a python port of the zonal stats implementation in QGIS . See https://github.com/qgis/Quantum-GIS/blob/master/src/analysis/ vector/qgszonalstatistics.cpp .. note:: Currently not projection checks are made to ensure that both layers are in the same CRS - we assume they are. """ if not is_polygon_layer(thePolygonLayer): raise InvalidParameterError(tr( 'Zonal stats needs a polygon layer in order to compute ' 'statistics.')) if not is_raster_layer(theRasterLayer): raise InvalidParameterError(tr( 'Zonal stats needs a raster layer in order to compute statistics.' )) LOGGER.debug('Calculating zonal stats for:') LOGGER.debug('Raster: %s' % theRasterLayer.source()) LOGGER.debug('Vector: %s' % thePolygonLayer.source()) myResults = {} myRasterSource = theRasterLayer.source() myFid = gdal.Open(str(myRasterSource), gdal.GA_ReadOnly) myGeoTransform = myFid.GetGeoTransform() myColumns = myFid.RasterXSize myRows = myFid.RasterYSize #myBandCount = myFid.RasterCount # Get first band. myBand = myFid.GetRasterBand(1) myNoData = myBand.GetNoDataValue() #print 'No data %s' % myNoData myCellSizeX = myGeoTransform[1] if myCellSizeX < 0: myCellSizeX = -myCellSizeX myCellSizeY = myGeoTransform[5] if myCellSizeY < 0: myCellSizeY = -myCellSizeY myRasterBox = QgsRectangle( myGeoTransform[0], myGeoTransform[3] - (myCellSizeY * myRows), myGeoTransform[0] + (myCellSizeX * myColumns), myGeoTransform[3]) # Get vector layer myProvider = thePolygonLayer.dataProvider() if myProvider is None: myMessage = tr( 'Could not obtain data provider from layer "%1"').arg( thePolygonLayer.source()) raise Exception(myMessage) myFeature = QgsFeature() myCount = 0 while myProvider.nextFeature(myFeature): myGeometry = myFeature.geometry() myCount += 1 myFeatureBox = myGeometry.boundingBox().intersect(myRasterBox) print 'NEW AGGR: %s' % myFeature.id() #print 'Raster Box: %s' % myRasterBox.asWktCoordinates() #print 'Feature Box: %s' % myFeatureBox.asWktCoordinates() myOffsetX, myOffsetY, myCellsX, myCellsY = cellInfoForBBox( myRasterBox, myFeatureBox, myCellSizeX, myCellSizeY) # If the poly does not intersect the raster just continue if None in [myOffsetX, myOffsetY, myCellsX, myCellsY]: continue # avoid access to cells outside of the raster (may occur because of # rounding) if (myOffsetX + myCellsX) > myColumns: myOffsetX = myColumns - myOffsetX if (myOffsetY + myCellsY) > myRows: myCellsY = myRows - myOffsetY mySum, myCount = statisticsFromMiddlePointTest( myBand, myGeometry, myOffsetX, myOffsetY, myCellsX, myCellsY, myCellSizeX, myCellSizeY, myRasterBox, myNoData) #print 'Sum: %s count: %s' % (mySum, myCount) if myCount <= 1: # The cell resolution is probably larger than the polygon area. # We switch to precise pixel - polygon intersection in this case mySum, myCount = statisticsFromPreciseIntersection( myBand, myGeometry, myOffsetX, myOffsetY, myCellsX, myCellsY, myCellSizeX, myCellSizeY, myRasterBox, myNoData) #print mySum, myCount if myCount == 0: myMean = 0 else: myMean = mySum / myCount myResults[myFeature.id()] = { 'sum': mySum, 'count': myCount, 'mean': myMean} myFid = None # Close return myResults
def calculate_zonal_stats(raster_layer, polygon_layer): """Calculate zonal statics given two layers. :param raster_layer: A QGIS raster layer. :type raster_layer: QgsRasterLayer, QgsMapLayer :param polygon_layer: A QGIS vector layer containing polygons. :type polygon_layer: QgsVectorLayer, QgsMapLayer :returns: A data structure containing sum, mean, min, max, count of raster values for each polygonal area. :rtype: dict :raises: InvalidParameterError, InvalidGeometryError Note: * InvalidParameterError if incorrect inputs are received. * InvalidGeometryError if none geometry is found during calculations. * Any other exceptions are propagated. Example of output data structure: { 1: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}, 2: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}, 3 {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}} The key in the outer dict is the feature id .. note:: This is a python port of the zonal stats implementation in QGIS . See https://github.com/qgis/Quantum-GIS/blob/master/src/analysis/ vector/qgszonalstatistics.cpp .. note:: Currently not projection checks are made to ensure that both layers are in the same CRS - we assume they are. """ if not is_polygon_layer(polygon_layer): raise InvalidParameterError(tr( 'Zonal stats needs a polygon layer in order to compute ' 'statistics.')) if not is_raster_layer(raster_layer): raise InvalidParameterError(tr( 'Zonal stats needs a raster layer in order to compute statistics.' )) LOGGER.debug('Calculating zonal stats for:') LOGGER.debug('Raster: %s' % raster_layer.source()) LOGGER.debug('Vector: %s' % polygon_layer.source()) results = {} raster_source = raster_layer.source() feature_id = gdal.Open(str(raster_source), gdal.GA_ReadOnly) geo_transform = feature_id.GetGeoTransform() columns = feature_id.RasterXSize rows = feature_id.RasterYSize # Get first band. band = feature_id.GetRasterBand(1) no_data = band.GetNoDataValue() # print 'No data %s' % no_data cell_size_x = geo_transform[1] if cell_size_x < 0: cell_size_x = -cell_size_x cell_size_y = geo_transform[5] if cell_size_y < 0: cell_size_y = -cell_size_y raster_box = QgsRectangle( geo_transform[0], geo_transform[3] - (cell_size_y * rows), geo_transform[0] + (cell_size_x * columns), geo_transform[3]) # noinspection PyCallByClass,PyTypeChecker,PyArgumentList raster_geometry = QgsGeometry.fromRect(raster_box) # Get vector layer provider = polygon_layer.dataProvider() if provider is None: message = tr( 'Could not obtain data provider from layer "%s"') % ( polygon_layer.source()) raise Exception(message) request = QgsFeatureRequest() crs = osr.SpatialReference() crs.ImportFromProj4(str(polygon_layer.crs().toProj4())) count = 0 for myFeature in provider.getFeatures(request): geometry = myFeature.geometry() if geometry is None: message = tr( 'Feature %d has no geometry or geometry is invalid') % ( myFeature.id()) raise InvalidGeometryError(message) count += 1 feature_box = geometry.boundingBox().intersect(raster_box) print 'NEW AGGR: %s' % myFeature.id() # print 'Raster Box: %s' % raster_box.asWktCoordinates() # print 'Feature Box: %s' % feature_box.asWktCoordinates() offset_x, offset_y, cells_x, cells_y = intersection_box( raster_box, feature_box, cell_size_x, cell_size_y) # If the poly does not intersect the raster just continue if None in [offset_x, offset_y, cells_x, cells_y]: continue # avoid access to cells outside of the raster (may occur because of # rounding) if (offset_x + cells_x) > columns: offset_x = columns - offset_x if (offset_y + cells_y) > rows: cells_y = rows - offset_y intersected_geometry = raster_geometry.intersection(geometry) geometry_sum, count = numpy_stats( band, intersected_geometry, geo_transform, no_data, crs) if count <= 1: # The cell resolution is probably larger than the polygon area. # We switch to precise pixel - polygon intersection in this case geometry_sum, count = precise_stats( band, geometry, offset_x, offset_y, cells_x, cells_y, cell_size_x, cell_size_y, raster_box, no_data) # print geometry_sum, count if count == 0: mean = 0 else: mean = geometry_sum / count results[myFeature.id()] = { 'sum': geometry_sum, 'count': count, 'mean': mean} # noinspection PyUnusedLocal feature_id = None # Close return results