def impact_summary(self): """The impact summary as per category :returns: The impact summary. :rtype: safe.message.Message """ affected_categories = self.affected_road_categories message = m.Message(style_class='container') table = m.Table(style_class='table table-condensed table-striped') table.caption = None row = m.Row() row.add(m.Cell(tr('Summary by road type'), header=True)) for _ in affected_categories: # Add empty cell as many as affected_categories row.add(m.Cell('', header=True)) if self.add_unaffected_column: # Add empty cell for un-affected road row.add(m.Cell('', header=True)) # Add empty cell for total column row.add(m.Cell('', header=True)) table.add(row) row = m.Row() row.add(m.Cell(tr('Road Type'), header=True)) for affected_category in affected_categories: row.add(m.Cell(affected_category, header=True, align='right')) if self.add_unaffected_column: row.add(m.Cell(tr('Unaffected'), header=True, align='right')) row.add(m.Cell(tr('Total'), header=True, align='right')) table.add(row) total_affected = [0] * len(affected_categories) for (category, road_breakdown) in self.affected_road_lengths.items(): number_affected = sum(road_breakdown.values()) count = affected_categories.index(category) total_affected[count] = number_affected row = m.Row() row.add(m.Cell(tr('All (m)'))) for total_affected_value in total_affected: row.add( m.Cell(format_int(int(total_affected_value)), align='right')) if self.add_unaffected_column: row.add( m.Cell(format_int( int(self.total_road_length - sum(total_affected))), align='right')) row.add(m.Cell(format_int(int(self.total_road_length)), align='right')) table.add(row) message.add(table) return message
def test_earthquake_building_impact_function(self): """Earthquake Building Impact Function works as expected.""" # Name file names for hazard level, exposure and expected fatalities hazard_filename = '%s/eq_yogya_2006.asc' % HAZDATA exposure_filename = '%s/OSM_building_polygons_20110905.shp' % TESTDATA # Calculate impact using API hazard_layer = read_layer(hazard_filename) exposure_layer = read_layer(exposure_filename) plugin_name = 'Earthquake Building Impact Function' impact_function = get_plugin(plugin_name) # Call calculation engine impact_layer = calculate_impact(layers=[hazard_layer, exposure_layer], impact_fcn=impact_function) impact_filename = impact_layer.get_filename() impact_layer = read_layer(impact_filename) # calculated_result = I.get_data() # print calculated_result.shape keywords = impact_layer.get_keywords() impact_summary = keywords['impact_summary'] # This is the expected number of building might be affected # Hazard Level - Buildings Affected # Low - 845 # Medium - 15524 # High - 122 message = 'Result not as expected' self.assertTrue(format_int(845) in impact_summary, message) self.assertTrue(format_int(15524) in impact_summary, message) self.assertTrue(format_int(122) in impact_summary, message)
def notes(self): """Return the notes section of the report. :return: The notes that should be attached to this impact report. :rtype: list """ population = format_int(population_rounding(self.total_population)) threshold = format_int(self.parameters['evacuation_percentage'].value) if get_needs_provenance_value(self.parameters) is None: needs_provenance = '' else: needs_provenance = tr(get_needs_provenance_value(self.parameters)) fields = [ tr('Total population in the analysis area: %s') % population, tr('<sup>1</sup>The evacuation threshold used to determine ' 'population needing evacuation is %s%%.') % threshold, needs_provenance, ] if self.no_data_warning: fields = fields + no_data_warning # include any generic exposure specific notes from definitions.py fields = fields + self.exposure_notes() # include any generic hazard specific notes from definitions.py fields = fields + self.hazard_notes() return fields
def action_checklist(self): """Breakdown by building type. :returns: The buildings breakdown report. :rtype: safe.messaging.Message """ schools_closed = self.schools_closed hospitals_closed = self.hospitals_closed message = m.Message(style_class='container') message.add(m.Heading(tr('Action checklist'), **styles.INFO_STYLE)) checklist = m.BulletedList() checklist.add( tr('Which structures have warning capacity (eg. sirens, speakers, ' 'etc.)?')) checklist.add( tr('Are the water and electricity services still operating?')) checklist.add(tr('Are the health centres still open?')) checklist.add(tr('Are the other public services accessible?')) checklist.add(tr('Which buildings will be evacuation centres?')) checklist.add(tr('Where will we locate the operations centre?')) checklist.add( tr('Where will we locate warehouse and/or distribution centres?')) checklist.add(tr('Are the schools and hospitals still active?')) if schools_closed > 0: checklist.add( tr('Where will the students from the %s closed schools ' 'go to study?') % format_int(schools_closed)) if hospitals_closed > 0: checklist.add( tr('Where will the patients from the %s closed hospitals go ' 'for treatment and how will we transport them?') % format_int(hospitals_closed)) message.add(checklist) return message
def action_checklist(self): """Action Checklist Data. :returns: An action list in dictionary format. :rtype: dict """ title = tr('Action checklist') fields = [ tr('Which structures have warning capacity (eg. sirens, speakers, ' 'etc.)?'), tr('Are the water and electricity services still operating?'), tr('Are the health centres still open?'), tr('Are the other public services accessible?'), tr('Which buildings will be evacuation centres?'), tr('Where will we locate the operations centre?'), tr('Where will we locate warehouse and/or distribution centres?'), tr('Are the schools and hospitals still active?'), ] if self.schools_closed > 0: fields.append(tr( 'Where will the students from the %s closed schools go to ' 'study?') % format_int(self.schools_closed)) if self.hospitals_closed > 0: fields.append(tr( 'Where will the patients from the %s closed hospitals go ' 'for treatment and how will we transport them?') % format_int( self.hospitals_closed)) return { 'title': title, 'fields': fields }
def action_checklist(self): """Breakdown by building type. :returns: The buildings breakdown report. :rtype: safe.messaging.Message """ schools_closed = self.schools_closed hospitals_closed = self.hospitals_closed message = m.Message(style_class='container') message.add(m.Heading(tr('Action checklist'), **styles.INFO_STYLE)) checklist = m.BulletedList() checklist.add(tr('Are the critical facilities still open?')) checklist.add(tr( 'Which structures have warning capacity (eg. sirens, speakers, ' 'etc.)?')) checklist.add(tr('Which buildings will be evacuation centres?')) checklist.add(tr('Where will we locate the operations centre?')) checklist.add( tr('Where will we locate warehouse and/or distribution centres?')) if schools_closed > 0: checklist.add(tr( 'Where will the students from the %s closed schools ' 'go to study?') % format_int(schools_closed)) if hospitals_closed > 0: checklist.add(tr( 'Where will the patients from the %s closed hospitals go ' 'for treatment and how will we transport them?') % format_int( hospitals_closed)) message.add(checklist) return message
def action_checklist(self): """Action checklist for the itb earthquake fatality report. :returns: The action checklist :rtype: list """ total_fatalities = self.total_fatalities total_displaced = self.total_evacuated rounded_displaced = format_int(population_rounding(total_displaced)) fields = super(ITBFatalityFunction, self).action_checklist() if total_fatalities: fields.append( tr('Are there enough victim identification units available ' 'for %s people?') % (format_int(population_rounding(total_fatalities)))) if rounded_displaced: fields.append( tr('Are there enough covered floor areas available for ' '%s people?') % rounded_displaced) fields.append( tr('Are there enough shelters and relief items available for ' '%s people?') % rounded_displaced) fields.append( tr('If yes, where are they located and how will we ' 'distribute them?')) fields.append( tr('If no, where can we obtain additional relief items ' 'from and how will we transport them?')) fields.append( tr('Are there enough water supply, sanitation, hygiene, food, ' 'shelter, medicines and relief items available for %s ' 'displaced people?') % rounded_displaced) return fields
def _tabulate_notes(self, minimum_needs, table_body, total, total_impact, no_data_warning): # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Map shows population count in high, medium, and low hazard ' 'area.'), tr('Total population: %s') % format_int(total), TableRow( tr('Table below shows the minimum needs for all ' 'affected people')) ]) if no_data_warning: table_body.extend([ tr('The layers contained `no data`. This missing data was ' 'carried through to the impact layer.'), tr('`No data` values in the impact layer were treated as 0 ' 'when counting the affected or total population.') ]) total_needs = evacuated_population_needs(total_impact, minimum_needs) for frequency, needs in total_needs.items(): table_body.append( TableRow([ tr('Needs should be provided %s' % frequency), tr('Total') ], header=True)) for resource in needs: table_body.append( TableRow([ tr(resource['table name']), format_int(resource['amount']) ])) return table_body, total_needs
def action_checklist(self): """Action checklist for the itb earthquake fatality report. :returns: The action checklist :rtype: list """ total_fatalities = self.total_fatalities total_displaced = self.total_evacuated rounded_displaced = format_int(population_rounding(total_displaced)) message = m.Message(style_class='container') message.add(m.Heading(tr('Action checklist'), **styles.INFO_STYLE)) checklist = m.BulletedList() if total_fatalities: checklist.add(tr( 'Are there enough victim identification units available ' 'for %s people?') % ( format_int(population_rounding(total_fatalities)))) if total_displaced: checklist.add(tr( 'Are there enough shelters and relief items available for ' '%s people?') % rounded_displaced) if rounded_displaced: checklist.add(tr( 'If yes, where are they located and how will we ' 'distribute them?')) if total_displaced: checklist.add(tr( 'If no, where can we obtain additional relief items ' 'from and how will we transport them?')) message.add(checklist) return message
def action_checklist(self): """Action checklist for the itb earthquake fatality report. :returns: The action checklist :rtype: list """ total_fatalities = self.total_fatalities total_displaced = self.total_evacuated rounded_displaced = format_int(population_rounding(total_displaced)) fields = super(ITBFatalityFunction, self).action_checklist() if total_fatalities: fields.append( tr("Are there enough victim identification units available " "for %s people?") % (format_int(population_rounding(total_fatalities))) ) if rounded_displaced: fields.append(tr("Are there enough covered floor areas available for " "%s people?") % rounded_displaced) fields.append( tr("Are there enough shelters and relief items available for " "%s people?") % rounded_displaced ) fields.append(tr("If yes, where are they located and how will we " "distribute them?")) fields.append( tr("If no, where can we obtain additional relief items " "from and how will we transport them?") ) fields.append( tr( "Are there enough water supply, sanitation, hygiene, food, " "shelter, medicines and relief items available for %s " "displaced people?" ) % rounded_displaced ) return fields
def _tabulate(self, counts, evacuated, minimum_needs, question, rounding, thresholds, total, no_data_warning): # noinspection PyListCreation table_body = [ question, TableRow([(tr('People in %.1f m of water') % thresholds[-1]), '%s*' % format_int(evacuated)], header=True), TableRow( tr('* Number is rounded up to the nearest %s') % rounding), TableRow(tr('Map shows the numbers of people needing evacuation'))] total_needs = evacuated_population_needs( evacuated, minimum_needs) for frequency, needs in total_needs.items(): table_body.append(TableRow( [ tr('Needs should be provided %s' % frequency), tr('Total') ], header=True)) for resource in needs: table_body.append(TableRow([ tr(resource['table name']), format_int(resource['amount'])])) table_body.append(TableRow(tr('Action Checklist:'), header=True)) table_body.append(TableRow(tr('How will warnings be disseminated?'))) table_body.append(TableRow(tr('How will we reach stranded people?'))) table_body.append(TableRow(tr('Do we have enough relief items?'))) table_body.append(TableRow(tr('If yes, where are they located and how ' 'will we distribute them?'))) table_body.append(TableRow(tr( 'If no, where can we obtain additional relief items from and how ' 'will we transport them to here?'))) # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Total population: %s') % format_int(total), tr('People need evacuation if tsunami levels exceed %(eps).1f m') % {'eps': thresholds[-1]}, tr('Minimum needs are defined in BNPB regulation 7/2008'), tr('All values are rounded up to the nearest integer in order to ' 'avoid representing human lives as fractions.')]) if len(counts) > 1: table_body.append(TableRow(tr('Detailed breakdown'), header=True)) for i, val in enumerate(counts[:-1]): s = (tr('People in %(lo).1f m to %(hi).1f m of water: %(val)i') % {'lo': thresholds[i], 'hi': thresholds[i + 1], 'val': format_int(val[0])}) table_body.append(TableRow(s)) if no_data_warning: table_body.extend([ tr('The layers contained `no data`. This missing data was ' 'carried through to the impact layer.'), tr('`No data` values in the impact layer were treated as 0 ' 'when counting the affected or total population.') ]) return table_body, total_needs
def test_format_int(self): """Test formatting integer """ my_int = 10000000 lang = os.getenv('LANG') my_formated_int = format_int(my_int) if lang == 'id': expected_str = '10.000.000' else: expected_str = '10,000,000' my_msg = 'Format integer is not valid' assert (my_formated_int == expected_str or my_formated_int == str(my_int)), my_msg my_int = 1234 lang = os.getenv('LANG') print lang my_formated_int = format_int(my_int) if lang == 'id': expected_str = '1.234' else: expected_str = '1,234' my_msg = 'Format integer %s is not valid' % my_formated_int assert (my_formated_int == expected_str or my_formated_int == str(my_int)), my_msg
def test_volcano_circle_population_impact(self): """Volcano function runs circular evacuation zone.""" # Name file names for hazard level, exposure and expected fatalities hazard_filename = '%s/Merapi_alert.shp' % TESTDATA exposure_filename = ('%s/glp10ag.asc' % EXPDATA) # Calculate impact using API hazard_layer = read_layer(hazard_filename) exposure_layer = read_layer(exposure_filename) plugin_name = 'Volcano Polygon Hazard Population' impact_function = get_plugin(plugin_name) impact_layer = calculate_impact( layers=[hazard_layer, exposure_layer], impact_fcn=impact_function) impact_filename = impact_layer.get_filename() impact_layer = read_layer(impact_filename) keywords = impact_layer.get_keywords() print keywords # This is the expected number of people affected # Distance [km] Total Cumulative # 3 15.800 15.800 # 5 17.300 33.100 # 10 125.000 158.000 message = 'Result not as expected' impact_summary = keywords['impact_summary'] self.assertTrue(format_int(15800) in impact_summary, message) self.assertTrue(format_int(17300) in impact_summary, message) self.assertTrue(format_int(125000) in impact_summary, message)
def format_breakdown(self): """Breakdown by road type. :returns: The roads breakdown report. :rtype: safe.message.Message """ road_breakdown = self.roads_breakdown attributes = road_breakdown['attributes'] fields = road_breakdown['fields'] message = m.Message(style_class='container') table = m.Table(style_class='table table-condensed table-striped') table.caption = None row = m.Row() row.add(m.Cell(tr('Breakdown by road type'), header=True)) for _ in attributes: # Add empty cell as many as affected_categories row.add(m.Cell('', header=True)) # Add empty cell for total column row.add(m.Cell('', header=True)) table.add(row) row = m.Row() # We align left the first column, then right. row.add(m.Cell(tr(attributes[0]), header=True)) for attribute in attributes[1:]: row.add(m.Cell(tr(attribute), header=True, align='right')) table.add(row) for field in fields: row = m.Row() # First column # proper format for i186 row.add(m.Cell( tr('%(road_type)s (m)') % { 'road_type': tr(field[0].capitalize())})) # Start from second column for value in field[1:]: row.add(m.Cell( format_int(int(value)), align='right')) table.add(row) impact_summary_fields = self.impact_summary['fields'] row = m.Row() row.add(m.Cell(tr('Total (m)'), header=True)) for field in impact_summary_fields: for value in field: row.add(m.Cell( format_int(int(value)), align='right', header=True)) table.add(row) message.add(table) return message
def test_earthquake_building_impact_function(self): """Earthquake Building Impact Function works as expected.""" # Name file names for hazard level, exposure and expected fatalities hazard_filename = '%s/eq_yogya_2006.asc' % HAZDATA exposure_filename = '%s/OSM_building_polygons_20110905.shp' % TESTDATA # Calculate impact using API hazard_layer = read_layer(hazard_filename) exposure_layer = read_layer(exposure_filename) plugin_name = 'Earthquake Building Impact Function' impact_function = get_plugin(plugin_name) # Call calculation engine impact_layer = calculate_impact( layers=[hazard_layer, exposure_layer], impact_fcn=impact_function) impact_filename = impact_layer.get_filename() impact_layer = read_layer(impact_filename) # calculated_result = I.get_data() # print calculated_result.shape keywords = impact_layer.get_keywords() impact_summary = keywords['impact_summary'] # This is the expected number of building might be affected # Hazard Level - Buildings Affected # Low - 845 # Medium - 15524 # High - 122 message = 'Result not as expected' self.assertTrue(format_int(845) in impact_summary, message) self.assertTrue(format_int(15524) in impact_summary, message) self.assertTrue(format_int(122) in impact_summary, message)
def action_checklist(self): """Action checklist for the itb earthquake fatality report. :returns: The action checklist :rtype: list """ total_fatalities = self.total_fatalities total_displaced = self.total_evacuated rounded_displaced = format_int(population_rounding(total_displaced)) fields = super(ITBFatalityFunction, self).action_checklist() if total_fatalities: fields.append(tr( 'Are there enough victim identification units available ' 'for %s people?') % ( format_int(population_rounding(total_fatalities)))) if total_displaced: fields.append(tr( 'Are there enough shelters and relief items available for ' '%s people?') % rounded_displaced) if rounded_displaced: fields.append(tr( 'If yes, where are they located and how will we ' 'distribute them?')) if total_displaced: fields.append(tr( 'If no, where can we obtain additional relief items ' 'from and how will we transport them?')) return fields
def roads_breakdown(self): """Breakdown by road type. :returns: The roads breakdown report. :rtype: list """ category_names = self.affected_road_categories roads_breakdown_report = [({"content": (tr("Breakdown by road type")), "header": True})] for road_type in self.road_lengths: affected_by_usage = [] for category in category_names: if road_type in self.affected_road_lengths[category]: affected_by_usage.append(self.affected_road_lengths[category][road_type]) else: affected_by_usage.append(0) road_detail = ( # building type [road_type.capitalize()] + # categories [format_int(int(x)) for x in affected_by_usage] + # total [format_int(int(self.road_lengths[road_type]))] ) roads_breakdown_report.append({"content": road_detail}) return roads_breakdown_report
def test_volcano_circle_population_impact(self): """Volcano function runs circular evacuation zone.""" # Name file names for hazard level, exposure and expected fatalities hazard_filename = '%s/Merapi_alert.shp' % TESTDATA exposure_filename = ('%s/glp10ag.asc' % EXPDATA) # Calculate impact using API hazard_layer = read_layer(hazard_filename) exposure_layer = read_layer(exposure_filename) plugin_name = 'Volcano Polygon Hazard Population' impact_function = get_plugin(plugin_name) impact_layer = calculate_impact(layers=[hazard_layer, exposure_layer], impact_fcn=impact_function) impact_filename = impact_layer.get_filename() impact_layer = read_layer(impact_filename) keywords = impact_layer.get_keywords() print keywords # This is the expected number of people affected # Distance [km] Total Cumulative # 3 15.800 15.800 # 5 17.300 33.100 # 10 125.000 158.000 message = 'Result not as expected' impact_summary = keywords['impact_summary'] self.assertTrue(format_int(15800) in impact_summary, message) self.assertTrue(format_int(17300) in impact_summary, message) self.assertTrue(format_int(125000) in impact_summary, message)
def hazard_table(self, hazard_table): """ Return updated hazard table. :param hazard_table: hazard table. :type hazard_table: Table :returns hazard_table: Updated Hazard Table :rtype area_name: Table """ hazard_table.caption = None for key, value in self.hazard_levels.iteritems(): name = self.hazard_class_mapping[key][0] # This skips reporting people not affected in No zone if key == 'wet': row = m.Row() row.add(m.Cell(tr( 'People within hazard field ("%s") of value "%s"') % (self.hazard_class_field, name), header=True)) value = format_int(population_rounding(value)) row.add(m.Cell(value, align='right')) elif key == 'dry': continue else: row = m.Row() row.add(m.Cell(name, header=True)) value = format_int(population_rounding(value)) row.add(m.Cell(value, align='right')) hazard_table.add(row) # Total affected population row = m.Row() row.add(m.Cell( tr('Total affected people'), header=True)) affected = format_int( population_rounding(self.total_affected_population)) row.add(m.Cell(affected, align='right')) hazard_table.add(row) # Non affected population row = m.Row() unaffected = format_int( population_rounding(self.unaffected_population)) row.add(m.Cell(tr('Unaffected people'), header=True)) row.add(m.Cell(unaffected, align='right')) hazard_table.add(row) # Total Population row = m.Row() total_population = format_int( population_rounding(self.total_population)) row.add(m.Cell(tr('Total people'), header=True)) row.add(m.Cell(total_population, align='right')) hazard_table.add(row) return hazard_table
def impact_summary(self): """The impact summary as per category :returns: The impact summary. :rtype: safe.message.Message """ affected_categories = self.affected_road_categories message = m.Message(style_class='container') table = m.Table(style_class='table table-condensed table-striped') table.caption = None row = m.Row() row.add(m.Cell(tr('Summary by road type'), header=True)) for _ in affected_categories: # Add empty cell as many as affected_categories row.add(m.Cell('', header=True)) if self.add_unaffected_column: # Add empty cell for un-affected road row.add(m.Cell('', header=True)) # Add empty cell for total column row.add(m.Cell('', header=True)) table.add(row) row = m.Row() row.add(m.Cell(tr('Road Type'), header=True)) for affected_category in affected_categories: row.add(m.Cell(affected_category, header=True, align='right')) if self.add_unaffected_column: row.add(m.Cell(tr('Unaffected'), header=True, align='right')) row.add(m.Cell(tr('Total'), header=True, align='right')) table.add(row) total_affected = [0] * len(affected_categories) for (category, road_breakdown) in self.affected_road_lengths.items(): number_affected = sum(road_breakdown.values()) count = affected_categories.index(category) total_affected[count] = number_affected row = m.Row() row.add(m.Cell(tr('All (m)'))) for total_affected_value in total_affected: row.add(m.Cell( format_int(int(total_affected_value)), align='right')) if self.add_unaffected_column: row.add(m.Cell(format_int(int( self.total_road_length - sum(total_affected))), align='right')) row.add(m.Cell(format_int(int(self.total_road_length)), align='right')) table.add(row) message.add(table) return message
def hazard_table(self, hazard_table): """ Return updated hazard table. :param hazard_table: hazard table. :type hazard_table: Table :returns hazard_table: Updated Hazard Table :rtype area_name: Table """ hazard_table.caption = None for key, value in self.hazard_levels.iteritems(): name = self.hazard_class_mapping[key][0] # This skips reporting people not affected in No zone if key == 'wet': row = m.Row() row.add( m.Cell( tr('People within hazard field ("%s") of value "%s"') % (self.hazard_class_field, name), header=True)) value = format_int(population_rounding(value)) row.add(m.Cell(value, align='right')) elif key == 'dry': continue else: row = m.Row() row.add(m.Cell(name, header=True)) value = format_int(population_rounding(value)) row.add(m.Cell(value, align='right')) hazard_table.add(row) # Total affected population row = m.Row() row.add(m.Cell(tr('Total affected people'), header=True)) affected = format_int( population_rounding(self.total_affected_population)) row.add(m.Cell(affected, align='right')) hazard_table.add(row) # Non affected population row = m.Row() unaffected = format_int(population_rounding( self.unaffected_population)) row.add(m.Cell(tr('Unaffected people'), header=True)) row.add(m.Cell(unaffected, align='right')) hazard_table.add(row) # Total Population row = m.Row() total_population = format_int( population_rounding(self.total_population)) row.add(m.Cell(tr('Total people'), header=True)) row.add(m.Cell(total_population, align='right')) hazard_table.add(row) return hazard_table
def _tabulate(self, affected_population, evacuated, minimum_needs, question, rounding, rounding_evacuated): # People Affected table_body = [ question, TableRow( [tr('People affected'), '%s*' % ( format_int(int(affected_population)))], header=True)] if self.use_affected_field: table_body.append( TableRow( tr('* People are considered to be affected if they are ' 'within the area where the value of the hazard field (' '"%s") is "%s"') % (self.parameters['affected_field'], self.parameters['affected_value']))) else: table_body.append( TableRow( tr('* People are considered to be affected if they are ' 'within any polygons.'))) table_body.append( TableRow([TableCell( tr('* Number is rounded up to the nearest %s') % rounding, col_span=2)])) # People Needing Evacuation table_body.append( TableRow([tr('People needing evacuation'), '%s*' % ( format_int(int(evacuated)))], header=True)) table_body.append(TableRow( [TableCell( tr('* Number is rounded up to the nearest %s') % rounding_evacuated, col_span=2)])) table_body.append( TableRow( [tr('Evacuation threshold'), '%s%%' % format_int( self.parameters['evacuation_percentage'])], header=True)) table_body.append( TableRow(tr('Table below shows the weekly minimum needs for all ' 'evacuated people'))) total_needs = evacuated_population_needs(evacuated, minimum_needs) for frequency, needs in total_needs.items(): table_body.append(TableRow( [ tr('Needs should be provided %s' % frequency), tr('Total') ], header=True)) for resource in needs: table_body.append(TableRow([ tr(resource['table name']), format_int(resource['amount'])])) return table_body, total_needs
def notes(self): """Return the notes section of the report. :return: The notes that should be attached to this impact report. :rtype: list """ notes = [ {'content': tr('Notes'), 'header': True}, { 'content': tr('Total population: %s') % format_int( population_rounding(self.total_population)) }, { 'content': tr( '<sup>1</sup>The evacuation threshold used to determine ' 'population needing evacuation is %s%%.'), 'arguments': format_int( self.parameters['evacuation_percentage'].value) }, { 'content': tr( '' 'are within any polygons.'), 'condition': not self.use_affected_field }, { 'content': tr( 'The layers contained `no data`. This missing data was ' 'carried through to the impact layer.'), 'condition': self.no_data_warning }, { 'content': tr( '`No data` values in the impact layer were treated as 0 ' 'when counting the affected or total population.'), 'condition': self.no_data_warning }, { 'content': get_needs_provenance_value(self.parameters) }, { 'content': tr( 'All values are rounded up to the nearest integer in ' 'order to avoid representing human lives as fractions.'), }, { 'content': tr( 'Population rounding is applied to all population ' 'values, which may cause discrepancies when adding ' 'values.' ) } ] return notes
def impact_row( area_name, affected, percent_affected, single_total_area, number_people_affected, percent_people_affected, area_population): """Adds the calculated results into respective impact row :param area_name: Area Name :type area_name: str :param affected: table with first and second row :type affected: Table :param percent_affected: percentage of affected area :type percent_affected: float :param single_total_area: total area of the land :type single_total_area: float :param number_people_affected: number of people affected :type number_people_affected: float :param percent_people_affected: percentage of people affected in the area :type percent_people_affected: float :param area_population: Population of the area :type area_population: float :return row: the new impact row :rtype row: Row """ row = m.Row() row.add(m.Cell(area_name)) row.add(m.Cell(format_int(int(affected)), align='right')) row.add(m.Cell( "%.1f%%" % percent_affected, align='right')) row.add(m.Cell( format_int(int(single_total_area)), align='right')) row.add(m.Cell( format_int(int(number_people_affected)), align='right')) row.add(m.Cell("%.1f%%" % percent_people_affected, align='right')) row.add(m.Cell( format_int(int(area_population)), align='right')) return row
def format_postprocessing(self): """Format postprocessing. :returns: The postprocessing. :rtype: safe.messaging.Message """ if not self.postprocessing: return False message = m.Message() for k, v in self.postprocessing.items(): table = m.Table( style_class='table table-condensed table-striped') table.caption = v['caption'] attributes = v['attributes'] if attributes: header = m.Row() # Bold and align left the 1st one. header.add(m.Cell(attributes[0], header=True, align='left')) for attribute in attributes[1:]: # Bold and align right. header.add(m.Cell(attribute, header=True, align='right')) header.add(m.Cell('Total', header=True, align='right')) table.add(header) for field in v['fields']: row = m.Row() # First column is string row.add(m.Cell(field[0])) total = 0 for value in field[1:]: try: val = int(value) total += val # Align right integers. row.add(m.Cell(format_int(val), align='right')) except ValueError: # Catch no data value. Align left strings. row.add(m.Cell(value, align='left')) row.add(m.Cell( format_int(int(round(total))), align='right')) table.add(row) message.add(table) for note in v['notes']: message.add(m.EmphasizedText(note)) return message
def impact_summary(self): """Create impact summary as data. :returns: Impact Summary in dictionary format. :rtype: dict """ attributes = ['category', 'value'] fields = [] # Breakdown by hazard level (if available) if len(self.impact_category_ordering): for category in self.impact_category_ordering: population_in_category = self.lookup_category(category) population_in_category = format_int(population_rounding( population_in_category )) row = [tr(category), population_in_category] fields.append(row) # Total affected population row = [ tr('Total affected population'), format_int(population_rounding(self.total_affected_population)) ] fields.append(row) # Non affected population row = [ tr('Unaffected population'), format_int(population_rounding(self.unaffected_population)) ] fields.append(row) # Total Population row = [ tr('Total population'), format_int(population_rounding(self.total_population)) ] fields.append(row) # Population needing evacuation row = [ tr('Population needing evacuation <sup>1</sup>'), format_int(population_rounding(self.total_evacuated)) ] fields.append(row) return { 'attributes': attributes, 'fields': fields }
def generate_analysis_result_html(self): """Return a HTML table of the analysis result :return: A file path to the html file saved to disk. """ message = m.Message(style_class='report') # Table for affected population table = m.Table(style_class='table table-condensed table-striped') row = m.Row() total_people = self.tr('%s') % format_int(population_rounding( self.impact_data.total_affected_population)) estimates_idp = self.tr('%s') % format_int(population_rounding( self.impact_data.estimates_idp)) row.add(m.Cell( self.tr('Total affected population (people)'), header=True)) row.add(m.Cell(total_people, style_class="text-right")) table.add(row) row = m.Row() row.add(m.Cell(self.tr('Estimates of IDP (people)'), header=True)) row.add(m.Cell(estimates_idp, style_class="text-right")) table.add(row) message.add(table) # Table for minimum needs for k, v in self.impact_data.minimum_needs.iteritems(): section = self.tr('Relief items to be provided %s :') % k # text = m.Text(section) row = m.Row(style_class='alert-info') row.add(m.Cell(section, header=True, attributes='colspan=2')) # message.add(text) table = m.Table( header=row, style_class='table table-condensed table-striped') for e in v: row = m.Row() need_name = self.tr(e['name']) need_number = format_int( population_rounding(e['amount'])) need_unit = self.tr(e['unit']['abbreviation']) if need_unit: need_string = '%s (%s)' % (need_name, need_unit) else: need_string = need_name row.add(m.Cell(need_string, header=True)) row.add(m.Cell(need_number, style_class="text-right")) table.add(row) message.add(table) path = self.write_html_table('impact_analysis_report.html', message) return path
def impact_summary(self): """The impact summary as per category. :returns: The impact summary. :rtype: safe.messaging.Message """ affect_types = self._impact_breakdown message = m.Message(style_class='container') table = m.Table(style_class='table table-condensed table-striped') table.caption = None row = m.Row() row.add(m.Cell('', header=True)) # intentionally empty top left cell row.add(m.Cell('Buildings affected', header=True)) for (category, building_breakdown) in self.affected_buildings.items(): total_affected = [0] * len(affect_types) for affected_breakdown in building_breakdown.values(): for affect_type, number_affected in affected_breakdown.items(): count = affect_types.index(affect_type) total_affected[count] += number_affected row = m.Row() row.add(m.Cell(tr(category), header=True)) for affected in total_affected: row.add(m.Cell(format_int(affected), align='right')) table.add(row) if len(self._affected_categories) > 1: row = m.Row() row.add(m.Cell(tr('Affected buildings'), header=True)) row.add( m.Cell(format_int(self.total_affected_buildings), align='right')) table.add(row) # Only show not affected building row if the IF does not use custom # affected categories if self._affected_categories == self.affected_buildings.keys(): row = m.Row() row.add(m.Cell(tr('Not affected buildings'), header=True)) row.add( m.Cell(format_int(self.total_unaffected_buildings), align='right')) table.add(row) row = m.Row() row.add(m.Cell(tr('Total'), header=True)) row.add(m.Cell(format_int(self.total_buildings), align='right')) table.add(row) message.add(table) return message
def format_impact_table(self): """Impact detailed report. :returns: The detailed report. :rtype: safe.messaging.Message """ message = m.Message(style_class='container') table = m.Table(style_class='table table-condensed table-striped') table.caption = None # Table header row = m.Row() attributes = self.impact_table['attributes'] # Bold and align left the 1st one. row.add(m.Cell(attributes[0], header=True, align='left')) for attribute in attributes[1:]: # Bold and align right. row.add(m.Cell(attribute, header=True, align='right')) table.add(row) # Fields for record in self.impact_table['fields'][:-1]: row = m.Row() # Bold and align left the 1st one. row.add(m.Cell(record[0], header=True, align='left')) for content in record[1:-1]: # Align right. row.add(m.Cell(format_int(int(content)), align='right')) # Bold and align right the last one. row.add( m.Cell(format_int(int(record[-1])), header=True, align='right')) table.add(row) # Total Row row = m.Row() last_row = self.impact_table['fields'][-1] # Bold and align left the 1st one. row.add(m.Cell(last_row[0], header=True, align='left')) for content in last_row[1:]: # Bold and align right. row.add( m.Cell(format_int(int(content)), header=True, align='right')) table.add(row) message.add(table) return message
def impact_summary(self): """The impact summary as per category. :returns: The impact summary. :rtype: safe.messaging.Message """ affect_types = self._impact_breakdown message = m.Message(style_class='container') table = m.Table(style_class='table table-condensed table-striped') table.caption = None row = m.Row() row.add(m.Cell('', header=True)) # intentionally empty top left cell row.add(m.Cell('Buildings affected', header=True)) for (category, building_breakdown) in self.affected_buildings.items(): total_affected = [0] * len(affect_types) for affected_breakdown in building_breakdown.values(): for affect_type, number_affected in affected_breakdown.items(): count = affect_types.index(affect_type) total_affected[count] += number_affected row = m.Row() row.add(m.Cell(tr(category), header=True)) for affected in total_affected: row.add(m.Cell(format_int(affected), align='right')) table.add(row) if len(self._affected_categories) > 1: row = m.Row() row.add(m.Cell(tr('Affected buildings'), header=True)) row.add(m.Cell( format_int(self.total_affected_buildings), align='right')) table.add(row) # Only show not affected building row if the IF does not use custom # affected categories if self._affected_categories == self.affected_buildings.keys(): row = m.Row() row.add(m.Cell(tr('Not affected buildings'), header=True)) row.add(m.Cell( format_int(self.total_unaffected_buildings), align='right')) table.add(row) row = m.Row() row.add(m.Cell(tr('Total'), header=True)) row.add(m.Cell( format_int(self.total_buildings), align='right')) table.add(row) message.add(table) return message
def format_impact_table(self): """Impact detailed report. :returns: The detailed report. :rtype: safe.messaging.Message """ message = m.Message(style_class='container') table = m.Table(style_class='table table-condensed table-striped') table.caption = None # Table header row = m.Row() attributes = self.impact_table['attributes'] # Bold and align left the 1st one. row.add(m.Cell(attributes[0], header=True, align='left')) for attribute in attributes[1:]: # Bold and align right. row.add(m.Cell(attribute, header=True, align='right')) table.add(row) # Fields for record in self.impact_table['fields'][:-1]: row = m.Row() # Bold and align left the 1st one. row.add(m.Cell(record[0], header=True, align='left')) for content in record[1:-1]: # Align right. row.add(m.Cell(format_int(int(content)), align='right')) # Bold and align right the last one. row.add( m.Cell( format_int(int(record[-1])), header=True, align='right')) table.add(row) # Total Row row = m.Row() last_row = self.impact_table['fields'][-1] # Bold and align left the 1st one. row.add(m.Cell(last_row[0], header=True, align='left')) for content in last_row[1:]: # Bold and align right. row.add( m.Cell(format_int(int(content)), header=True, align='right')) table.add(row) message.add(table) return message
def notes(self): """Notes and caveats for the IF report. :returns: Dicts containing notes. :rtype: list """ fields = [ tr('Total population in the analysis area: %s') % format_int(population_rounding(self.total_population)), tr('<sup>1</sup>People are displaced if they experience and ' 'survive a shake level of more than 5 on the MMI scale.'), tr('The fatality calculation assumes that no fatalities occur for ' 'shake levels below 4 and fatality counts of less than 50 are ' 'disregarded.') ] if self.__class__ != ITBFatalityFunction: fields.append(tr( 'Fatality model is from Institut Teknologi Bandung 2012.')) fields.append(tr( 'Fatality model is from the Population Vulnerability ' 'Pager Model.')) fields.extend([ tr('Map shows the estimation of displaced population.'), ]) # include any generic exposure specific notes from definitions.py fields = fields + self.exposure_notes() # include any generic hazard specific notes from definitions.py fields = fields + self.hazard_notes() return fields
def minimum_needs_breakdown(self): """Breakdown by population. :returns: The population breakdown report. :rtype: list """ message = m.Message(style_class='container') message.add(m.Heading( tr('Evacuated population minimum needs'), **styles.INFO_STYLE)) table = m.Table( style_class='table table-condensed table-striped') table.caption = None total_needs = self.total_needs for frequency, needs in total_needs.items(): row = m.Row() row.add(m.Cell( tr('Relief items to be provided %s' % frequency), header=True )) row.add(m.Cell(tr('Total'), header=True, align='right')) table.add(row) for resource in needs: row = m.Row() row.add(m.Cell(tr(resource['table name']))) row.add(m.Cell( tr(format_int(resource['amount'])), align='right' )) table.add(row) message.add(table) return message
def notes(self): """Return the notes section of the report. :return: The notes that should be attached to this impact report. :rtype: list """ if get_needs_provenance_value(self.parameters) is None: needs_provenance = '' else: needs_provenance = tr(get_needs_provenance_value(self.parameters)) if self.volcano_names: sorted_volcano_names = ', '.join(sorted(self.volcano_names)) else: sorted_volcano_names = tr('Not specified in data') fields = [ tr('Map shows buildings affected in each of the volcano buffered ' 'zones.'), tr('Total population in the analysis area: %s') % format_int(population_rounding(self.total_population)), tr('<sup>1</sup>People need evacuation if they are within the ' 'volcanic hazard zones.'), tr('Volcanoes considered: %s.') % sorted_volcano_names, ] if needs_provenance: fields.append(needs_provenance) if self.no_data_warning: fields = fields + no_data_warning # include any generic exposure specific notes from definitions.py fields = fields + self.exposure_notes() # include any generic hazard specific notes from definitions.py fields = fields + self.hazard_notes() return fields
def format_int(number): """Get the correct integer format. :param number: The number to format :type number: float or integer """ return format_int(int(number))
def test_issue47(self): """Issue47: Hazard & exposure data are in different proj to viewport. See https://github.com/AIFDR/inasafe/issues/47""" result, message = setup_scenario( self.dock, hazard='Continuous Flood', exposure='Population', function='Need evacuation', function_id='FloodEvacuationRasterHazardFunction') self.assertTrue(result, message) # Enable on-the-fly reprojection set_canvas_crs(GOOGLECRS, True) set_jakarta_google_extent(self.dock) # Press RUN self.dock.accept() result = self.dock.wvResults.page_to_text() message = 'Result not as expected: %s' % result # searching for values 6700 clean water [l] in result self.assertTrue(format_int(6700) in result, message)
def minimum_needs_breakdown(self): """Breakdown by population. :returns: The population breakdown report. :rtype: list """ message = m.Message(style_class='container') message.add( m.Heading(tr('Evacuated population minimum needs'), **styles.INFO_STYLE)) table = m.Table(style_class='table table-condensed table-striped') table.caption = None total_needs = self.total_needs for frequency, needs in total_needs.items(): row = m.Row() row.add( m.Cell(tr('Relief items to be provided %s' % frequency), header=True)) row.add(m.Cell(tr('Total'), header=True, align='right')) table.add(row) for resource in needs: row = m.Row() row.add(m.Cell(tr(resource['table name']))) row.add( m.Cell(tr(format_int(resource['amount'])), align='right')) table.add(row) message.add(table) return message
def notes(self): """Return the notes section of the report. :return: The notes that should be attached to this impact report. :rtype: safe.messaging.Message """ message = m.Message(style_class='container') message.add(m.Heading(tr('Notes and assumptions'), **styles.INFO_STYLE)) checklist = m.BulletedList() population = format_int(population_rounding(self.total_population)) checklist.add( tr('Total population in the analysis area: %s') % population) checklist.add( tr('<sup>1</sup>People need evacuation if they are in a ' 'hazard zone.')) checklist.add( tr('Map shows population count in high, medium, and low ' 'hazard areas.')) checklist.add( tr('All values are rounded up to the nearest integer in ' 'order to avoid representing human lives as fractions.')) checklist.add( tr('Population rounding is applied to all population ' 'values, which may cause discrepancies when adding values.')) message.add(checklist) return message
def test_volcano_population_evacuation_impact(self): """Population impact from volcanic hazard is computed correctly.""" # Name file names for hazard level, exposure and expected fatalities hazard_filename = '%s/donut.shp' % TESTDATA exposure_filename = ('%s/pop_merapi_clip.tif' % TESTDATA) # Calculate impact using API hazard_layer = read_layer(hazard_filename) exposure_layer = read_layer(exposure_filename) plugin_name = 'Volcano Polygon Hazard Population' impact_function = get_plugin(plugin_name) impact_layer = calculate_impact(layers=[hazard_layer, exposure_layer], impact_fcn=impact_function) impact_filename = impact_layer.get_filename() impact_layer = read_layer(impact_filename) keywords = impact_layer.get_keywords() # Check for expected results: for value in ['Merapi', 192055, 56514, 68568, 66971]: if isinstance(value, int): x = format_int(population_rounding(value)) else: x = value summary = keywords['impact_summary'] msg = ('Did not find expected value %s in summary %s' % (x, summary)) assert x in summary, msg
def _tabulate_action_checklist(self, table_body, total, nan_warning): # Action Checklist table_body.append(TableRow(tr('Action Checklist:'), header=True)) table_body.append(TableRow(tr('How will warnings be disseminated?'))) table_body.append(TableRow(tr('How will we reach stranded people?'))) table_body.append(TableRow(tr('Do we have enough relief items?'))) table_body.append( TableRow( 'If yes, where are they located and how will we distribute ' 'them?')) table_body.append( TableRow( 'If no, where can we obtain additional relief items from and ' 'how will we transport them to here?')) # Notes table_body.append(TableRow(tr('Notes'), header=True)) table_body.append( TableRow(tr('Total population: %s') % format_int(total))) table_body.append(TableRow(self.parameters['provenance'])) if nan_warning: table_body.extend([ tr('The population layer contained `no data`. This missing ' 'data was carried through to the impact layer.'), tr('`No data` values in the impact layer were treated as 0 ' 'when counting the affected or total population.') ])
def format_impact_summary(self): """The impact summary as per category :returns: The impact summary. :rtype: safe.message.Message """ attributes = self.impact_summary['attributes'] fields = self.impact_summary['fields'] message = m.Message(style_class='container') table = m.Table(style_class='table table-condensed table-striped') table.caption = None row = m.Row() row.add(m.Cell(tr('Summary by road type'), header=True)) for _ in attributes: row.add(m.Cell('', header=True)) row = m.Row() row.add(m.Cell(tr('Road Type'), header=True)) for affected_category in attributes: row.add(m.Cell(tr(affected_category), header=True, align='right')) table.add(row) row = m.Row() row.add(m.Cell(tr('All (m)'))) for total_affected_value in fields[0]: row.add(m.Cell( format_int(int(total_affected_value)), align='right')) table.add(row) message.add(table) return message
def _tabulate_action_checklist(self, table_body, total, no_data_warning): table_body.append(TableRow(tr('Action Checklist:'), header=True)) table_body.append(TableRow(tr('How will warnings be disseminated?'))) table_body.append(TableRow(tr('How will we reach stranded people?'))) table_body.append(TableRow(tr('Do we have enough relief items?'))) table_body.append( TableRow( tr('If yes, where are they located and how will we distribute ' 'them?'))) table_body.append( TableRow( tr('If no, where can we obtain additional relief items from ' 'and how will we transport them to here?'))) # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Map shows the numbers of people in high, medium, and low ' 'hazard class areas'), tr('Total population: %s') % format_int(total) ]) if no_data_warning: table_body.extend([ tr('The layers contained `no data`. This missing data was ' 'carried through to the impact layer.'), tr('`No data` values in the impact layer were treated as 0 ' 'when counting the affected or total population.') ]) return table_body
def notes(self): """Return the notes section of the report. :return: The notes that should be attached to this impact report. :rtype: safe.messaging.Message """ message = m.Message(style_class="container") message.add(m.Heading(tr("Notes and assumptions"), **styles.INFO_STYLE)) checklist = m.BulletedList() population = format_int(population_rounding(self.total_population)) checklist.add(tr("Total population in the analysis area: %s") % population) checklist.add(tr("<sup>1</sup>People need evacuation if they are in a " "hazard zone.")) checklist.add(tr("Map shows population count in high, medium, and low " "hazard areas.")) checklist.add( tr( "All values are rounded up to the nearest integer in " "order to avoid representing human lives as fractions." ) ) checklist.add( tr( "Population rounding is applied to all population " "values, which may cause discrepancies when adding values." ) ) message.add(checklist) return message
def _append_result(self, name, result, metadata=None): """add an indicator results to the postprocessors result. internal method to be used by the postprocessors to add an indicator results to the postprocessors result Args: * name: str the name of the indicator * result the value calculated by the indicator * metadata Dict of metadata Returns: None Raises: None """ if metadata is None: metadata = dict() # LOGGER.debug('name : ' + str(name) + '\nresult : ' + str(result)) if result is not None and result != self.NO_DATA_TEXT: try: result = format_int(result) except ValueError as e: LOGGER.debug(e) result = result self._results[name] = {'value': result, 'metadata': metadata}
def _append_result(self, name, result, metadata=None): """add an indicator results to the postprocessors result. internal method to be used by the postprocessors to add an indicator results to the postprocessors result Args: * name: str the name of the indicator * result the value calculated by the indicator * metadata Dict of metadata Returns: None Raises: None """ if metadata is None: metadata = dict() LOGGER.debug('name : ' + str(name) + '\nresult : ' + str(result)) if result is not None and result != self.NO_DATA_TEXT: try: result = format_int(result) except ValueError as e: LOGGER.debug(e) result = result self._results[name] = {'value': result, 'metadata': metadata}
def test_volcano_building_impact(self): """Building impact from volcanic hazard is computed correctly.""" # Name file names for hazard level, exposure and expected fatalities hazard_filename = os.path.join(TESTDATA, 'donut.shp') exposure_filename = test_data_path('exposure', 'bangunan.shp') # Calculate impact using API hazard = read_layer(hazard_filename) exposure = read_layer(exposure_filename) plugin_name = 'Volcano Building Impact' impact_function = get_plugin(plugin_name) impact_function.parameters['name attribute'] = 'GUNUNG' print 'Calculating' # Call calculation engine impact_layer = calculate_impact( layers=[hazard, exposure], impact_fcn=impact_function) impact_filename = impact_layer.get_filename() impact = read_layer(impact_filename) keywords = impact.get_keywords() # Check for expected results: for value in ['Merapi', 5, 86, 91, 1, 21, 22, 6, 107, 113]: if isinstance(value, int): x = format_int(value) else: x = value summary = keywords['impact_summary'] message = ( 'Did not find expected value %s in summary %s' % (x, summary)) self.assertIn(x, summary, message)
def notes(self): """Return the notes section of the report. :return: The notes that should be attached to this impact report. :rtype: list """ population = format_int(population_rounding(self.total_population)) thresholds = self.parameters['thresholds'].value if get_needs_provenance_value(self.parameters) is None: needs_provenance = '' else: needs_provenance = tr(get_needs_provenance_value(self.parameters)) fields = [ tr('Total population in the analysis area: %s') % population, tr('<sup>1</sup>People need evacuation if flood levels exceed ' '%(eps).1f m.') % { 'eps': thresholds[-1] }, needs_provenance, ] if self.no_data_warning: fields = fields + no_data_warning # include any generic exposure specific notes from definitions.py fields = fields + self.exposure_notes() # include any generic hazard specific notes from definitions.py fields = fields + self.hazard_notes() return fields
def notes(self): """Return the notes section of the report. :return: The notes that should be attached to this impact report. :rtype: list """ if get_needs_provenance_value(self.parameters) is None: needs_provenance = '' else: needs_provenance = tr(get_needs_provenance_value(self.parameters)) if self.volcano_names: sorted_volcano_names = ', '.join(sorted(self.volcano_names)) else: sorted_volcano_names = tr('Not specified in data') fields = [ tr('Total population in the analysis area: %s') % format_int(population_rounding(self.total_population)), tr('<sup>1</sup>People need evacuation if they are within the ' 'volcanic hazard zones.'), tr('Volcanoes considered: %s.') % sorted_volcano_names ] if needs_provenance: fields.append(needs_provenance) if self.no_data_warning: fields = fields + no_data_warning # include any generic exposure specific notes from definitions.py fields = fields + self.exposure_notes() # include any generic hazard specific notes from definitions.py fields = fields + self.hazard_notes() return fields
def generate_analysis_result_html(self): """Return a HTML table of the analysis result :return: A file path to the html file saved to disk. """ message = m.Message(style_class='report') # Table for affected population table = m.Table(style_class='table table-condensed table-striped') row = m.Row() total_people = self.tr('%s') % format_int( population_rounding(self.impact_data.total_affected_population)) estimates_idp = self.tr('%s') % format_int( population_rounding(self.impact_data.estimates_idp)) row.add( m.Cell(self.tr('Total affected population (people)'), header=True)) row.add(m.Cell(total_people, style_class="text-right")) table.add(row) row = m.Row() row.add(m.Cell(self.tr('Estimates of IDP (people)'), header=True)) row.add(m.Cell(estimates_idp, style_class="text-right")) table.add(row) message.add(table) # Table for minimum needs for k, v in self.impact_data.minimum_needs.iteritems(): section = self.tr('Relief items to be provided %s :') % k # text = m.Text(section) row = m.Row(style_class='alert-info') row.add(m.Cell(section, header=True, attributes='colspan=2')) # message.add(text) table = m.Table(header=row, style_class='table table-condensed table-striped') for e in v: row = m.Row() need_name = self.tr(e['name']) need_number = format_int(population_rounding(e['amount'])) need_unit = self.tr(e['unit']['abbreviation']) if need_unit: need_string = '%s (%s)' % (need_name, need_unit) else: need_string = need_name row.add(m.Cell(need_string, header=True)) row.add(m.Cell(need_number, style_class="text-right")) table.add(row) message.add(table) path = self.write_html_table('impact_analysis_report.html', message) return path
def _tabulate_zero_impact(self, evacuated, question, table_body, thresholds): table_body = [ question, TableRow([(tr('People in %.1f m of water') % thresholds[-1]), '%s' % format_int(evacuated)], header=True)] return table_body
def impact_summary(self): """The impact summary as per category :returns: The impact summary. :rtype: list """ affect_types = self._impact_breakdown impact_summary_report = [{ 'content': [tr('Hazard Category')] + affect_types, 'header': True }] for (category, building_breakdown) in self.affected_buildings.items(): total_affected = [0] * len(affect_types) for affected_breakdown in building_breakdown.values(): for affect_type, number_affected in affected_breakdown.items(): count = affect_types.index(affect_type) total_affected[count] += number_affected total_affected_formatted = [ format_int(affected) for affected in total_affected ] impact_summary_report.append( {'content': [tr(category)] + total_affected_formatted}) if len(self._affected_categories) > 1: impact_summary_report.append({ 'content': [ tr(tr('Total Buildings Affected')), format_int(self.total_affected_buildings) ], 'header': True }) impact_summary_report.append({ 'content': [ tr('Buildings Not Affected'), format_int(self.total_unaffected_buildings) ], 'header': True }) impact_summary_report.append({ 'content': [tr('All Buildings'), format_int(self.total_buildings)], 'header': True }) return impact_summary_report
def test_issue160(self): """Test that multipart features can be used in a scenario - issue #160 """ exposure = test_data_path('exposure', 'buildings.shp') hazard = test_data_path('hazard', 'flood_multipart_polygons.shp') # See https://github.com/AIFDR/inasafe/issues/71 # Push OK with the left mouse button # print 'Using QGIS: %s' % qgis_version() self.tearDown() button = DOCK.pbnRunStop # First part of scenario should have enabled run file_list = [hazard, exposure] hazard_layer_count, exposure_layer_count = load_layers(file_list) message = ('Incorrect number of Hazard layers: expected 1 got %s' % hazard_layer_count) self.assertTrue(hazard_layer_count == 1, message) message = ('Incorrect number of Exposure layers: expected 1 got %s' % exposure_layer_count) self.assertTrue(exposure_layer_count == 1, message) message = 'Run button was not enabled' self.assertTrue(button.isEnabled(), message) # Second part of scenario - run disabled when adding invalid layer # and select it - run should be disabled path = os.path.join(TESTDATA, 'issue71.tif') file_list = [path] # This layer has incorrect keywords clear_flag = False _, _ = load_layers(file_list, clear_flag) result, message = setup_scenario( DOCK, hazard='Flood Polygon', exposure='Buildings', function='Be flooded', function_id='FloodPolygonBuildingFunction') self.assertTrue(result, message) # Enable on-the-fly reprojection set_canvas_crs(GEOCRS, True) expected_extent = QgsRectangle(106.80801, -6.19531, 106.83456946836641, -6.167526) CANVAS.setExtent(expected_extent) crs = QgsCoordinateReferenceSystem('EPSG:4326') DOCK.define_user_analysis_extent(expected_extent, crs) # Press RUN # noinspection PyCallByClass,PyCallByClass,PyTypeChecker DOCK.accept() result = DOCK.wvResults.page_to_text() message = 'Result not as expected: %s' % result self.assertTrue(format_int(33) in result, message)
def impact_summary(self): """The impact summary as per category :returns: The impact summary. :rtype: safe.messaging.Message """ message = m.Message(style_class='container') table = m.Table(style_class='table table-condensed table-striped') table.caption = None row = m.Row() row.add( m.Cell(tr('Population needing evacuation <sup>1</sup>'), header=True)) evacuated = format_int(population_rounding(self.total_evacuated)) row.add(m.Cell(evacuated, align='right')) table.add(row) if len(self.impact_category_ordering): table.add(m.Row()) # add a blank line row = m.Row() row.add(m.Cell(tr('Total affected population'), header=True)) affected = format_int( population_rounding(self.total_affected_population)) row.add(m.Cell(affected, align='right')) table.add(row) for category in self.impact_category_ordering: population_in_category = self.lookup_category(category) population_in_category = format_int( population_rounding(population_in_category)) row = m.Row() row.add(m.Cell(tr(category), header=True)) row.add(m.Cell(population_in_category, align='right')) table.add(row) table.add(m.Row()) # add a blank line row = m.Row() unaffected = format_int(population_rounding( self.unaffected_population)) row.add(m.Cell(tr('Unaffected population'), header=True)) row.add(m.Cell(unaffected, align='right')) table.add(row) message.add(table) return message
def test_itb_earthquake_fatality_estimation(self): """Fatalities from ground shaking can be computed correctly using the ITB fatality model (Test data from Hadi Ghasemi).""" # Name file names for hazard level, exposure and expected fatalities hazard_filename = '%s/itb_test_mmi.asc' % TESTDATA exposure_filename = '%s/itb_test_pop.asc' % TESTDATA # Calculate impact using API hazard_layer = read_layer(hazard_filename) exposure_layer = read_layer(exposure_filename) plugin_name = 'ITB Fatality Function' impact_function = get_plugin(plugin_name) # Call calculation engine impact_layer = calculate_impact(layers=[hazard_layer, exposure_layer], impact_fcn=impact_function) impact_filename = impact_layer.get_filename() impact_layer = read_layer(impact_filename) # calculated_result = I.get_data() # print calculated_result.shape keywords = impact_layer.get_keywords() # print "keywords", keywords population = float(keywords['total_population']) fatalities = float(keywords['total_fatalities']) # Check aggregated values expected_population = population_rounding(85424650.0) msg = ('Expected population was %f, I got %f' % (expected_population, population)) assert population == expected_population, msg expected_fatalities = population_rounding(40871.3028) msg = ('Expected fatalities was %f, I got %f' % (expected_fatalities, fatalities)) assert numpy.allclose(fatalities, expected_fatalities, rtol=1.0e-5), msg # Check that aggregated number of fatilites is as expected all_numbers = int( numpy.sum([ 31.8937368131, 2539.26369372, 1688.72362573, 17174.9261705, 19436.834531 ])) msg = ('Aggregated number of fatalities not as expected: %i' % all_numbers) assert all_numbers == 40871, msg x = population_rounding(all_numbers) msg = ('Did not find expected fatality value %i in summary %s' % (x, keywords['impact_summary'])) assert format_int(x) in keywords['impact_summary'], msg
def notes(self): """Return the notes section of the report. :return: The notes that should be attached to this impact report. :rtype: safe.messaging.Message """ if get_needs_provenance_value(self.parameters) is None: needs_provenance = '' else: needs_provenance = tr(get_needs_provenance_value(self.parameters)) message = m.Message(style_class='container') message.add( m.Heading(tr('Notes and assumptions'), **styles.INFO_STYLE)) checklist = m.BulletedList() population = format_int(population_rounding(self.total_population)) checklist.add(tr( 'Total population in the analysis area: %s') % population) threshold = format_int(self.parameters['evacuation_percentage'].value) checklist.add(tr( '<sup>1</sup>The evacuation threshold used to determine ' 'population needing evacuation is %s%%.') % threshold) checklist.add(needs_provenance) if self.no_data_warning: checklist.add(tr( 'The layers contained "no data" values. This missing data ' 'was carried through to the impact layer.')) checklist.add(tr( '"No data" values in the impact layer were treated as 0 ' 'when counting the affected or total population.')) checklist.add(tr( 'All values are rounded up to the nearest integer in ' 'order to avoid representing human lives as fractions.')) checklist.add(tr( 'Population rounding is applied to all population ' 'values, which may cause discrepancies when adding values.')) message.add(checklist) return message