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)
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)
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)
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
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