def set_widgets(self): """Set widgets on the Classification tab.""" self.clear_further_steps() purpose = self.parent.step_kw_purpose.selected_purpose()['name'] subcategory = self.parent.step_kw_subcategory.\ selected_subcategory()['name'] self.lstClassifications.clear() self.lblDescribeClassification.setText('') self.lblSelectClassification.setText( classification_question % (subcategory, purpose)) classifications = self.classifications_for_layer() for classification in classifications: if not isinstance(classification, dict): classification = definition(classification) item = QListWidgetItem( classification['name'], self.lstClassifications) item.setData(QtCore.Qt.UserRole, classification['key']) self.lstClassifications.addItem(item) # Set values based on existing keywords (if already assigned) geom = 'raster' if is_raster_layer(self.parent.layer) else 'vector' key = '%s_%s_classification' % ( geom, self.parent.step_kw_purpose.selected_purpose()['key']) classification_keyword = self.parent.get_existing_keyword(key) if classification_keyword: classifications = [] for index in xrange(self.lstClassifications.count()): item = self.lstClassifications.item(index) classifications.append(item.data(QtCore.Qt.UserRole)) if classification_keyword in classifications: self.lstClassifications.setCurrentRow( classifications.index(classification_keyword)) self.auto_select_one_item(self.lstClassifications)
def set_widgets(self): """Set widgets on the layer purpose tab.""" self.clear_further_steps() # Set widgets self.lstCategories.clear() self.lblDescribeCategory.setText("") self.lblIconCategory.setPixmap(QPixmap()) self.lblSelectCategory.setText(category_question % self.parent.layer.name()) purposes = self.purposes_for_layer() if self.parent.get_layer_geometry_id() == "polygon": purposes += ["aggregation"] for purpose in purposes: if not isinstance(purpose, dict): purpose = definition(purpose) item = QListWidgetItem(purpose["name"], self.lstCategories) item.setData(QtCore.Qt.UserRole, purpose["key"]) self.lstCategories.addItem(item) # Check if layer keywords are already assigned purpose_keyword = self.parent.get_existing_keyword("layer_purpose") # Overwrite the purpose_keyword if it's KW mode embedded in IFCW mode if self.parent.parent_step: purpose_keyword = self.parent.get_parent_mode_constraints()[0]["key"] # Set values based on existing keywords or parent mode if purpose_keyword: purposes = [] for index in xrange(self.lstCategories.count()): item = self.lstCategories.item(index) purposes.append(item.data(QtCore.Qt.UserRole)) if purpose_keyword in purposes: self.lstCategories.setCurrentRow(purposes.index(purpose_keyword)) self.auto_select_one_item(self.lstCategories)
def set_widgets(self): """Set widgets on the Classification tab.""" self.clear_further_steps() purpose = self.parent.step_kw_purpose.selected_purpose()['name'] subcategory = self.parent.step_kw_subcategory.\ selected_subcategory()['name'] self.lstClassifications.clear() self.lblDescribeClassification.setText('') self.lblSelectClassification.setText(classification_question % (subcategory, purpose)) classifications = self.classifications_for_layer() for classification in classifications: if not isinstance(classification, dict): classification = definition(classification) item = QListWidgetItem(classification['name'], self.lstClassifications) item.setData(QtCore.Qt.UserRole, classification['key']) self.lstClassifications.addItem(item) # Set values based on existing keywords (if already assigned) geom = 'raster' if is_raster_layer(self.parent.layer) else 'vector' key = '%s_%s_classification' % ( geom, self.parent.step_kw_purpose.selected_purpose()['key']) classification_keyword = self.parent.get_existing_keyword(key) if classification_keyword: classifications = [] for index in xrange(self.lstClassifications.count()): item = self.lstClassifications.item(index) classifications.append(item.data(QtCore.Qt.UserRole)) if classification_keyword in classifications: self.lstClassifications.setCurrentRow( classifications.index(classification_keyword)) self.auto_select_one_item(self.lstClassifications)
def set_widgets(self): """Set widgets on the Hazard Category tab.""" self.clear_further_steps() # Set widgets self.lstHazardCategories.clear() self.lblDescribeHazardCategory.setText('') self.lblSelectHazardCategory.setText(hazard_category_question) hazard_categories = self.hazard_categories_for_layer() for hazard_category in hazard_categories: if not isinstance(hazard_category, dict): hazard_category = definition(hazard_category) item = QListWidgetItem(hazard_category['name'], self.lstHazardCategories) item.setData(QtCore.Qt.UserRole, hazard_category['key']) self.lstHazardCategories.addItem(item) # Set values based on existing keywords (if already assigned) category_keyword = self.parent.get_existing_keyword('hazard_category') if category_keyword: categories = [] for index in xrange(self.lstHazardCategories.count()): item = self.lstHazardCategories.item(index) categories.append(item.data(QtCore.Qt.UserRole)) if category_keyword in categories: self.lstHazardCategories.setCurrentRow( categories.index(category_keyword)) self.auto_select_one_item(self.lstHazardCategories)
def set_widgets(self): """Set widgets on the Hazard Category tab.""" self.clear_further_steps() # Set widgets self.lstHazardCategories.clear() self.lblDescribeHazardCategory.setText('') self.lblSelectHazardCategory.setText( hazard_category_question) hazard_categories = self.hazard_categories_for_layer() for hazard_category in hazard_categories: if not isinstance(hazard_category, dict): hazard_category = definition(hazard_category) item = QListWidgetItem( hazard_category['name'], self.lstHazardCategories) item.setData(QtCore.Qt.UserRole, hazard_category['key']) self.lstHazardCategories.addItem(item) # Set values based on existing keywords (if already assigned) category_keyword = self.parent.get_existing_keyword('hazard_category') if category_keyword: categories = [] for index in xrange(self.lstHazardCategories.count()): item = self.lstHazardCategories.item(index) categories.append(item.data(QtCore.Qt.UserRole)) if category_keyword in categories: self.lstHazardCategories.setCurrentRow( categories.index(category_keyword)) self.auto_select_one_item(self.lstHazardCategories)
def test_definition(self): """Test we can get definitions for keywords. .. versionadded:: 3.2 """ keyword = 'hazards' keyword_definition = definition(keyword) self.assertTrue('description' in keyword_definition)
def selected_layermode(self): """Obtain the layer mode selected by user. :returns: selected layer mode. :rtype: string, None """ item = self.lstLayerModes.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_classification(self): """Obtain the classification selected by user. :returns: Metadata of the selected classification. :rtype: dict, None """ item = self.lstClassifications.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_unit(self): """Obtain the unit selected by user. :returns: Metadata of the selected unit. :rtype: dict, None """ item = self.lstUnits.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_purpose(self): """Obtain the layer purpose selected by user. :returns: Metadata of the selected layer purpose. :rtype: dict, None """ item = self.lstCategories.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_hazard_category(self): """Obtain the hazard category selected by user. :returns: Metadata of the selected hazard category. :rtype: dict, None """ item = self.lstHazardCategories.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def set_widgets(self): """Set widgets on the layer purpose tab.""" self.clear_further_steps() # Set widgets self.lstCategories.clear() self.lblDescribeCategory.setText('') self.lblIconCategory.setPixmap(QPixmap()) self.lblSelectCategory.setText(category_question % self.parent.layer.name()) purposes = self.purposes_for_layer() if self.parent.get_layer_geometry_id() == 'polygon': purposes += ['aggregation'] for purpose in purposes: if not isinstance(purpose, dict): purpose = definition(purpose) item = QListWidgetItem(purpose['name'], self.lstCategories) item.setData(QtCore.Qt.UserRole, purpose['key']) self.lstCategories.addItem(item) # Check if layer keywords are already assigned purpose_keyword = self.parent.get_existing_keyword('layer_purpose') # Overwrite the purpose_keyword if it's KW mode embedded in IFCW mode if self.parent.parent_step: purpose_keyword = self.parent.\ get_parent_mode_constraints()[0]['key'] # Set values based on existing keywords or parent mode if purpose_keyword: purposes = [] for index in xrange(self.lstCategories.count()): item = self.lstCategories.item(index) purposes.append(item.data(QtCore.Qt.UserRole)) if purpose_keyword in purposes: self.lstCategories.setCurrentRow( purposes.index(purpose_keyword)) self.auto_select_one_item(self.lstCategories)
def run(self): """Risk plugin for volcano hazard on building/structure. Counts number of building exposed to each volcano hazard zones. :returns: Map of building exposed to volcanic hazard zones. Table with number of buildings affected :rtype: dict """ # Get parameters from layer's keywords self.hazard_class_attribute = self.hazard.keyword('field') self.name_attribute = self.hazard.keyword('volcano_name_field') self.hazard_class_mapping = self.hazard.keyword('value_map') self.exposure_class_attribute = self.exposure.keyword( 'structure_class_field') exposure_value_mapping = self.exposure.keyword('value_mapping') # Input checks if not self.hazard.layer.is_polygon_data: message = ( 'Input hazard must be a polygon. I got %s with ' 'layer type %s' % (self.hazard.name, self.hazard.layer.get_geometry_name())) raise Exception(message) # Check if hazard_zone_attribute exists in hazard_layer if (self.hazard_class_attribute not in self.hazard.layer.get_attribute_names()): message = ( 'Hazard data %s did not contain expected attribute %s ' % (self.hazard.name, self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) # Get names of volcanoes considered if self.name_attribute in self.hazard.layer.get_attribute_names(): for row in self.hazard.layer.get_data(): # Run through all polygons and get unique names self.volcano_names.add(row[self.name_attribute]) # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Initialize OrderedDict of affected buildings hazard_class = [] # Iterate over vector hazard classes for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building hazard_class.append(vector_hazard_class['name']) # Run interpolation function for polygon2raster interpolated_layer = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer) # Extract relevant exposure data features = interpolated_layer.get_data() self.init_report_var(hazard_class) for i in range(len(features)): # Get the hazard value based on the value mapping in keyword hazard_value = get_key_for_value( features[i][self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value features[i][self.target_field] = get_string(hazard_value) usage = features[i][self.exposure_class_attribute] usage = main_type(usage, exposure_value_mapping) affected = False if hazard_value in self.affected_buildings.keys(): affected = True self.classify_feature(hazard_value, usage, affected) self.reorder_dictionaries() # Create style colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] colours = colours[::-1] # flip colours = colours[:len(self.affected_buildings.keys())] style_classes = [] for i, category_name in enumerate(self.affected_buildings.keys()): style_class = dict() style_class['label'] = tr(category_name) style_class['transparency'] = 0 style_class['value'] = category_name style_class['size'] = 1 if i >= len(self.affected_buildings.keys()): i = len(self.affected_buildings.keys()) - 1 style_class['colour'] = colours[i] style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_data = self.generate_data() extra_keywords = { 'target_field': self.target_field, 'map_title': self.map_title(), 'legend_notes': self.metadata().key('legend_notes'), 'legend_units': self.metadata().key('legend_units'), 'legend_title': self.metadata().key('legend_title') } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Vector( data=features, projection=interpolated_layer.get_projection(), geometry=interpolated_layer.get_geometry(), 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
def run(self): """Risk plugin for classified polygon hazard on building/structure. Counts number of building exposed to each hazard zones. :returns: Impact vector layer building exposed to each hazard zones. Table with number of buildings affected :rtype: Vector """ # Value from layer's keywords self.hazard_class_attribute = self.hazard.keyword('field') self.hazard_class_mapping = self.hazard.keyword('value_map') self.exposure_class_attribute = self.exposure.keyword( 'structure_class_field') try: exposure_value_mapping = self.exposure.keyword('value_mapping') except KeywordNotFoundError: # Generic IF, the keyword might not be defined base.py exposure_value_mapping = {} # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Iterate over vector hazard classes hazard_classes = [] for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building hazard_classes.append(vector_hazard_class['name']) hazard_zone_attribute_index = self.hazard.layer.fieldNameIndex( self.hazard_class_attribute) # Check if hazard_zone_attribute exists in hazard_layer if hazard_zone_attribute_index < 0: message = ( 'Hazard data %s does not contain expected attribute %s ' % (self.hazard.layer.name(), self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) # Hazard zone categories from hazard layer unique_values = self.hazard.layer.uniqueValues( hazard_zone_attribute_index) # Values might be integer or float, we should have unicode. #2626 self.hazard_zones = [get_unicode(val) for val in unique_values] self.init_report_var(hazard_classes) wgs84_extent = QgsRectangle(self.requested_extent[0], self.requested_extent[1], self.requested_extent[2], self.requested_extent[3]) # Run interpolation function for polygon2polygon interpolated_layer = interpolate_polygon_polygon( self.hazard.layer, self.exposure.layer, wgs84_extent) new_field = QgsField(self.target_field, QVariant.String) interpolated_layer.dataProvider().addAttributes([new_field]) interpolated_layer.updateFields() target_field_index = interpolated_layer.fieldNameIndex( self.target_field) changed_values = {} if interpolated_layer.featureCount() < 1: raise ZeroImpactException() # Extract relevant interpolated data for feature in interpolated_layer.getFeatures(): # Get the hazard value based on the value mapping in keyword hazard_value = get_key_for_value( feature[self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value changed_values[feature.id()] = {target_field_index: hazard_value} usage = feature[self.exposure_class_attribute] usage = main_type(usage, exposure_value_mapping) affected = False if hazard_value in self.hazard_class_mapping.keys(): affected = True self.classify_feature(hazard_value, usage, affected) interpolated_layer.dataProvider().changeAttributeValues(changed_values) self.reorder_dictionaries() # Create style categories = self.affected_buildings.keys() categories.append(self._not_affected_value) colours = color_ramp(len(categories)) style_classes = [] for i, hazard_zone in enumerate(self.affected_buildings.keys()): style_class = dict() style_class['label'] = tr(hazard_zone) style_class['transparency'] = 0 style_class['value'] = hazard_zone style_class['size'] = 1 style_class['colour'] = colours[i] style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_data = self.generate_data() extra_keywords = { 'target_field': self.target_field, 'map_title': self.map_title(), 'legend_notes': self.metadata().key('legend_notes'), 'legend_units': self.metadata().key('legend_units'), 'legend_title': self.metadata().key('legend_title') } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Vector(data=interpolated_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
def run(self): """Risk plugin for classified polygon hazard on polygon population. Counts population in an area exposed to hazard zones and then computes the proportion of each area that is affected. The population in each area is then calculated as the proportion of the original population to the affected area. :returns: Impact layer :rtype: Vector """ # Identify hazard and exposure layers hazard = self.hazard.layer exposure = self.exposure.layer # 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 feature in hazard.getFeatures(QgsFeatureRequest(extent_hazard)): feature.geometry().transform(hazard_to_exposure) hazard_index.insertFeature(feature) hazard_features[feature.id()] = QgsFeature(feature) # create impact layer filename = unique_filename(suffix='.shp') impact_fields = exposure.dataProvider().fields() impact_fields.append(QgsField(self.target_field, QVariant.Int)) # impact_fields.append(QgsField(self.people_field, QVariant.Int)) unaffected_fields = exposure.dataProvider().fields() unaffected_fields.append(QgsField(self.target_field, QVariant.Int)) # unaffected_fields.append(QgsField(self.people_field, QVariant.Int)) writer = QgsVectorFileWriter(filename, "utf-8", impact_fields, QGis.WKBPolygon, exposure.crs()) # Evaluating the impact self.evaluate_impact(exposure, extent_exposure, extent_exposure_geom, hazard_index, hazard_features, writer, unaffected_fields, impact_fields) del writer impact_layer = QgsVectorLayer(filename, "Impacted People", "ogr") # Generate the report of affected populations in the areas # To avoid Null for value in self.all_areas_population.values(): if isinstance(value, QPyNullVariant): value = 0 self.total_population += value self.areas = self.all_areas_ids self.affected_areas = self.all_affected_areas self.areas_population = self.all_areas_population # Calculating number of people affected # This will help area report mixin to know how # to calculate the all row values before other # rows values in the report table self.evaluate_affected_people() # Define style for the impact layer transparent_color = QColor() transparent_color.setAlpha(0) # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the # classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] classes = self.hazard_class_mapping classes_colours = {} color_mapping = { 'wet': '#F31A1C', 'low': '#1EFC7C', 'medium': '#FFA500', 'high': '#F31A1C' } classes_values = {'wet': 1, 'low': 1, 'medium': 2, 'high': 3} # Assigning colors for vector_hazard_class in vector_hazard_classes: key = vector_hazard_class['key'] if key in classes.keys() and key in color_mapping.keys(): classes_colours[key] = color_mapping[key] # Define style info for output polygons showing population counts style_classes = [] index = 0 for class_key, colour in classes_colours.items(): style_class = dict() if class_key in classes.keys(): # label = classes[class_key][0] label = class_key else: continue transparency = 0 style_class['label'] = label style_class['value'] = classes_values[class_key] style_class['colour'] = colour style_class['transparency'] = transparency style_classes.append(style_class) index += 1 style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_data = self.generate_data() extra_keywords = { 'target_field': self.target_field, 'map_title': self.map_title(), } 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
def run(self): """Risk plugin for volcano hazard on building/structure. Counts number of building exposed to each volcano hazard zones. :returns: Map of building exposed to volcanic hazard zones. Table with number of buildings affected :rtype: dict """ # Get parameters from layer's keywords self.hazard_class_attribute = self.hazard.keyword('field') self.name_attribute = self.hazard.keyword('volcano_name_field') self.hazard_class_mapping = self.hazard.keyword('value_map') self.exposure_class_attribute = self.exposure.keyword( 'structure_class_field') exposure_value_mapping = self.exposure.keyword('value_mapping') # Input checks if not self.hazard.layer.is_polygon_data: message = ( 'Input hazard must be a polygon. I got %s with ' 'layer type %s' % (self.hazard.name, self.hazard.layer.get_geometry_name())) raise Exception(message) # Check if hazard_zone_attribute exists in hazard_layer if (self.hazard_class_attribute not in self.hazard.layer.get_attribute_names()): message = ( 'Hazard data %s did not contain expected attribute %s ' % (self.hazard.name, self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) # Get names of volcanoes considered if self.name_attribute in self.hazard.layer.get_attribute_names(): volcano_name_list = set() for row in self.hazard.layer.get_data(): # Run through all polygons and get unique names volcano_name_list.add(row[self.name_attribute]) self.volcano_names = ', '.join(volcano_name_list) else: self.volcano_names = tr('Not specified in data') # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Initialize OrderedDict of affected buildings hazard_class = [] # Iterate over vector hazard classes for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building hazard_class.append(vector_hazard_class['name']) # Run interpolation function for polygon2raster interpolated_layer = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer) # Extract relevant exposure data features = interpolated_layer.get_data() self.init_report_var(hazard_class) for i in range(len(features)): # Get the hazard value based on the value mapping in keyword hazard_value = get_key_for_value( features[i][self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value features[i][self.target_field] = get_string(hazard_value) usage = features[i][self.exposure_class_attribute] usage = main_type(usage, exposure_value_mapping) affected = False if hazard_value in self.affected_buildings.keys(): affected = True self.classify_feature(hazard_value, usage, affected) self.reorder_dictionaries() # Create style colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] colours = colours[::-1] # flip colours = colours[:len(self.affected_buildings.keys())] style_classes = [] for i, category_name in enumerate(self.affected_buildings.keys()): style_class = dict() style_class['label'] = tr(category_name) style_class['transparency'] = 0 style_class['value'] = category_name style_class['size'] = 1 if i >= len(self.affected_buildings.keys()): i = len(self.affected_buildings.keys()) - 1 style_class['colour'] = colours[i] style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_data = self.generate_data() extra_keywords = { 'target_field': self.target_field, 'map_title': self.metadata().key('map_title'), 'legend_notes': self.metadata().key('legend_notes'), 'legend_units': self.metadata().key('legend_units'), 'legend_title': self.metadata().key('legend_title') } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Vector( data=features, projection=interpolated_layer.get_projection(), geometry=interpolated_layer.get_geometry(), 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): """Risk plugin for classified polygon hazard on building/structure. Counts number of building exposed to each hazard zones. :returns: Impact vector layer building exposed to each hazard zones. Table with number of buildings affected :rtype: Vector """ self.validate() self.prepare() self.provenance.append_step( 'Calculating Step', 'Impact function is calculating the impact.') # Value from layer's keywords self.hazard_class_attribute = self.hazard.keyword('field') self.hazard_class_mapping = self.hazard.keyword('value_map') # Try to get the value from keyword, if not exist, it will not fail, # but use the old get_osm_building_usage try: self.exposure_class_attribute = self.exposure.keyword( 'structure_class_field') except KeywordNotFoundError: self.exposure_class_attribute = None # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Initialize OrderedDict of affected buildings self.affected_buildings = OrderedDict() # Iterate over vector hazard classes for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building self.affected_buildings[vector_hazard_class['name']] = {} hazard_zone_attribute_index = self.hazard.layer.fieldNameIndex( self.hazard_class_attribute) # Check if hazard_zone_attribute exists in hazard_layer if hazard_zone_attribute_index < 0: message = ( 'Hazard data %s does not contain expected attribute %s ' % (self.hazard.layer.name(), self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) # Hazard zone categories from hazard layer unique_values = self.hazard.layer.uniqueValues( hazard_zone_attribute_index) # Values might be integer or float, we should have unicode. #2626 self.hazard_zones = [get_unicode(val) for val in unique_values] self.buildings = {} wgs84_extent = QgsRectangle(self.requested_extent[0], self.requested_extent[1], self.requested_extent[2], self.requested_extent[3]) # Run interpolation function for polygon2polygon interpolated_layer = interpolate_polygon_polygon( self.hazard.layer, self.exposure.layer, wgs84_extent) new_field = QgsField(self.target_field, QVariant.String) interpolated_layer.dataProvider().addAttributes([new_field]) interpolated_layer.updateFields() attribute_names = [ field.name() for field in interpolated_layer.pendingFields() ] target_field_index = interpolated_layer.fieldNameIndex( self.target_field) changed_values = {} if interpolated_layer.featureCount() < 1: raise ZeroImpactException() # Extract relevant interpolated data for feature in interpolated_layer.getFeatures(): # Get the hazard value based on the value mapping in keyword hazard_value = get_key_for_value( feature[self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value changed_values[feature.id()] = {target_field_index: hazard_value} if (self.exposure_class_attribute and self.exposure_class_attribute in attribute_names): usage = feature[self.exposure_class_attribute] else: usage = get_osm_building_usage(attribute_names, feature) if usage is None: usage = tr('Unknown') if usage not in self.buildings: self.buildings[usage] = 0 for category in self.hazard_class_mapping.keys(): self.affected_buildings[category][usage] = OrderedDict([ (tr('Buildings Affected'), 0) ]) self.buildings[usage] += 1 if hazard_value in self.hazard_class_mapping.keys(): self.affected_buildings[hazard_value][usage][tr( 'Buildings Affected')] += 1 interpolated_layer.dataProvider().changeAttributeValues(changed_values) # Lump small entries and 'unknown' into 'other' category # Building threshold #2468 postprocessors = self.parameters['postprocessors'] building_postprocessors = postprocessors['BuildingType'][0] self.building_report_threshold = building_postprocessors.value[0].value self._consolidate_to_other() # Generate simple impact report impact_summary = impact_table = self.html_report() # Create style categories = self.affected_buildings.keys() categories.append(self._not_affected_value) colours = color_ramp(len(categories)) style_classes = [] i = 0 for hazard_zone in self.affected_buildings.keys(): style_class = dict() style_class['label'] = tr(hazard_zone) style_class['transparency'] = 0 style_class['value'] = hazard_zone style_class['size'] = 1 style_class['colour'] = colours[i] style_classes.append(style_class) i += 1 # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') # For printing map purpose map_title = tr('Buildings affected by each hazard zone') legend_title = tr('Building count') legend_units = tr('(building)') legend_notes = tr('Thousand separator is represented by %s' % get_thousand_separator()) extra_keywords = { 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title } self.set_if_provenance() impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Vector( data=interpolated_layer, name=tr('Buildings affected by each hazard zone'), keywords=impact_layer_keywords, style_info=style_info) self._impact = impact_layer return impact_layer
def run(self): """Risk plugin for classified polygon hazard on polygon population. Counts population in an area exposed to hazard zones and then computes the proportion of each area that is affected. The population in each area is then calculated as the proportion of the original population to the affected area. :returns: Impact layer :rtype: Vector """ # Identify hazard and exposure layers hazard = self.hazard.layer exposure = self.exposure.layer # 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 feature in hazard.getFeatures(QgsFeatureRequest(extent_hazard)): feature.geometry().transform(hazard_to_exposure) hazard_index.insertFeature(feature) hazard_features[feature.id()] = QgsFeature(feature) # create impact layer filename = unique_filename(suffix='.shp') impact_fields = exposure.dataProvider().fields() impact_fields.append(QgsField(self.target_field, QVariant.Int)) # impact_fields.append(QgsField(self.people_field, QVariant.Int)) unaffected_fields = exposure.dataProvider().fields() unaffected_fields.append(QgsField(self.target_field, QVariant.Int)) # unaffected_fields.append(QgsField(self.people_field, QVariant.Int)) writer = QgsVectorFileWriter( filename, "utf-8", impact_fields, QGis.WKBPolygon, exposure.crs()) # Evaluating the impact self.evaluate_impact( exposure, extent_exposure, extent_exposure_geom, hazard_index, hazard_features, writer, unaffected_fields, impact_fields) del writer impact_layer = QgsVectorLayer(filename, "Impacted People", "ogr") # Generate the report of affected populations in the areas # To avoid Null for value in self.all_areas_population.values(): if isinstance(value, QPyNullVariant): value = 0 self.total_population += value self.areas = self.all_areas_ids self.affected_areas = self.all_affected_areas self.areas_population = self.all_areas_population # Calculating number of people affected # This will help area report mixin to know how # to calculate the all row values before other # rows values in the report table self.evaluate_affected_people() # Define style for the impact layer transparent_color = QColor() transparent_color.setAlpha(0) # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the # classification vector_hazard_classification = definition( vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] classes = self.hazard_class_mapping classes_colours = {} color_mapping = { 'wet': '#F31A1C', 'low': '#1EFC7C', 'medium': '#FFA500', 'high': '#F31A1C' } classes_values = { 'wet': 1, 'low': 1, 'medium': 2, 'high': 3 } # Assigning colors for vector_hazard_class in vector_hazard_classes: key = vector_hazard_class['key'] if key in classes.keys() and key in color_mapping.keys(): classes_colours[key] = color_mapping[key] # Define style info for output polygons showing population counts style_classes = [] index = 0 for class_key, colour in classes_colours.items(): style_class = dict() if class_key in classes.keys(): label = classes[class_key][0] else: continue transparency = 0 style_class['label'] = label style_class['value'] = classes_values[class_key] style_class['colour'] = colour style_class['transparency'] = transparency style_classes.append(style_class) index += 1 style_info = dict( target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_data = self.generate_data() extra_keywords = { 'target_field': self.target_field, 'map_title': self.metadata().key('map_title'), } 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): """Risk plugin for volcano hazard on building/structure. Counts number of building exposed to each volcano hazard zones. :returns: Map of building exposed to volcanic hazard zones. Table with number of buildings affected :rtype: dict """ self.validate() self.prepare() self.provenance.append_step( 'Calculating Step', 'Impact function is calculating the impact.') # Get parameters from layer's keywords self.hazard_class_attribute = self.hazard.keyword('field') self.name_attribute = self.hazard.keyword('volcano_name_field') self.hazard_class_mapping = self.hazard.keyword('value_map') # Try to get the value from keyword, if not exist, it will not fail, # but use the old get_osm_building_usage try: self.exposure_class_attribute = self.exposure.keyword( 'structure_class_field') except KeywordNotFoundError: self.exposure_class_attribute = None # Input checks if not self.hazard.layer.is_polygon_data: message = ( 'Input hazard must be a polygon. I got %s with ' 'layer type %s' % (self.hazard.name, self.hazard.layer.get_geometry_name())) raise Exception(message) # Check if hazard_zone_attribute exists in hazard_layer if (self.hazard_class_attribute not in self.hazard.layer.get_attribute_names()): message = ( 'Hazard data %s did not contain expected attribute %s ' % (self.hazard.name, self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) # Get names of volcanoes considered if self.name_attribute in self.hazard.layer.get_attribute_names(): volcano_name_list = set() for row in self.hazard.layer.get_data(): # Run through all polygons and get unique names volcano_name_list.add(row[self.name_attribute]) self.volcano_names = ', '.join(volcano_name_list) else: self.volcano_names = tr('Not specified in data') # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Initialize OrderedDict of affected buildings self.affected_buildings = OrderedDict() # Iterate over vector hazard classes for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building self.affected_buildings[vector_hazard_class['name']] = {} # Run interpolation function for polygon2raster interpolated_layer = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer) # Extract relevant exposure data attribute_names = interpolated_layer.get_attribute_names() features = interpolated_layer.get_data() self.buildings = {} for i in range(len(features)): # Get the hazard value based on the value mapping in keyword hazard_value = get_key_for_value( features[i][self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value features[i][self.target_field] = get_string(hazard_value) if (self.exposure_class_attribute and self.exposure_class_attribute in attribute_names): usage = features[i][self.exposure_class_attribute] else: usage = get_osm_building_usage(attribute_names, features[i]) if usage in [None, 'NULL', 'null', 'Null', 0]: usage = tr('Unknown') if usage not in self.buildings: self.buildings[usage] = 0 for category in self.affected_buildings.keys(): self.affected_buildings[category][usage] = OrderedDict([ (tr('Buildings Affected'), 0) ]) self.buildings[usage] += 1 if hazard_value in self.affected_buildings.keys(): self.affected_buildings[hazard_value][usage][tr( 'Buildings Affected')] += 1 # Lump small entries and 'unknown' into 'other' category # Building threshold #2468 postprocessors = self.parameters['postprocessors'] building_postprocessors = postprocessors['BuildingType'][0] self.building_report_threshold = building_postprocessors.value[0].value self._consolidate_to_other() # Generate simple impact report impact_summary = impact_table = self.html_report() # Create style colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] colours = colours[::-1] # flip colours = colours[:len(self.affected_buildings.keys())] style_classes = [] i = 0 for category_name in self.affected_buildings.keys(): style_class = dict() style_class['label'] = tr(category_name) style_class['transparency'] = 0 style_class['value'] = category_name style_class['size'] = 1 if i >= len(self.affected_buildings.keys()): i = len(self.affected_buildings.keys()) - 1 style_class['colour'] = colours[i] i += 1 style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') # For printing map purpose map_title = tr('Buildings affected by volcanic hazard zone') legend_title = tr('Building count') legend_units = tr('(building)') legend_notes = tr('Thousand separator is represented by %s' % get_thousand_separator()) extra_keywords = { 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title } self.set_if_provenance() impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Vector( data=features, projection=interpolated_layer.get_projection(), geometry=interpolated_layer.get_geometry(), name=tr('Buildings affected by volcanic hazard zone'), keywords=impact_layer_keywords, style_info=style_info) self._impact = impact_layer return impact_layer
def run(self): """Run classified population evacuation Impact Function. Counts number of people exposed to each hazard zones. :returns: Map of population exposed to each hazard zone. The returned dict will include a table with number of people evacuated and supplies required. :rtype: dict :raises: * Exception - When hazard layer is not vector layer """ # Value from layer's keywords self.hazard_class_attribute = self.hazard.keyword('field') self.hazard_class_mapping = self.hazard.keyword('value_map') # TODO: Remove check to self.validate (Ismail) # Input checks message = tr( 'Input hazard must be a polygon layer. I got %s with layer type ' '%s' % (self.hazard.name, self.hazard.layer.get_geometry_name())) if not self.hazard.layer.is_polygon_data: raise Exception(message) # Check if hazard_class_attribute exists in hazard_layer if (self.hazard_class_attribute not in self.hazard.layer.get_attribute_names()): message = tr( 'Hazard data %s does not contain expected hazard ' 'zone attribute "%s". Please change it in the option. ' % (self.hazard.name, self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Initialize OrderedDict of affected buildings self.affected_population = OrderedDict() # Iterate over vector hazard classes for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building self.affected_population[vector_hazard_class['name']] = 0 # Interpolated layer represents grid cell that lies in the polygon interpolated_layer, covered_exposure_layer = \ assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=self.target_field ) # Count total affected population per hazard zone for row in interpolated_layer.get_data(): # Get population at this location population = row[self.target_field] if not numpy.isnan(population): population = float(population) # Update population count for this hazard zone hazard_value = get_key_for_value( row[self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value else: self.affected_population[hazard_value] += population # Count total population from exposure layer self.total_population = int( numpy.nansum(self.exposure.layer.get_data())) # Count total affected population total_affected_population = self.total_affected_population self.unaffected_population = (self.total_population - total_affected_population) self.minimum_needs = [ parameter.serialize() for parameter in filter_needs_parameters( self.parameters['minimum needs']) ] # check for zero impact if total_affected_population == 0: message = no_population_impact_message(self.question) raise ZeroImpactException(message) # Create style colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] classes = create_classes(covered_exposure_layer.get_data().flat[:], len(colours)) interval_classes = humanize_class(classes) # Define style info for output polygons showing population counts style_classes = [] for i in xrange(len(colours)): style_class = dict() style_class['label'] = create_label(interval_classes[i]) if i == 1: label = create_label( interval_classes[i], tr('Low Population [%i people/cell]' % classes[i])) elif i == 4: label = create_label( interval_classes[i], tr('Medium Population [%i people/cell]' % classes[i])) elif i == 7: label = create_label( interval_classes[i], tr('High Population [%i people/cell]' % classes[i])) else: label = create_label(interval_classes[i]) style_class['label'] = label style_class['quantity'] = classes[i] style_class['colour'] = colours[i] style_class['transparency'] = 0 style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=None, style_classes=style_classes, style_type='rasterStyle') impact_data = self.generate_data() extra_keywords = { 'target_field': self.target_field, 'map_title': self.map_title(), 'legend_notes': self.metadata().key('legend_notes'), 'legend_units': self.metadata().key('legend_units'), 'legend_title': self.metadata().key('legend_title') } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Raster( data=covered_exposure_layer.get_data(), projection=covered_exposure_layer.get_projection(), geotransform=covered_exposure_layer.get_geotransform(), 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
def run(self): """Risk plugin for classified polygon hazard on building/structure. Counts number of building exposed to each hazard zones. :returns: Impact vector layer building exposed to each hazard zones. Table with number of buildings affected :rtype: Vector """ # Value from layer's keywords self.hazard_class_attribute = self.hazard.keyword('field') self.hazard_class_mapping = self.hazard.keyword('value_map') self.exposure_class_attribute = self.exposure.keyword( 'structure_class_field') try: exposure_value_mapping = self.exposure.keyword('value_mapping') except KeywordNotFoundError: # Generic IF, the keyword might not be defined base.py exposure_value_mapping = {} # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Iterate over vector hazard classes hazard_classes = [] for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building hazard_classes.append(vector_hazard_class['name']) hazard_zone_attribute_index = self.hazard.layer.fieldNameIndex( self.hazard_class_attribute) # Check if hazard_zone_attribute exists in hazard_layer if hazard_zone_attribute_index < 0: message = ( 'Hazard data %s does not contain expected attribute %s ' % (self.hazard.layer.name(), self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) # Hazard zone categories from hazard layer unique_values = self.hazard.layer.uniqueValues( hazard_zone_attribute_index) # Values might be integer or float, we should have unicode. #2626 self.hazard_zones = [get_unicode(val) for val in unique_values] self.init_report_var(hazard_classes) wgs84_extent = QgsRectangle( self.requested_extent[0], self.requested_extent[1], self.requested_extent[2], self.requested_extent[3]) # Run interpolation function for polygon2polygon interpolated_layer = interpolate_polygon_polygon( self.hazard.layer, self.exposure.layer, wgs84_extent) new_field = QgsField(self.target_field, QVariant.String) interpolated_layer.dataProvider().addAttributes([new_field]) interpolated_layer.updateFields() target_field_index = interpolated_layer.fieldNameIndex( self.target_field) changed_values = {} if interpolated_layer.featureCount() < 1: raise ZeroImpactException() # Extract relevant interpolated data for feature in interpolated_layer.getFeatures(): # Get the hazard value based on the value mapping in keyword hazard_value = get_key_for_value( feature[self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value changed_values[feature.id()] = {target_field_index: hazard_value} usage = feature[self.exposure_class_attribute] usage = main_type(usage, exposure_value_mapping) affected = False if hazard_value in self.hazard_class_mapping.keys(): affected = True self.classify_feature(hazard_value, usage, affected) interpolated_layer.dataProvider().changeAttributeValues(changed_values) self.reorder_dictionaries() # Create style categories = self.affected_buildings.keys() categories.append(self._not_affected_value) colours = color_ramp(len(categories)) style_classes = [] for i, hazard_zone in enumerate(self.affected_buildings.keys()): style_class = dict() style_class['label'] = tr(hazard_zone) style_class['transparency'] = 0 style_class['value'] = hazard_zone style_class['size'] = 1 style_class['colour'] = colours[i] style_classes.append(style_class) # Override style info with new classes and name style_info = dict( target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol' ) impact_data = self.generate_data() extra_keywords = { 'target_field': self.target_field, 'map_title': self.map_title(), 'legend_notes': self.metadata().key('legend_notes'), 'legend_units': self.metadata().key('legend_units'), 'legend_title': self.metadata().key('legend_title') } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Vector( data=interpolated_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
def run(self): """Run volcano population evacuation Impact Function. Counts number of people exposed to volcano event. :returns: Map of population exposed to the volcano hazard zone. The returned dict will include a table with number of people evacuated and supplies required. :rtype: dict :raises: * Exception - When hazard layer is not vector layer * RadiiException - When radii are not valid (they need to be monotonically increasing) """ self.validate() self.prepare() self.provenance.append_step( 'Calculating Step', 'Impact function is calculating the impact.') # Parameters self.hazard_class_attribute = self.hazard.keyword('field') name_attribute = self.hazard.keyword('volcano_name_field') self.hazard_class_mapping = self.hazard.keyword('value_map') if has_no_data(self.exposure.layer.get_data(nan=True)): self.no_data_warning = True # Input checks if not self.hazard.layer.is_polygon_data: message = tr( 'Input hazard must be a polygon layer. I got %s with layer ' 'type %s' % (self.hazard.layer.get_name(), self.hazard.layer.get_geometry_name())) raise Exception(message) # Check if hazard_class_attribute exists in hazard_layer if (self.hazard_class_attribute not in self.hazard.layer.get_attribute_names()): message = tr( 'Hazard data %s did not contain expected attribute ' '%s ' % (self.hazard.layer.get_name(), self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) features = self.hazard.layer.get_data() # Get names of volcanoes considered if name_attribute in self.hazard.layer.get_attribute_names(): volcano_name_list = [] # Run through all polygons and get unique names for row in features: volcano_name_list.append(row[name_attribute]) self.volcano_names = ', '.join(set(volcano_name_list)) # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Initialize OrderedDict of affected buildings self.affected_population = OrderedDict() # Iterate over vector hazard classes for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building self.affected_population[vector_hazard_class['name']] = 0 # Run interpolation function for polygon2raster interpolated_layer, covered_exposure_layer = \ assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=self.target_field) # Count affected population per polygon and total for row in interpolated_layer.get_data(): # Get population at this location population = row[self.target_field] if not numpy.isnan(population): population = float(population) # Update population count for this hazard zone hazard_value = get_key_for_value( row[self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value self.affected_population[hazard_value] += population # Count totals self.total_population = int( numpy.nansum(self.exposure.layer.get_data())) self.unaffected_population = (self.total_population - self.total_affected_population) self.minimum_needs = [ parameter.serialize() for parameter in filter_needs_parameters( self.parameters['minimum needs']) ] impact_table = impact_summary = self.html_report() # check for zero impact if self.total_affected_population == 0: message = no_population_impact_message(self.question) raise ZeroImpactException(message) # Create style colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] classes = create_classes(covered_exposure_layer.get_data().flat[:], len(colours)) interval_classes = humanize_class(classes) # Define style info for output polygons showing population counts style_classes = [] for i in xrange(len(colours)): style_class = dict() style_class['label'] = create_label(interval_classes[i]) if i == 1: label = create_label( interval_classes[i], tr('Low Population [%i people/cell]' % classes[i])) elif i == 4: label = create_label( interval_classes[i], tr('Medium Population [%i people/cell]' % classes[i])) elif i == 7: label = create_label( interval_classes[i], tr('High Population [%i people/cell]' % classes[i])) else: label = create_label(interval_classes[i]) style_class['label'] = label style_class['quantity'] = classes[i] style_class['colour'] = colours[i] style_class['transparency'] = 0 style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=None, style_classes=style_classes, style_type='rasterStyle') # For printing map purpose map_title = tr('People affected by Volcano Hazard Zones') legend_title = tr('Population') legend_units = tr('(people per cell)') legend_notes = tr('Thousand separator is represented by %s' % get_thousand_separator()) extra_keywords = { 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title, 'total_needs': self.total_needs } self.set_if_provenance() impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Raster( data=covered_exposure_layer.get_data(), projection=covered_exposure_layer.get_projection(), geotransform=covered_exposure_layer.get_geotransform(), name=tr('People affected by volcano hazard zones'), keywords=impact_layer_keywords, style_info=style_info) self._impact = impact_layer return impact_layer
def run(self): """Run volcano population evacuation Impact Function. Counts number of people exposed to volcano event. :returns: Map of population exposed to the volcano hazard zone. The returned dict will include a table with number of people evacuated and supplies required. :rtype: dict :raises: * Exception - When hazard layer is not vector layer * RadiiException - When radii are not valid (they need to be monotonically increasing) """ # Parameters self.hazard_class_attribute = self.hazard.keyword('field') name_attribute = self.hazard.keyword('volcano_name_field') self.hazard_class_mapping = self.hazard.keyword('value_map') if has_no_data(self.exposure.layer.get_data(nan=True)): self.no_data_warning = True # Input checks if not self.hazard.layer.is_polygon_data: message = tr( 'Input hazard must be a polygon layer. I got %s with layer ' 'type %s' % ( self.hazard.layer.get_name(), self.hazard.layer.get_geometry_name())) raise Exception(message) # Check if hazard_class_attribute exists in hazard_layer if (self.hazard_class_attribute not in self.hazard.layer.get_attribute_names()): message = tr( 'Hazard data %s did not contain expected attribute ''%s ' % ( self.hazard.layer.get_name(), self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) features = self.hazard.layer.get_data() # Get names of volcanoes considered if name_attribute in self.hazard.layer.get_attribute_names(): # Run through all polygons and get unique names for row in features: self.volcano_names.add(row[name_attribute]) # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Initialize OrderedDict of affected buildings self.affected_population = OrderedDict() # Iterate over vector hazard classes for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building self.affected_population[vector_hazard_class['name']] = 0 # Run interpolation function for polygon2raster interpolated_layer, covered_exposure_layer = \ assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=self.target_field) # Count affected population per polygon and total for row in interpolated_layer.get_data(): # Get population at this location population = row[self.target_field] if not numpy.isnan(population): population = float(population) # Update population count for this hazard zone hazard_value = get_key_for_value( row[self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value self.affected_population[hazard_value] += population # Count totals self.total_population = int( numpy.nansum(self.exposure.layer.get_data())) self.unaffected_population = ( self.total_population - self.total_affected_population) self.minimum_needs = [ parameter.serialize() for parameter in filter_needs_parameters(self.parameters['minimum needs']) ] # check for zero impact if self.total_affected_population == 0: message = no_population_impact_message(self.question) raise ZeroImpactException(message) # Create style colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] classes = create_classes( covered_exposure_layer.get_data().flat[:], len(colours)) interval_classes = humanize_class(classes) # Define style info for output polygons showing population counts style_classes = [] for i in xrange(len(colours)): style_class = dict() style_class['label'] = create_label(interval_classes[i]) if i == 1: label = create_label( interval_classes[i], tr('Low Population [%i people/cell]' % classes[i])) elif i == 4: label = create_label( interval_classes[i], tr('Medium Population [%i people/cell]' % classes[i])) elif i == 7: label = create_label( interval_classes[i], tr('High Population [%i people/cell]' % classes[i])) else: label = create_label(interval_classes[i]) style_class['label'] = label style_class['quantity'] = classes[i] style_class['colour'] = colours[i] style_class['transparency'] = 0 style_classes.append(style_class) # Override style info with new classes and name style_info = dict( target_field=None, style_classes=style_classes, style_type='rasterStyle') impact_data = self.generate_data() extra_keywords = { 'target_field': self.target_field, 'map_title': self.map_title(), 'legend_notes': self.metadata().key('legend_notes'), 'legend_units': self.metadata().key('legend_units'), 'legend_title': self.metadata().key('legend_title'), 'total_needs': self.total_needs } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Raster( data=covered_exposure_layer.get_data(), projection=covered_exposure_layer.get_projection(), geotransform=covered_exposure_layer.get_geotransform(), 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
def run(self): """Risk plugin for volcano hazard on building/structure. Counts number of building exposed to each volcano hazard zones. :returns: Map of building exposed to volcanic hazard zones. Table with number of buildings affected :rtype: dict """ self.validate() self.prepare() self.provenance.append_step( 'Calculating Step', 'Impact function is calculating the impact.') # Get parameters from layer's keywords self.hazard_class_attribute = self.hazard.keyword('field') self.name_attribute = self.hazard.keyword('volcano_name_field') self.hazard_class_mapping = self.hazard.keyword('value_map') # Try to get the value from keyword, if not exist, it will not fail, # but use the old get_osm_building_usage try: self.exposure_class_attribute = self.exposure.keyword( 'structure_class_field') except KeywordNotFoundError: self.exposure_class_attribute = None # Input checks if not self.hazard.layer.is_polygon_data: message = ( 'Input hazard must be a polygon. I got %s with ' 'layer type %s' % (self.hazard.name, self.hazard.layer.get_geometry_name())) raise Exception(message) # Check if hazard_zone_attribute exists in hazard_layer if (self.hazard_class_attribute not in self.hazard.layer.get_attribute_names()): message = ( 'Hazard data %s did not contain expected attribute %s ' % (self.hazard.name, self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) # Get names of volcanoes considered if self.name_attribute in self.hazard.layer.get_attribute_names(): volcano_name_list = set() for row in self.hazard.layer.get_data(): # Run through all polygons and get unique names volcano_name_list.add(row[self.name_attribute]) self.volcano_names = ', '.join(volcano_name_list) else: self.volcano_names = tr('Not specified in data') # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Initialize OrderedDict of affected buildings self.affected_buildings = OrderedDict() # Iterate over vector hazard classes for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building self.affected_buildings[vector_hazard_class['name']] = {} # Run interpolation function for polygon2raster interpolated_layer = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer) # Extract relevant exposure data attribute_names = interpolated_layer.get_attribute_names() features = interpolated_layer.get_data() self.buildings = {} for i in range(len(features)): # Get the hazard value based on the value mapping in keyword hazard_value = get_key_for_value( features[i][self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value features[i][self.target_field] = get_string(hazard_value) if (self.exposure_class_attribute and self.exposure_class_attribute in attribute_names): usage = features[i][self.exposure_class_attribute] else: usage = get_osm_building_usage(attribute_names, features[i]) if usage in [None, 'NULL', 'null', 'Null', 0]: usage = tr('Unknown') if usage not in self.buildings: self.buildings[usage] = 0 for category in self.affected_buildings.keys(): self.affected_buildings[category][ usage] = OrderedDict([ (tr('Buildings Affected'), 0)]) self.buildings[usage] += 1 if hazard_value in self.affected_buildings.keys(): self.affected_buildings[hazard_value][usage][ tr('Buildings Affected')] += 1 # Lump small entries and 'unknown' into 'other' category # Building threshold #2468 postprocessors = self.parameters['postprocessors'] building_postprocessors = postprocessors['BuildingType'][0] self.building_report_threshold = building_postprocessors.value[0].value self._consolidate_to_other() # Generate simple impact report impact_summary = impact_table = self.html_report() # Create style colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] colours = colours[::-1] # flip colours = colours[:len(self.affected_buildings.keys())] style_classes = [] i = 0 for category_name in self.affected_buildings.keys(): style_class = dict() style_class['label'] = tr(category_name) style_class['transparency'] = 0 style_class['value'] = category_name style_class['size'] = 1 if i >= len(self.affected_buildings.keys()): i = len(self.affected_buildings.keys()) - 1 style_class['colour'] = colours[i] i += 1 style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') # For printing map purpose map_title = tr('Buildings affected by volcanic hazard zone') legend_title = tr('Building count') legend_units = tr('(building)') legend_notes = tr('Thousand separator is represented by %s' % get_thousand_separator()) extra_keywords = { 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title } self.set_if_provenance() impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Vector( data=features, projection=interpolated_layer.get_projection(), geometry=interpolated_layer.get_geometry(), name=tr('Buildings affected by volcanic hazard zone'), keywords=impact_layer_keywords, style_info=style_info ) self._impact = impact_layer return impact_layer
def run(self): """Run classified population evacuation Impact Function. Counts number of people exposed to each hazard zones. :returns: Map of population exposed to each hazard zone. The returned dict will include a table with number of people evacuated and supplies required. :rtype: dict :raises: * Exception - When hazard layer is not vector layer """ self.validate() self.prepare() self.provenance.append_step("Calculating Step", "Impact function is calculating the impact.") # Value from layer's keywords self.hazard_class_attribute = self.hazard.keyword("field") self.hazard_class_mapping = self.hazard.keyword("value_map") # TODO: Remove check to self.validate (Ismail) # Input checks message = tr( "Input hazard must be a polygon layer. I got %s with layer type " "%s" % (self.hazard.name, self.hazard.layer.get_geometry_name()) ) if not self.hazard.layer.is_polygon_data: raise Exception(message) # Check if hazard_class_attribute exists in hazard_layer if self.hazard_class_attribute not in self.hazard.layer.get_attribute_names(): message = ( "Hazard data %s does not contain expected hazard " 'zone attribute "%s". Please change it in the option. ' % (self.hazard.name, self.hazard_class_attribute) ) # noinspection PyExceptionInherit raise InaSAFEError(message) # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword("vector_hazard_classification") # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification["classes"] # Initialize OrderedDict of affected buildings self.affected_population = OrderedDict() # Iterate over vector hazard classes for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class["key"] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class["name"]] = self.hazard_class_mapping.pop( vector_hazard_class["key"] ) # Adding the class name as a key in affected_building self.affected_population[vector_hazard_class["name"]] = 0 # Interpolated layer represents grid cell that lies in the polygon interpolated_layer, covered_exposure_layer = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=self.target_field ) # Count total affected population per hazard zone for row in interpolated_layer.get_data(): # Get population at this location population = row[self.target_field] if not numpy.isnan(population): population = float(population) # Update population count for this hazard zone hazard_value = get_key_for_value(row[self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value self.affected_population[hazard_value] += population # Count total population from exposure layer self.total_population = int(numpy.nansum(self.exposure.layer.get_data())) # Count total affected population total_affected_population = self.total_affected_population self.unaffected_population = self.total_population - total_affected_population self.minimum_needs = [ parameter.serialize() for parameter in filter_needs_parameters(self.parameters["minimum needs"]) ] # check for zero impact if total_affected_population == 0: message = no_population_impact_message(self.question) raise ZeroImpactException(message) impact_table = impact_summary = self.html_report() # Create style colours = ["#FFFFFF", "#38A800", "#79C900", "#CEED00", "#FFCC00", "#FF6600", "#FF0000", "#7A0000"] classes = create_classes(covered_exposure_layer.get_data().flat[:], len(colours)) interval_classes = humanize_class(classes) # Define style info for output polygons showing population counts style_classes = [] for i in xrange(len(colours)): style_class = dict() style_class["label"] = create_label(interval_classes[i]) if i == 1: label = create_label(interval_classes[i], tr("Low Population [%i people/cell]" % classes[i])) elif i == 4: label = create_label(interval_classes[i], tr("Medium Population [%i people/cell]" % classes[i])) elif i == 7: label = create_label(interval_classes[i], tr("High Population [%i people/cell]" % classes[i])) else: label = create_label(interval_classes[i]) style_class["label"] = label style_class["quantity"] = classes[i] style_class["colour"] = colours[i] style_class["transparency"] = 0 style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=None, style_classes=style_classes, style_type="rasterStyle") # For printing map purpose map_title = tr("People impacted by each hazard zone") legend_title = tr("Population") legend_units = tr("(people per cell)") legend_notes = tr("Thousand separator is represented by %s" % get_thousand_separator()) extra_keywords = { "impact_summary": impact_summary, "impact_table": impact_table, "target_field": self.target_field, "map_title": map_title, "legend_notes": legend_notes, "legend_units": legend_units, "legend_title": legend_title, } self.set_if_provenance() impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Raster( data=covered_exposure_layer.get_data(), projection=covered_exposure_layer.get_projection(), geotransform=covered_exposure_layer.get_geotransform(), name=tr("People impacted by each hazard zone"), keywords=impact_layer_keywords, style_info=style_info, ) self._impact = impact_layer return impact_layer
def run(self): """Risk plugin for classified polygon hazard on building/structure. Counts number of building exposed to each hazard zones. :returns: Impact vector layer building exposed to each hazard zones. Table with number of buildings affected :rtype: Vector """ self.validate() self.prepare() self.provenance.append_step( 'Calculating Step', 'Impact function is calculating the impact.') # Value from layer's keywords self.hazard_class_attribute = self.hazard.keyword('field') self.hazard_class_mapping = self.hazard.keyword('value_map') # Try to get the value from keyword, if not exist, it will not fail, # but use the old get_osm_building_usage try: self.exposure_class_attribute = self.exposure.keyword( 'structure_class_field') except KeywordNotFoundError: self.exposure_class_attribute = None # Retrieve the classification that is used by the hazard layer. vector_hazard_classification = self.hazard.keyword( 'vector_hazard_classification') # Get the dictionary that contains the definition of the classification vector_hazard_classification = definition(vector_hazard_classification) # Get the list classes in the classification vector_hazard_classes = vector_hazard_classification['classes'] # Initialize OrderedDict of affected buildings self.affected_buildings = OrderedDict() # Iterate over vector hazard classes for vector_hazard_class in vector_hazard_classes: # Check if the key of class exist in hazard_class_mapping if vector_hazard_class['key'] in self.hazard_class_mapping.keys(): # Replace the key with the name as we need to show the human # friendly name in the report. self.hazard_class_mapping[vector_hazard_class['name']] = \ self.hazard_class_mapping.pop(vector_hazard_class['key']) # Adding the class name as a key in affected_building self.affected_buildings[vector_hazard_class['name']] = {} hazard_zone_attribute_index = self.hazard.layer.fieldNameIndex( self.hazard_class_attribute) # Check if hazard_zone_attribute exists in hazard_layer if hazard_zone_attribute_index < 0: message = ( 'Hazard data %s does not contain expected attribute %s ' % (self.hazard.layer.name(), self.hazard_class_attribute)) # noinspection PyExceptionInherit raise InaSAFEError(message) # Hazard zone categories from hazard layer unique_values = self.hazard.layer.uniqueValues( hazard_zone_attribute_index) # Values might be integer or float, we should have unicode. #2626 self.hazard_zones = [get_unicode(val) for val in unique_values] self.buildings = {} wgs84_extent = QgsRectangle( self.requested_extent[0], self.requested_extent[1], self.requested_extent[2], self.requested_extent[3]) # Run interpolation function for polygon2polygon interpolated_layer = interpolate_polygon_polygon( self.hazard.layer, self.exposure.layer, wgs84_extent) new_field = QgsField(self.target_field, QVariant.String) interpolated_layer.dataProvider().addAttributes([new_field]) interpolated_layer.updateFields() attribute_names = [ field.name() for field in interpolated_layer.pendingFields()] target_field_index = interpolated_layer.fieldNameIndex( self.target_field) changed_values = {} if interpolated_layer.featureCount() < 1: raise ZeroImpactException() # Extract relevant interpolated data for feature in interpolated_layer.getFeatures(): # Get the hazard value based on the value mapping in keyword hazard_value = get_key_for_value( feature[self.hazard_class_attribute], self.hazard_class_mapping) if not hazard_value: hazard_value = self._not_affected_value changed_values[feature.id()] = {target_field_index: hazard_value} if (self.exposure_class_attribute and self.exposure_class_attribute in attribute_names): usage = feature[self.exposure_class_attribute] else: usage = get_osm_building_usage(attribute_names, feature) if usage is None: usage = tr('Unknown') if usage not in self.buildings: self.buildings[usage] = 0 for category in self.hazard_class_mapping.keys(): self.affected_buildings[category][usage] = OrderedDict( [(tr('Buildings Affected'), 0)]) self.buildings[usage] += 1 if hazard_value in self.hazard_class_mapping.keys(): self.affected_buildings[hazard_value][usage][ tr('Buildings Affected')] += 1 interpolated_layer.dataProvider().changeAttributeValues(changed_values) # Lump small entries and 'unknown' into 'other' category # Building threshold #2468 postprocessors = self.parameters['postprocessors'] building_postprocessors = postprocessors['BuildingType'][0] self.building_report_threshold = building_postprocessors.value[0].value self._consolidate_to_other() # Generate simple impact report impact_summary = impact_table = self.html_report() # Create style categories = self.affected_buildings.keys() categories.append(self._not_affected_value) colours = color_ramp(len(categories)) style_classes = [] i = 0 for hazard_zone in self.affected_buildings.keys(): style_class = dict() style_class['label'] = tr(hazard_zone) style_class['transparency'] = 0 style_class['value'] = hazard_zone style_class['size'] = 1 style_class['colour'] = colours[i] style_classes.append(style_class) i += 1 # Override style info with new classes and name style_info = dict( target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol' ) # For printing map purpose map_title = tr('Buildings affected by each hazard zone') legend_title = tr('Building count') legend_units = tr('(building)') legend_notes = tr( 'Thousand separator is represented by %s' % get_thousand_separator()) extra_keywords = { 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title } self.set_if_provenance() impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Vector( data=interpolated_layer, name=tr('Buildings affected by each hazard zone'), keywords=impact_layer_keywords, style_info=style_info) self._impact = impact_layer return impact_layer