def deintersect(self, theHazardLayer, theExposureLayer): """Ensure there are no intersecting features with self.layer. This should only happen after initial checks have been made. Buildings are not split up by this method. """ if not self.isValid: raise InvalidAggregatorError # These should have already been clipped to analysis extents self.hazardLayer = theHazardLayer self.exposureLayer = theExposureLayer self._prepareLayer() if not self.aoiMode: # This is a safe version of the aggregation layer self.safeLayer = safe_read_layer(str(self.layer.source())) if is_polygon_layer(self.hazardLayer): self.hazardLayer = self._preparePolygonLayer(self.hazardLayer) if is_polygon_layer(self.exposureLayer): # Find out the subcategory for this layer mySubcategory = self.keywordIO.read_keywords( self.exposureLayer, 'subcategory') # We dont want to chop up buildings! if mySubcategory != 'structure': self.exposureLayer = self._preparePolygonLayer( self.exposureLayer)
def test_isLayerPolygonal(self): """Test we can get the correct attributes back""" layer = make_polygon_layer() message = 'isPolygonLayer, %s layer should be polygonal' % layer assert is_polygon_layer(layer), message layer = make_point_layer() message = '%s layer should be polygonal' % layer assert not is_polygon_layer(layer), message layer = make_padang_layer() message = ('%s raster layer should not be polygonal' % layer) assert not is_polygon_layer(layer), message
def test_isLayerPolygonal(self): """Test we can get the correct attributes back""" myLayer = makePolygonLayer() myMessage = 'isPolygonLayer, %s layer should be polygonal' % myLayer assert is_polygon_layer(myLayer), myMessage myLayer = makePointLayer() myMessage = '%s layer should be polygonal' % myLayer assert not is_polygon_layer(myLayer), myMessage myLayer = makePadangLayer() myMessage = ('%s raster layer should not be polygonal' % myLayer) assert not is_polygon_layer(myLayer), myMessage
def test_isLayerPolygonal(self): """Test we can get the correct attributes back""" myLayer = makePolygonLayer() myMessage = 'isPolygonLayer, %s layer should be polygonal' % myLayer assert is_polygon_layer(myLayer), myMessage myLayer = makePointLayer() myMessage = '%s layer should be polygonal' % myLayer assert not is_polygon_layer(myLayer), myMessage myLayer = makePadangLayer() myMessage = ('%s raster layer should not be polygonal' % myLayer) assert not is_polygon_layer(myLayer), myMessage
def update_controls_from_list(self): """Set the ui state to match the keywords of the active layer.""" subcategory = self.get_value_for_key('subcategory') units = self.get_value_for_key('unit') data_type = self.get_value_for_key('datatype') title = self.get_value_for_key('title') if title is not None: self.leTitle.setText(title) elif self.layer is not None: layer_name = self.layer.name() self.lblLayerName.setText(self.tr('Keywords for %s' % layer_name)) else: self.lblLayerName.setText('') if not is_polygon_layer(self.layer): self.radPostprocessing.setEnabled(False) # adapt gui if we are in postprocessing category self.toggle_postprocessing_widgets() if self.radExposure.isChecked(): if subcategory is not None and data_type is not None: self.set_subcategory_list( self.standard_exposure_list, subcategory + ' [' + data_type + ']') elif subcategory is not None: self.set_subcategory_list( self.standard_exposure_list, subcategory) else: self.set_subcategory_list( self.standard_exposure_list, self.tr('Not Set')) elif self.radHazard.isChecked(): if subcategory is not None and units is not None: self.set_subcategory_list( self.standard_hazard_list, subcategory + ' [' + units + ']') elif subcategory is not None: self.set_subcategory_list( self.standard_hazard_list, subcategory) else: self.set_subcategory_list( self.standard_hazard_list, self.tr('Not Set')) self.resize_dialog()
def polygon_layers_to_combo(self): """Populate the combo with all polygon layers loaded in QGIS.""" # noinspection PyArgumentList registry = QgsMapLayerRegistry.instance() layers = registry.mapLayers().values() found_flag = False for layer in layers: name = layer.name() source = str(layer.id()) # check if layer is a vector polygon layer if is_polygon_layer(layer) or is_point_layer(layer): found_flag = True add_ordered_combo_item(self.cboPolygonLayers, name, source) if found_flag: self.cboPolygonLayers.setCurrentIndex(0)
def polygon_layers_to_combo(self): """Populate the combo with all polygon layers loaded in QGIS.""" # noinspection PyArgumentList myRegistry = QgsMapLayerRegistry.instance() myLayers = myRegistry.mapLayers().values() myFoundFlag = False for myLayer in myLayers: myName = myLayer.name() mySource = str(myLayer.id()) #check if layer is a vector polygon layer if is_polygon_layer(myLayer) or is_point_layer(myLayer): myFoundFlag = True add_ordered_combo_item(self.cboPolygonLayers, myName, mySource) if myFoundFlag: self.cboPolygonLayers.setCurrentIndex(0)
def polygon_layers_to_combo(self): """Populate the combo with all polygon layers loaded in QGIS.""" # noinspection PyArgumentList myRegistry = QgsMapLayerRegistry.instance() myLayers = myRegistry.mapLayers().values() myFoundFlag = False for myLayer in myLayers: myName = myLayer.name() mySource = str(myLayer.id()) # check if layer is a vector polygon layer if is_polygon_layer(myLayer) or is_point_layer(myLayer): myFoundFlag = True add_ordered_combo_item(self.cboPolygonLayers, myName, mySource) if myFoundFlag: self.cboPolygonLayers.setCurrentIndex(0)
def polygon_layers_to_combo(self): """Populate the combo with all polygon layers loaded in QGIS.""" # noinspection PyArgumentList registry = QgsMapLayerRegistry.instance() layers = registry.mapLayers().values() found_flag = False for layer in layers: name = layer.name() source = str(layer.id()) # check if layer is a vector polygon layer if is_polygon_layer(layer) or is_point_layer(layer): found_flag = True add_ordered_combo_item(self.cboPolygonLayers, name, source) if found_flag: self.cboPolygonLayers.setCurrentIndex(0)
def update_controls_from_list(self): """Set the ui state to match the keywords of the active layer.""" mySubcategory = self.get_value_for_key('subcategory') myUnits = self.get_value_for_key('unit') myType = self.get_value_for_key('datatype') myTitle = self.get_value_for_key('title') if myTitle is not None: self.leTitle.setText(myTitle) elif self.layer is not None: myLayerName = self.layer.name() self.lblLayerName.setText(self.tr('Keywords for %s' % myLayerName)) else: self.lblLayerName.setText('') if not is_polygon_layer(self.layer): self.radPostprocessing.setEnabled(False) #adapt gui if we are in postprocessing category self.toggle_postprocessing_widgets() if self.radExposure.isChecked(): if mySubcategory is not None and myType is not None: self.set_subcategory_list( self.standardExposureList, mySubcategory + ' [' + myType + ']') elif mySubcategory is not None: self.set_subcategory_list( self.standardExposureList, mySubcategory) else: self.set_subcategory_list( self.standardExposureList, self.tr('Not Set')) elif self.radHazard.isChecked(): if mySubcategory is not None and myUnits is not None: self.set_subcategory_list( self.standardHazardList, mySubcategory + ' [' + myUnits + ']') elif mySubcategory is not None: self.set_subcategory_list( self.standardHazardList, mySubcategory) else: self.set_subcategory_list( self.standardHazardList, self.tr('Not Set')) self.resize_dialog()
def update_controls_from_list(self): """Set the ui state to match the keywords of the active layer.""" mySubcategory = self.get_value_for_key("subcategory") myUnits = self.get_value_for_key("unit") myType = self.get_value_for_key("datatype") myTitle = self.get_value_for_key("title") if myTitle is not None: self.leTitle.setText(myTitle) elif self.layer is not None: myLayerName = self.layer.name() self.lblLayerName.setText(self.tr("Keywords for %s" % myLayerName)) else: self.lblLayerName.setText("") if not is_polygon_layer(self.layer): self.radPostprocessing.setEnabled(False) # adapt gui if we are in postprocessing category self.toggle_postprocessing_widgets() if self.radExposure.isChecked(): if mySubcategory is not None and myType is not None: self.set_subcategory_list(self.standardExposureList, mySubcategory + " [" + myType + "]") elif mySubcategory is not None: self.set_subcategory_list(self.standardExposureList, mySubcategory) else: self.set_subcategory_list(self.standardExposureList, self.tr("Not Set")) elif self.radHazard.isChecked(): if mySubcategory is not None and myUnits is not None: self.set_subcategory_list(self.standardHazardList, mySubcategory + " [" + myUnits + "]") elif mySubcategory is not None: self.set_subcategory_list(self.standardHazardList, mySubcategory) else: self.set_subcategory_list(self.standardHazardList, self.tr("Not Set")) self.resize_dialog()
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, 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 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 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 __init__(self, parent, iface, dock=None, layer=None): """Constructor for the dialog. .. note:: In QtDesigner the advanced editor's predefined keywords list should be shown in english always, so when adding entries to cboKeyword, be sure to choose :safe_qgis:`Properties<<` and untick the :safe_qgis:`translatable` property. :param parent: Parent widget of this dialog. :type parent: QWidget :param iface: Quantum GIS QGisAppInterface instance. :type iface: QGisAppInterface :param dock: Dock widget instance that we can notify of changes to the keywords. Optional. :type dock: Dock """ QtGui.QDialog.__init__(self, parent) self.setupUi(self) self.setWindowTitle( self.tr('InaSAFE %s Keywords Editor' % get_version())) # Save reference to the QGIS interface and parent self.iface = iface self.parent = parent self.dock = dock self.defaults = None # string constants self.global_default_string = metadata.global_default_attribute['name'] self.do_not_use_string = metadata.do_not_use_attribute['name'] self.global_default_data = metadata.global_default_attribute['id'] self.do_not_use_data = metadata.do_not_use_attribute['id'] if layer is None: self.layer = self.iface.activeLayer() else: self.layer = layer self.keyword_io = KeywordIO() # note the keys should remain untranslated as we need to write # english to the keywords file. The keys will be written as user data # in the combo entries. # .. seealso:: http://www.voidspace.org.uk/python/odict.html self.standard_exposure_list = OrderedDict([ ('population', self.tr('population')), ('structure', self.tr('structure')), ('road', self.tr('road')), ('Not Set', self.tr('Not Set')) ]) self.standard_hazard_list = OrderedDict([ ('earthquake [MMI]', self.tr('earthquake [MMI]')), ('tsunami [m]', self.tr('tsunami [m]')), ('tsunami [wet/dry]', self.tr('tsunami [wet/dry]')), ('tsunami [feet]', self.tr('tsunami [feet]')), ('flood [m]', self.tr('flood [m]')), ('flood [wet/dry]', self.tr('flood [wet/dry]')), ('flood [feet]', self.tr('flood [feet]')), ('tephra [kg2/m2]', self.tr('tephra [kg2/m2]')), ('volcano', self.tr('volcano')), ('generic [categorised]', self.tr('generic [categorised]')), ('Not Set', self.tr('Not Set')) ]) # noinspection PyUnresolvedReferences self.lstKeywords.itemClicked.connect(self.edit_key_value_pair) # Set up help dialog showing logic. help_button = self.buttonBox.button(QtGui.QDialogButtonBox.Help) help_button.clicked.connect(self.show_help) if self.layer is not None and is_polygon_layer(self.layer): # set some initial ui state: self.defaults = get_defaults() self.radPredefined.setChecked(True) self.dsbFemaleRatioDefault.blockSignals(True) self.dsbFemaleRatioDefault.setValue(self.defaults['FEMALE_RATIO']) self.dsbFemaleRatioDefault.blockSignals(False) self.dsbYouthRatioDefault.blockSignals(True) self.dsbYouthRatioDefault.setValue(self.defaults['YOUTH_RATIO']) self.dsbYouthRatioDefault.blockSignals(False) self.dsbAdultRatioDefault.blockSignals(True) self.dsbAdultRatioDefault.setValue(self.defaults['ADULT_RATIO']) self.dsbAdultRatioDefault.blockSignals(False) self.dsbElderlyRatioDefault.blockSignals(True) self.dsbElderlyRatioDefault.setValue( self.defaults['ELDERLY_RATIO']) self.dsbElderlyRatioDefault.blockSignals(False) else: self.radPostprocessing.hide() self.tab_widget.removeTab(1) if self.layer: self.load_state_from_keywords() # add a reload from keywords button reload_button = self.buttonBox.addButton( self.tr('Reload'), QtGui.QDialogButtonBox.ActionRole) reload_button.clicked.connect(self.load_state_from_keywords) self.resize_dialog() self.tab_widget.setCurrentIndex(0) # TODO No we should not have test related stuff in prod code. TS self.test = False
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 __init__(self, parent, iface, dock=None, layer=None): """Constructor for the dialog. .. note:: In QtDesigner the advanced editor's predefined keywords list should be shown in english always, so when adding entries to cboKeyword, be sure to choose :safe_qgis:`Properties<<` and untick the :safe_qgis:`translatable` property. :param parent: Parent widget of this dialog. :type parent: QWidget :param iface: Quantum GIS QGisAppInterface instance. :type iface: QGisAppInterface :param dock: Dock widget instance that we can notify of changes to the keywords. Optional. :type dock: Dock """ QtGui.QDialog.__init__(self, parent) self.setupUi(self) self.setWindowTitle(self.tr( 'InaSAFE %s Keywords Editor' % get_version())) # Save reference to the QGIS interface and parent self.iface = iface self.parent = parent self.dock = dock self.defaults = None # string constants self.global_default_string = metadata.global_default_attribute['name'] self.do_not_use_string = metadata.do_not_use_attribute['name'] self.global_default_data = metadata.global_default_attribute['id'] self.do_not_use_data = metadata.do_not_use_attribute['id'] if layer is None: self.layer = self.iface.activeLayer() else: self.layer = layer self.keyword_io = KeywordIO() # note the keys should remain untranslated as we need to write # english to the keywords file. The keys will be written as user data # in the combo entries. # .. seealso:: http://www.voidspace.org.uk/python/odict.html self.standard_exposure_list = OrderedDict( [('population', self.tr('population')), ('structure', self.tr('structure')), ('road', self.tr('road')), ('Not Set', self.tr('Not Set'))]) self.standard_hazard_list = OrderedDict( [('earthquake [MMI]', self.tr('earthquake [MMI]')), ('tsunami [m]', self.tr('tsunami [m]')), ('tsunami [wet/dry]', self.tr('tsunami [wet/dry]')), ('tsunami [feet]', self.tr('tsunami [feet]')), ('flood [m]', self.tr('flood [m]')), ('flood [wet/dry]', self.tr('flood [wet/dry]')), ('flood [feet]', self.tr('flood [feet]')), ('tephra [kg2/m2]', self.tr('tephra [kg2/m2]')), ('volcano', self.tr('volcano')), ('generic [categorised]', self.tr('generic [categorised]')), ('Not Set', self.tr('Not Set'))]) # noinspection PyUnresolvedReferences self.lstKeywords.itemClicked.connect(self.edit_key_value_pair) # Set up help dialog showing logic. help_button = self.buttonBox.button(QtGui.QDialogButtonBox.Help) help_button.clicked.connect(self.show_help) if self.layer is not None and is_polygon_layer(self.layer): # set some initial ui state: self.defaults = get_defaults() self.radPredefined.setChecked(True) self.dsbFemaleRatioDefault.blockSignals(True) self.dsbFemaleRatioDefault.setValue(self.defaults['FEMALE_RATIO']) self.dsbFemaleRatioDefault.blockSignals(False) self.dsbYouthRatioDefault.blockSignals(True) self.dsbYouthRatioDefault.setValue(self.defaults['YOUTH_RATIO']) self.dsbYouthRatioDefault.blockSignals(False) self.dsbAdultRatioDefault.blockSignals(True) self.dsbAdultRatioDefault.setValue(self.defaults['ADULT_RATIO']) self.dsbAdultRatioDefault.blockSignals(False) self.dsbElderlyRatioDefault.blockSignals(True) self.dsbElderlyRatioDefault.setValue( self.defaults['ELDERLY_RATIO']) self.dsbElderlyRatioDefault.blockSignals(False) else: self.radPostprocessing.hide() self.tab_widget.removeTab(1) if self.layer: self.load_state_from_keywords() # add a reload from keywords button reload_button = self.buttonBox.addButton( self.tr('Reload'), QtGui.QDialogButtonBox.ActionRole) reload_button.clicked.connect(self.load_state_from_keywords) self.resize_dialog() self.tab_widget.setCurrentIndex(0) # TODO No we should not have test related stuff in prod code. TS self.test = False