def accept(self):
        """Do raster reclassification and display it in QGIS

        .. versionadded: 3.4

        :return:
        """
        registry = QgsMapLayerRegistry.instance()
        try:
            index = self.cbo_raster_input.currentIndex()
            layer_id = self.cbo_raster_input.itemData(
                index, QtCore.Qt.UserRole)
            layer = registry.mapLayer(layer_id)
            class_attribute = 'class'
            # extract thresholds
            thresholds_list = self.thresholds_widget.get_parameter().value
            thresholds_list.append(None)
            ranges = ranges_according_thresholds_list(thresholds_list)

            path = reclassify_polygonize(
                layer.source(), ranges, name_field=class_attribute)

            # load layer to QGIS
            title = self.tr('%s classified') % self.tr(layer.name())
            layer = QgsVectorLayer(path, title, 'ogr')
            registry.addMapLayer(layer)
        except Exception as e:
            LOGGER.exception(e)

        QtGui.qApp.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
        self.disable_busy_cursor()
        self.done(QDialog.Accepted)
Example #2
0
    def test_reclassify_polygonize(self):
        """Test if we can reclassify a raster according to some thresholds."""

        raster_path = standard_data_path('hazard',
                                         'continuous_flood_20_20.asc')

        ranges = OrderedDict()

        # value <= 0.2
        ranges[1] = [None, 0.2]
        # 0.2 < value <= 1
        ranges[2] = [0.2, 1]
        # 1 < value <= 1.3 and gap in output classes
        ranges[10] = [1, 1.3]
        # value > 1.3
        ranges[11] = [1.3, None]

        output = reclassify_polygonize(raster_path, ranges)

        layer = QgsVectorLayer(output, 'test layer', 'ogr')
        self.assertEqual(layer.featureCount(), 61)

        expression = '"DN" = \'%s\'' % 1
        request = QgsFeatureRequest().setFilterExpression(expression)
        self.assertEqual(sum(1 for _ in layer.getFeatures(request)), 20)

        expression = '"DN" = \'%s\'' % 2
        request = QgsFeatureRequest().setFilterExpression(expression)
        self.assertEqual(sum(1 for _ in layer.getFeatures(request)), 1)

        expression = '"DN" = \'%s\'' % 10
        request = QgsFeatureRequest().setFilterExpression(expression)
        self.assertEqual(sum(1 for _ in layer.getFeatures(request)), 20)

        expression = '"DN" = \'%s\'' % 11
        request = QgsFeatureRequest().setFilterExpression(expression)
        self.assertEqual(sum(1 for _ in layer.getFeatures(request)), 20)
Example #3
0
    def test_reclassify_polygonize(self):
        """Test if we can reclassify a raster according to some thresholds."""

        raster_path = standard_data_path(
            'hazard', 'continuous_flood_20_20.asc')

        ranges = OrderedDict()

        # value <= 0.2
        ranges[1] = [None, 0.2]
        # 0.2 < value <= 1
        ranges[2] = [0.2, 1]
        # 1 < value <= 1.3 and gap in output classes
        ranges[10] = [1, 1.3]
        # value > 1.3
        ranges[11] = [1.3, None]

        output = reclassify_polygonize(raster_path, ranges)

        layer = QgsVectorLayer(output, 'test layer', 'ogr')
        self.assertEqual(layer.featureCount(), 61)

        expression = '"DN" = \'%s\'' % 1
        request = QgsFeatureRequest().setFilterExpression(expression)
        self.assertEqual(sum(1 for _ in layer.getFeatures(request)), 20)

        expression = '"DN" = \'%s\'' % 2
        request = QgsFeatureRequest().setFilterExpression(expression)
        self.assertEqual(sum(1 for _ in layer.getFeatures(request)), 1)

        expression = '"DN" = \'%s\'' % 10
        request = QgsFeatureRequest().setFilterExpression(expression)
        self.assertEqual(sum(1 for _ in layer.getFeatures(request)), 20)

        expression = '"DN" = \'%s\'' % 11
        request = QgsFeatureRequest().setFilterExpression(expression)
        self.assertEqual(sum(1 for _ in layer.getFeatures(request)), 20)
Example #4
0
    def run(self):
        """Run the impact function.

        :returns: A vector layer with affected areas marked.
        :type: safe_layer
        """
        hazard_layer = self.hazard.layer
        exposure = self.exposure.layer

        # Thresholds for tsunami hazard zone breakdown.
        group_parameters = self.parameters['group_threshold']
        ver_low_unit = group_parameters.value_map['very_low_threshold'].unit
        unit_abbrev = ver_low_unit.abbreviation
        unaffected_threshold = group_parameters.value_map[
            'unaffected_threshold']
        unaffected_max = unaffected_threshold.value
        very_low_max = group_parameters.value_map['very_low_threshold'].value
        low_max = group_parameters.value_map['low_threshold'].value
        medium_max = group_parameters.value_map['moderate_threshold'].value
        high_max = group_parameters.value_map['high_threshold'].value
        ranges = ranges_according_thresholds_list(
            [unaffected_max, very_low_max, low_max,
             medium_max, high_max, None])

        hazard_value_to_class = {}
        for i, interval in enumerate(ranges):
            hazard_value_to_class[interval] = self.hazard_classes[i]

        # Get parameters from layer's keywords
        class_field = self.exposure.keyword('field')

        # reproject self.extent to the hazard projection
        hazard_crs = hazard_layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        small_raster = align_clip_raster(hazard_layer, viewport_extent)

        # Create vector features from the flood raster
        hazard_class_attribute = 'hazard'
        vector_file_path = reclassify_polygonize(
            small_raster.source(), ranges, name_field=hazard_class_attribute)

        hazard = QgsVectorLayer(vector_file_path, 'ash vector', 'ogr')

        # prepare objects for re-projection of geometries
        crs_wgs84 = QgsCoordinateReferenceSystem('EPSG:4326')
        hazard_to_exposure = QgsCoordinateTransform(
            hazard.crs(), exposure.crs())
        wgs84_to_hazard = QgsCoordinateTransform(
            crs_wgs84, hazard.crs())
        wgs84_to_exposure = QgsCoordinateTransform(
            crs_wgs84, exposure.crs())

        extent = QgsRectangle(
            self.requested_extent[0], self.requested_extent[1],
            self.requested_extent[2], self.requested_extent[3])
        extent_hazard = wgs84_to_hazard.transformBoundingBox(extent)
        extent_exposure = wgs84_to_exposure.transformBoundingBox(extent)
        extent_exposure_geom = QgsGeometry.fromRect(extent_exposure)

        # make spatial index of hazard
        hazard_index = QgsSpatialIndex()
        hazard_features = {}
        for f in hazard.getFeatures(QgsFeatureRequest(extent_hazard)):
            f.geometry().transform(hazard_to_exposure)
            hazard_index.insertFeature(f)
            hazard_features[f.id()] = QgsFeature(f)

        # create impact layer
        filename = unique_filename(suffix='.shp')
        impact_fields = exposure.dataProvider().fields()
        impact_fields.append(QgsField(self.target_field, QVariant.String))
        writer = QgsVectorFileWriter(
            filename, 'utf-8', impact_fields, QGis.WKBPolygon, exposure.crs())

        # iterate over all exposure polygons and calculate the impact
        _calculate_landcover_impact(
            exposure, extent_exposure, extent_exposure_geom,
            hazard_class_attribute, hazard_features, hazard_index,
            hazard_value_to_class, impact_fields, writer)

        del writer
        impact_layer = QgsVectorLayer(filename, 'Impacted Land Cover', 'ogr')

        if impact_layer.featureCount() == 0:
            raise ZeroImpactException()

        zone_field = None
        if self.aggregator:
            zone_field = self.aggregator.exposure_aggregation_field

        impact_data = LandCoverReportMixin(
            question=self.question,
            impact_layer=impact_layer,
            target_field=self.target_field,
            ordered_columns=self.hazard_classes,
            affected_columns=self.affected_hazard_columns,
            land_cover_field=class_field,
            zone_field=zone_field
        ).generate_data()

        # Define style for the impact layer
        style_classes = [
            dict(
                label=self.hazard_classes[0] + ': %.1f - %.1f %s' % (
                    unaffected_max, very_low_max, unit_abbrev),
                value=self.hazard_classes[0],
                colour='#2C6BA4',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[1] + ': %.1f - %.1f %s' % (
                    very_low_max + 0.1, low_max, unit_abbrev),
                value=self.hazard_classes[1],
                colour='#00A4D8',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[2] + ': %.1f - %.1f %s' % (
                    low_max + 0.1, medium_max, unit_abbrev),
                value=self.hazard_classes[2],
                colour='#FFEF36',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[3] + ': %.1f - %.1f %s' % (
                    medium_max + 0.1, high_max, unit_abbrev),
                value=self.hazard_classes[3],
                colour='#EFA951',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[4] + ': > %.1f %s' % (
                    high_max, unit_abbrev),
                value=self.hazard_classes[4],
                colour='#d62631',
                border_color='#000000',
                transparency=0),
        ]
        style_info = dict(
            target_field=self.target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        extra_keywords = {
            'map_title': self.metadata().key('map_title'),
            'target_field': self.target_field
        }

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Create vector layer and return
        impact_layer = Vector(
            data=impact_layer,
            name=self.metadata().key('layer_name'),
            keywords=impact_layer_keywords,
            style_info=style_info)

        impact_layer.impact_data = impact_data
        self._impact = impact_layer
        return impact_layer
Example #5
0
    def run(self):
        """Run the impact function.

        :returns: A vector layer with affected areas marked.
        :type: safe_layer
        """
        hazard_layer = self.hazard.layer
        exposure = self.exposure.layer

        # Thresholds for tsunami hazard zone breakdown.
        low_max = self.parameters['low_threshold'].value
        medium_max = self.parameters['medium_threshold'].value
        high_max = self.parameters['high_threshold'].value
        ranges = ranges_according_thresholds(low_max, medium_max, high_max)

        hazard_value_to_class = {}
        for i, interval in enumerate(ranges):
            hazard_value_to_class[interval] = self.hazard_classes[i]

        # Get parameters from layer's keywords
        class_field = self.exposure.keyword('field')

        # reproject self.extent to the hazard projection
        hazard_crs = hazard_layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        small_raster = align_clip_raster(hazard_layer, viewport_extent)

        # Create vector features from the flood raster
        hazard_class_attribute = 'hazard'
        vector_file_path = reclassify_polygonize(
            small_raster.source(), ranges, name_field=hazard_class_attribute)

        hazard = QgsVectorLayer(vector_file_path, 'tsunami', 'ogr')

        # prepare objects for re-projection of geometries
        crs_wgs84 = QgsCoordinateReferenceSystem('EPSG:4326')
        hazard_to_exposure = QgsCoordinateTransform(
            hazard.crs(), exposure.crs())
        wgs84_to_hazard = QgsCoordinateTransform(
            crs_wgs84, hazard.crs())
        wgs84_to_exposure = QgsCoordinateTransform(
            crs_wgs84, exposure.crs())

        extent = QgsRectangle(
            self.requested_extent[0], self.requested_extent[1],
            self.requested_extent[2], self.requested_extent[3])
        extent_hazard = wgs84_to_hazard.transformBoundingBox(extent)
        extent_exposure = wgs84_to_exposure.transformBoundingBox(extent)
        extent_exposure_geom = QgsGeometry.fromRect(extent_exposure)

        # make spatial index of hazard
        hazard_index = QgsSpatialIndex()
        hazard_features = {}
        for f in hazard.getFeatures(QgsFeatureRequest(extent_hazard)):
            f.geometry().transform(hazard_to_exposure)
            hazard_index.insertFeature(f)
            hazard_features[f.id()] = QgsFeature(f)

        # create impact layer
        filename = unique_filename(suffix='.shp')
        impact_fields = exposure.dataProvider().fields()
        impact_fields.append(QgsField(self.target_field, QVariant.String))
        writer = QgsVectorFileWriter(
            filename, 'utf-8', impact_fields, QGis.WKBPolygon, exposure.crs())

        # iterate over all exposure polygons and calculate the impact
        _calculate_landcover_impact(
            exposure, extent_exposure, extent_exposure_geom,
            hazard_class_attribute, hazard_features, hazard_index,
            hazard_value_to_class, impact_fields, writer)

        del writer
        impact_layer = QgsVectorLayer(filename, 'Impacted Land Cover', 'ogr')

        if impact_layer.featureCount() == 0:
            raise ZeroImpactException()

        zone_field = None
        if self.aggregator:
            zone_field = self.aggregator.exposure_aggregation_field

        impact_data = LandCoverReportMixin(
            question=self.question,
            impact_layer=impact_layer,
            target_field=self.target_field,
            ordered_columns=self.hazard_classes,
            affected_columns=self.affected_hazard_columns,
            land_cover_field=class_field,
            zone_field=zone_field
        ).generate_data()

        # Define style for the impact layer
        style_classes = [
            dict(
                label=self.hazard_classes[0] + ': 0m',
                value=self.hazard_classes[0],
                colour='#00FF00',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[1] + ': >0 - %.1f m' % low_max,
                value=self.hazard_classes[1],
                colour='#FFFF00',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[2] + ': %.1f - %.1f m' % (
                    low_max + 0.1, medium_max),
                value=self.hazard_classes[2],
                colour='#FFB700',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[3] + ': %.1f - %.1f m' % (
                    medium_max + 0.1, high_max),
                value=self.hazard_classes[3],
                colour='#FF6F00',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[4] + ' > %.1f m' % high_max,
                value=self.hazard_classes[4],
                colour='#FF0000',
                border_color='#000000',
                transparency=0),
        ]
        style_info = dict(
            target_field=self.target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        extra_keywords = {
            'map_title': self.map_title(),
            'target_field': self.target_field
        }

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Create vector layer and return
        impact_layer = Vector(
            data=impact_layer,
            name=self.map_title(),
            keywords=impact_layer_keywords,
            style_info=style_info)

        impact_layer.impact_data = impact_data
        self._impact = impact_layer
        return impact_layer