def validate(self): """Validate things needed before running the analysis.""" # Validate that input layers are valid if (self.hazard is None) or (self.exposure is None): message = tr( 'Ensure that hazard and exposure layers are all set before ' 'trying to run the impact function.') raise FunctionParametersError(message) # Validate extent, with the QGIS IF, we need requested_extent set if self.function_type() == 'qgis2.0' and self.requested_extent is None: message = tr( 'Impact Function with QGIS function type is used, but no ' 'extent is provided.') raise InvalidExtentError(message)
def run(self): """Plugin for impact of population as derived by continuous hazard. Hazard is reclassified into 3 classes based on the extrema provided as impact function parameters. Counts number of people exposed to each category of the hazard :returns: Map of population exposed to high category Table with number of people in each category """ thresholds = [ p.value for p in self.parameters['Categorical thresholds'].value ] # Thresholds must contain 3 thresholds if len(thresholds) != 3: raise FunctionParametersError( 'The thresholds must consist of 3 values.') # Thresholds must monotonically increasing monotonically_increasing_flag = all( x < y for x, y in zip(thresholds, thresholds[1:])) if not monotonically_increasing_flag: raise FunctionParametersError( 'Each threshold should be larger than the previous.') # The 3 categories low_t = thresholds[0] medium_t = thresholds[1] high_t = thresholds[2] # Extract data as numeric arrays hazard_data = self.hazard.layer.get_data(nan=True) # Category if has_no_data(hazard_data): self.no_data_warning = True # Calculate impact as population exposed to each category exposure_data = self.exposure.layer.get_data(nan=True, scaling=True) if has_no_data(exposure_data): self.no_data_warning = True # Make 3 data for each zone. Get the value of the exposure if the # exposure is in the hazard zone, else just assign 0 low_exposure = numpy.where(hazard_data < low_t, exposure_data, 0) medium_exposure = numpy.where( (hazard_data >= low_t) & (hazard_data < medium_t), exposure_data, 0) high_exposure = numpy.where( (hazard_data >= medium_t) & (hazard_data <= high_t), exposure_data, 0) impacted_exposure = low_exposure + medium_exposure + high_exposure # Count totals self.total_population = int(numpy.nansum(exposure_data)) self.affected_population[tr('Population in high hazard zones')] = int( numpy.nansum(high_exposure)) self.affected_population[tr( 'Population in medium hazard zones')] = int( numpy.nansum(medium_exposure)) self.affected_population[tr('Population in low hazard zones')] = int( numpy.nansum(low_exposure)) self.unaffected_population = (self.total_population - self.total_affected_population) # check for zero impact if self.total_affected_population == 0: message = no_population_impact_message(self.question) raise ZeroImpactException(message) # Don't show digits less than a 1000 self.minimum_needs = [ parameter.serialize() for parameter in filter_needs_parameters( self.parameters['minimum needs']) ] total_needs = self.total_needs # Style for impact layer colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] classes = create_classes(impacted_exposure.flat[:], len(colours)) interval_classes = humanize_class(classes) style_classes = [] for i in xrange(len(colours)): style_class = dict() 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['transparency'] = 0 style_class['colour'] = colours[i] style_classes.append(style_class) style_info = dict(target_field=None, style_classes=style_classes, style_type='rasterStyle') impact_data = self.generate_data() extra_keywords = { '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': total_needs } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create raster object and return impact_layer = Raster( data=impacted_exposure, projection=self.hazard.layer.get_projection(), geotransform=self.hazard.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, layers=None): """Plugin for impact of population as derived by classified hazard. Input :param layers: List of layers expected to contain * hazard_layer: Raster layer of classified hazard * exposure_layer: Raster layer of population data Counts number of people exposed to each class of the hazard Return Map of population exposed to high class Table with number of people in each class """ self.validate() self.prepare(layers) # The 3 classes # TODO (3.2): shouldnt these be defined in keywords rather? TS low_class = self.parameters['low_hazard_class'] medium_class = self.parameters['medium_hazard_class'] high_class = self.parameters['high_hazard_class'] # The classes must be different to each other unique_classes_flag = all(x != y for x, y in list( itertools.combinations([low_class, medium_class, high_class], 2))) if not unique_classes_flag: raise FunctionParametersError( 'There is hazard class that has the same value with other ' 'class. Please check the parameters.') # Identify hazard and exposure layers hazard_layer = self.hazard # Classified Hazard exposure_layer = self.exposure # Population Raster # Extract data as numeric arrays hazard_data = hazard_layer.get_data(nan=True) # Class no_data_warning = False if has_no_data(hazard_data): no_data_warning = True # Calculate impact as population exposed to each class population = exposure_layer.get_data(scaling=True) # Get all population data that falls in each hazard class high_hazard_population = numpy.where(hazard_data == high_class, population, 0) medium_hazard_population = numpy.where(hazard_data == medium_class, population, 0) low_hazard_population = numpy.where(hazard_data == low_class, population, 0) affected_population = (high_hazard_population + medium_hazard_population + low_hazard_population) # Carry the no data values forward to the impact layer. affected_population = numpy.where(numpy.isnan(population), numpy.nan, affected_population) affected_population = numpy.where(numpy.isnan(hazard_data), numpy.nan, affected_population) # Count totals total_population = int(numpy.nansum(population)) total_high_population = int(numpy.nansum(high_hazard_population)) total_medium_population = int(numpy.nansum(medium_hazard_population)) total_low_population = int(numpy.nansum(low_hazard_population)) total_affected = int(numpy.nansum(affected_population)) total_not_affected = total_population - total_affected # check for zero impact if total_affected == 0: table_body = [ self.question, TableRow( [tr('People affected'), '%s' % format_int(total_affected)], header=True) ] message = Table(table_body).toNewlineFreeString() raise ZeroImpactException(message) minimum_needs = [ parameter.serialize() for parameter in self.parameters['minimum needs'] ] table_body, total_needs = self._tabulate( population_rounding(total_high_population), population_rounding(total_low_population), population_rounding(total_medium_population), minimum_needs, population_rounding(total_not_affected), self.question, population_rounding(total_affected)) impact_table = Table(table_body).toNewlineFreeString() table_body = self._tabulate_action_checklist( table_body, population_rounding(total_population), no_data_warning) impact_summary = Table(table_body).toNewlineFreeString() # Create style colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] classes = create_classes(affected_population.flat[:], len(colours)) interval_classes = humanize_class(classes) style_classes = [] for i in xrange(len(colours)): style_class = dict() 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] if i == 0: transparency = 100 else: transparency = 0 style_class['transparency'] = transparency style_class['colour'] = colours[i] style_classes.append(style_class) style_info = dict(target_field=None, style_classes=style_classes, style_type='rasterStyle') # For printing map purpose map_title = tr('Population affected by each class') legend_notes = tr('Thousand separator is represented by %s' % get_thousand_separator()) legend_units = tr('(people per cell)') legend_title = tr('Number of People') # Create raster object and return raster_layer = Raster( data=affected_population, projection=exposure_layer.get_projection(), geotransform=exposure_layer.get_geotransform(), name=tr('Population which %s') % (self.impact_function_manager.get_function_title(self).lower()), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title, 'total_needs': total_needs }, style_info=style_info) self._impact = raster_layer return raster_layer
def run(self): """Plugin for impact of population as derived by classified hazard. Counts number of people exposed to each class of the hazard :returns: Map of population exposed to high class Table with number of people in each class """ # The 3 classes # TODO (3.2): shouldnt these be defined in keywords rather? TS categorical_hazards = self.parameters['Categorical hazards'].value low_class = categorical_hazards[0].value medium_class = categorical_hazards[1].value high_class = categorical_hazards[2].value # The classes must be different to each other unique_classes_flag = all(x != y for x, y in list( itertools.combinations([low_class, medium_class, high_class], 2))) if not unique_classes_flag: raise FunctionParametersError( 'There is hazard class that has the same value with other ' 'class. Please check the parameters.') # Extract data as numeric arrays hazard_data = self.hazard.layer.get_data(nan=True) # Class if has_no_data(hazard_data): self.no_data_warning = True # Calculate impact as population exposed to each class population = self.exposure.layer.get_data(scaling=True) # Get all population data that falls in each hazard class high_hazard_population = numpy.where(hazard_data == high_class, population, 0) medium_hazard_population = numpy.where(hazard_data == medium_class, population, 0) low_hazard_population = numpy.where(hazard_data == low_class, population, 0) affected_population = (high_hazard_population + medium_hazard_population + low_hazard_population) # Carry the no data values forward to the impact layer. affected_population = numpy.where(numpy.isnan(population), numpy.nan, affected_population) affected_population = numpy.where(numpy.isnan(hazard_data), numpy.nan, affected_population) # Count totals self.total_population = int(numpy.nansum(population)) self.affected_population[tr('Population in low hazard zone')] = int( numpy.nansum(low_hazard_population)) self.affected_population[tr('Population in medium hazard zone')] = int( numpy.nansum(medium_hazard_population)) self.affected_population[tr('Population in high hazard zone')] = int( numpy.nansum(high_hazard_population)) self.unaffected_population = (self.total_population - self.total_affected_population) # check for zero impact if self.total_affected_population == 0: message = no_population_impact_message(self.question) raise ZeroImpactException(message) self.minimum_needs = [ parameter.serialize() for parameter in self.parameters['minimum needs'] ] total_needs = self.total_needs # Create style colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] classes = create_classes(affected_population.flat[:], len(colours)) interval_classes = humanize_class(classes) style_classes = [] for i in xrange(len(colours)): style_class = dict() 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['transparency'] = 0 style_class['colour'] = colours[i] style_classes.append(style_class) style_info = dict(target_field=None, style_classes=style_classes, style_type='rasterStyle') impact_data = self.generate_data() extra_keywords = { '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': total_needs } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create raster object and return impact_layer = Raster( data=affected_population, projection=self.exposure.layer.get_projection(), geotransform=self.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, layers=None): """Plugin for impact of population as derived by categorised hazard. :param layers: List of layers expected to contain * hazard_layer: Raster layer of categorised hazard * exposure_layer: Raster layer of population data Counts number of people exposed to each category of the hazard :returns: Map of population exposed to high category Table with number of people in each category """ self.validate() self.prepare(layers) thresholds = self.parameters['Categorical thresholds'] # Thresholds must contain 3 thresholds if len(thresholds) != 3: raise FunctionParametersError( 'The thresholds must consist of 3 values.') # Thresholds must monotonically increasing monotonically_increasing_flag = all( x < y for x, y in zip(thresholds, thresholds[1:])) if not monotonically_increasing_flag: raise FunctionParametersError( 'Each threshold should be larger than the previous.') # The 3 categories low_t = thresholds[0] medium_t = thresholds[1] high_t = thresholds[2] # Identify hazard and exposure layers hazard_layer = self.hazard # Categorised Hazard exposure_layer = self.exposure # Population Raster # Extract data as numeric arrays hazard_data = hazard_layer.get_data(nan=True) # Category no_data_warning = False if has_no_data(hazard_data): no_data_warning = True # Calculate impact as population exposed to each category exposure_data = exposure_layer.get_data(nan=True, scaling=True) if has_no_data(exposure_data): no_data_warning = True # Make 3 data for each zone. Get the value of the exposure if the # exposure is in the hazard zone, else just assign 0 low_exposure = numpy.where(hazard_data < low_t, exposure_data, 0) medium_exposure = numpy.where( (hazard_data >= low_t) & (hazard_data < medium_t), exposure_data, 0) high_exposure = numpy.where( (hazard_data >= medium_t) & (hazard_data <= high_t), exposure_data, 0) impacted_exposure = low_exposure + medium_exposure + high_exposure # Count totals total = int(numpy.nansum(exposure_data)) low_total = int(numpy.nansum(low_exposure)) medium_total = int(numpy.nansum(medium_exposure)) high_total = int(numpy.nansum(high_exposure)) total_impact = high_total + medium_total + low_total # Check for zero impact if total_impact == 0: table_body = [ self.question, TableRow( [tr('People impacted'), '%s' % format_int(total_impact)], header=True) ] message = Table(table_body).toNewlineFreeString() raise ZeroImpactException(message) # Don't show digits less than a 1000 total = population_rounding(total) total_impact = population_rounding(total_impact) low_total = population_rounding(low_total) medium_total = population_rounding(medium_total) high_total = population_rounding(high_total) minimum_needs = [ parameter.serialize() for parameter in self.parameters['minimum needs'] ] table_body = self._tabulate(high_total, low_total, medium_total, self.question, total_impact) impact_table = Table(table_body).toNewlineFreeString() table_body, total_needs = self._tabulate_notes(minimum_needs, table_body, total, total_impact, no_data_warning) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('People in each hazard areas (low, medium, high)') # Style for impact layer colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] classes = create_classes(impacted_exposure.flat[:], len(colours)) interval_classes = humanize_class(classes) style_classes = [] for i in xrange(len(colours)): style_class = dict() 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] if i == 0: transparency = 100 else: transparency = 0 style_class['transparency'] = transparency style_class['colour'] = colours[i] style_classes.append(style_class) style_info = dict(target_field=None, style_classes=style_classes, style_type='rasterStyle') # Create raster object and return raster_layer = Raster( data=impacted_exposure, projection=hazard_layer.get_projection(), geotransform=hazard_layer.get_geotransform(), name=tr('Population might %s') % (self.impact_function_manager.get_function_title(self).lower()), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'total_needs': total_needs }, style_info=style_info) self._impact = raster_layer return raster_layer