Пример #1
0
    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)
Пример #2
0
    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
Пример #3
0
    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
Пример #4
0
    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
Пример #5
0
    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)
Пример #7
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)
Пример #8
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)
Пример #9
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)
Пример #10
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()
Пример #11
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()
Пример #12
0
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
Пример #13
0
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
Пример #14
0
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
Пример #15
0
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
Пример #16
0
    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
Пример #17
0
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
Пример #18
0
    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