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 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 flood population evacuation. Counts number of people exposed to areas identified as flood prone :returns: Map of population exposed to flooding Table with number of people evacuated and supplies required. :rtype: tuple """ 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.hazard_class_mapping = self.hazard.keyword('value_map') # Get the IF parameters self._evacuation_percentage = ( self.parameters['evacuation_percentage'].value) # Check that hazard is polygon type if not self.hazard.layer.is_polygon_data: message = ( 'Input hazard must be a polygon layer. I got %s with layer ' 'type %s' % ( self.hazard.name, self.hazard.layer.get_geometry_name())) raise Exception(message) if has_no_data(self.exposure.layer.get_data(nan=True)): self.no_data_warning = True # Check that affected field exists in hazard layer if (self.hazard_class_attribute in self.hazard.layer.get_attribute_names()): self.use_affected_field = True # Run interpolation function for polygon2raster interpolated_layer, covered_exposure = \ assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=self.target_field) # Data for manipulating the covered_exposure layer new_covered_exposure_data = covered_exposure.get_data() covered_exposure_top_left = numpy.array([ covered_exposure.get_geotransform()[0], covered_exposure.get_geotransform()[3]]) covered_exposure_dimension = numpy.array([ covered_exposure.get_geotransform()[1], covered_exposure.get_geotransform()[5]]) # Count affected population per polygon, per category and total total_affected_population = 0 for attr in interpolated_layer.get_data(): affected = False if self.use_affected_field: row_affected_value = attr[self.hazard_class_attribute] if row_affected_value is not None: affected = get_key_for_value( row_affected_value, self.hazard_class_mapping) else: # assume that every polygon is affected (see #816) affected = self.wet if affected == self.wet: # Get population at this location population = attr[self.target_field] if not numpy.isnan(population): population = float(population) total_affected_population += population else: # If it's not affected, set the value of the impact layer to 0 grid_point = attr['grid_point'] index = numpy.floor( (grid_point - covered_exposure_top_left) / ( covered_exposure_dimension)).astype(int) new_covered_exposure_data[index[1]][index[0]] = 0 # Estimate number of people in need of evacuation if self.use_affected_field: affected_population = tr( 'People within hazard field ("%s") of value "%s"') % ( self.hazard_class_attribute, ','.join([ unicode(hazard_class) for hazard_class in self.hazard_class_mapping[self.wet] ])) else: affected_population = tr('People within any hazard polygon.') self.affected_population[affected_population] = ( total_affected_population) self.total_population = int( numpy.nansum(self.exposure.layer.get_data(scaling=False))) 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() # Create style colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] classes = create_classes( new_covered_exposure_data.flat[:], len(colours)) # check for zero impact if total_affected_population == 0: message = no_population_impact_message(self.question) raise ZeroImpactException(message) 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 flood prone areas') legend_title = tr('Population Count') legend_units = tr('(people per polygon)') 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, 'affected_population': total_affected_population, 'total_population': self.total_population, '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=new_covered_exposure_data, projection=covered_exposure.get_projection(), geotransform=covered_exposure.get_geotransform(), name=tr('People affected by flood prone areas'), 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): """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 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): """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 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): """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 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 """ # 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 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 """ 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