def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, You can choose a exposure ' 'layer from the list of layers that have been loaded to QGIS and ' 'that matches with the geometry and exposure type you set in the ' 'previous step').format(step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you will be able to define ' 'field mappings to use for demographic breakdowns of your ' 'analysis results.').format(step_name=self.step_name))) message.add(field_mapping_help_content()) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add(m.Paragraph(tr( 'In this wizard step: {step_name}, you will know that your ' 'exposure and hazard layer do not intersect with your aggregation ' 'layer. You can not go forward and you need to change the layer ' 'to run an analysis.' ).format(step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you will be able to set the ' 'classification that you will use per exposure type. You can also ' 'set the threshold or value map for each classification.'). format(step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you will be able to set the ' 'unit of the layer that is being assigned in this wizard. This ' 'only applies for continuous layer.').format( step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, You can choose a hazard layer ' 'from the list of layers from local disk or postgres database ' 'that matches with the geometry and hazard type you set in the ' 'previous step').format(step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you can choose where your ' 'aggregation layer come from. The option for choosing aggregation ' 'layer from QGIS can not be chosen if there is no aggregation ' 'layer in QGIS.').format(step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you will see the summary of ' 'the analysis that you have set up from the previous steps. You ' 'can click run button to run the analysis.').format( step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you will be able to map the ' 'value in the field (in the left panel) to a group in the right ' 'panel. You can do this by drag the value and drop it to the ' 'preferred group.').format(step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add(m.Paragraph(tr( 'In this wizard step: {step_name}, you will be able to ' 'set a field that corresponded with a InaSAFE field ' 'concept. It also allows you to set a default value for all ' 'feature if you do not want to use any field').format( step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you will be able to set the ' 'purpose of the layer. We have 3 options: hazard, exposure, ' 'and aggregation layer purpose.' '').format(step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you will be able to ' 'set a value that corresponded with a InaSAFE field ' 'concept as default value.').format( step_name=self.step_name))) return message
def content(): """Helper method that returns just the content. This method was added so that the text could be reused in the dock_help module. .. versionadded:: 3.2.2 :returns: A message object without brand element. :rtype: safe.messaging.message.Message """ message = m.Message() message.add( m.Paragraph( tr('To start report generation you need to click on the Print... ' 'button in the buttons area. This will open the Impact report ' 'dialog which has three main areas.'))) bullets = m.BulletedList() bullets.add( m.Text( m.ImportantText(tr('Area to print')), tr(' - There are two options available. Choose Current extent if ' 'current canvas extent represents necessary area. Analysis ' 'extent will set extent of the report map to impact layer ' 'extent.'))) bullets.add( m.Text( m.ImportantText(tr('Template to use')), tr(' - Here you can select desired template for your report. All ' 'templates bundled with InaSAFE are available here, plus ' 'templates from user-defined template directory (see Options ' 'for information how to set templates directory). It is also ' 'possible to select custom template from any location: just ' 'activate radiobutton under combobox and provide path to template ' 'using the "..." button.'))) bullets.add( m.Text( m.ImportantText(tr('Buttons area')), tr(' - In this area you will find buttons to open the report as ' 'a PDF or in the QGIS print composer. You can also get help by ' 'clicking on the help button or using the close button to close ' 'the print dialog.'))) message.add(bullets) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add(m.Paragraph(tr( 'In this wizard step: {step_name}, you will see the summary of ' 'the analysis that you have run. You can get your PDF report or ' 'show the report in the web browser by clicking the <b>Generate ' 'PDF</b> and <b>Open in web browser</b> respectively. You can ' 'also click the <b>Finish</b> button to end the wizard session.' ).format(step_name=self.step_name))) return message
def content(): """Helper method that returns just the content. This method was added so that the text could be reused in the dock_help module. .. versionadded:: 3.2.3 :returns: A message object without brand element. :rtype: safe.messaging.message.Message """ message = m.Message() link = m.Link('https://petajakarta.org', 'PetaJakarta.org') body = m.Paragraph( tr('This tool will fetch current flood data for Jakarta from '), link) tips = m.BulletedList() tips.add( tr('Check the output directory is correct. Note that the saved ' 'dataset will be called jakarta_flood.shp (and associated files).')) tips.add( tr('If you wish you can specify a prefix to ' 'add in front of this default name. For example using a prefix ' 'of \'foo-\' will cause the downloaded files to be saved as e.g. ' '\'foo-rw-jakarta-flood.shp\'. Note that the only allowed prefix ' 'characters are A-Z, a-z, 0-9 and the characters \'-\' and \'_\'. ' 'You can leave this blank if you prefer.')) tips.add( tr('If a dataset already exists in the output directory it will be ' 'overwritten if the "overwrite existing files" checkbox is ticked.') ) tips.add( tr('If the "include date/time in output filename" option is ticked, ' 'the filename will be prefixed with a time stamp e.g. ' '\'foo-22-Mar-2015-08-01-2015-rw-jakarta-flood.shp\' where the date ' 'timestamp is in the form DD-MMM-YYYY.')) tips.add( tr('This tool requires a working internet connection and fetching ' 'data will consume your bandwidth.')) tips.add( m.Link('https://petajakarta.org/banjir/en/data/', text=tr( 'Downloaded data is copyright the PetaJakarta contributors' ' (click for more info).'))) message.add(body) message.add(tips) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add(m.Paragraph(tr( 'In this wizard step: {step_name}, you will be able to set the ' 'type of your layer based on the purpose that you have set in the ' 'previous step (if you choose hazard or exposure purpose). In ' 'this step, there is list of exposure / hazard type that you can ' 'select to specify your layer purpose type.' ).format(step_name=self.step_name))) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name} you will be allowed to specify ' 'which geographical region should be used for your analysis. ' 'There are a number of different modes that can be used which are ' 'described below:').format(step_name=self.step_name))) message.add(extent_mode_content()) return message
def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add(m.Paragraph(tr( 'In this wizard step: {step_name}, there is a grid that shows all ' 'possible combination for hazard and exposure that can be run in ' 'InaSAFE. You can select a grid cell where your intended exposure ' 'and hazard intersect. This will help you to choose the ' 'layer that is suitable for the analysis. You can only ' 'select the green grid cell. The grey color indicates that the ' 'combination is not supported by InaSAFE.' '').format(step_name=self.step_name))) return message
def content(): """Helper method that returns just the content. This method was added so that the text could be reused in the dock_help module. .. versionadded:: 3.2.2 :returns: A message object without brand element. :rtype: safe.messaging.message.Message """ message = m.Message() paragraph = m.Paragraph( m.Image( 'file:///%s/img/screenshots/' 'shakemap-converter-screenshot.png' % resources_path()), style_class='text-center' ) message.add(paragraph) body = tr( 'This tool will convert an earthquake \'shakemap\' that is in ' 'grid xml format into a GeoTIFF file. The imported file can be used ' 'in InaSAFE as an input for impact functions that require an ' 'earthquake layer. To use this tool effectively:') message.add(body) tips = m.BulletedList() tips.add(tr( 'Select a grid.xml for the input layer.')) tips.add(tr( 'Choose where to write the output layer to.' )) tips.add(tr( 'Choose the interpolation algorithm that should be used when ' 'converting the xml grid to a raster. If unsure keep the default.' )) tips.add(tr( 'If you want to obtain shake data you can get download it free from ' 'the USGS shakemap site: ' 'http://earthquake.usgs.gov/earthquakes/shakemap/list.php?y=2013')) message.add(tips) return message
def missing_keyword_message(sender, missing_keyword_exception): """Display an error when there is missing keyword. :param sender: The sender. :type sender: object :param missing_keyword_exception: A KeywordNotFoundError exception. :type missing_keyword_exception: KeywordNotFoundError """ warning_heading = m.Heading( tr('Missing Keyword'), **WARNING_STYLE) warning_message = tr( 'There is missing keyword that needed for this analysis.') detail_heading = m.Heading( tr('Detail'), **DETAILS_STYLE) suggestion_heading = m.Heading( tr('Suggestion'), **DETAILS_STYLE) detail = tr( 'The layer <b>%s</b> is missing the keyword <i>%s</i>.' % ( missing_keyword_exception.layer_name, missing_keyword_exception.keyword ) ) suggestion = m.Paragraph( tr('Please use the keyword wizard to update the keywords. You ' 'can open the wizard by clicking on the '), m.Image( 'file:///%s/img/icons/' 'show-keyword-wizard.svg' % resources_path(), **SMALL_ICON_STYLE), tr( ' icon in the toolbar.')) message = m.Message() message.add(warning_heading) message.add(warning_message) message.add(detail_heading) message.add(detail) message.add(suggestion_heading) message.add(suggestion) send_static_message(sender, message)
def show_no_keywords_message(sender): """Show a message indicating that no keywords are defined. .. note:: The print button will be disabled if this method is called. """ LOGGER.debug('Showing No Keywords Message') message = generate_input_error_message( tr('Layer keywords missing:'), m.Paragraph( tr('No keywords have been defined for this layer yet or there is ' 'an issue with the currently defined keywords and they need ' 'to be reviewed. If you wish to use this layer as an ' 'exposure, hazard, or aggregation layer in an analysis, ' 'please use the keyword wizard to update the keywords. You ' 'can open the wizard by clicking on the '), m.Image( 'file:///%s/img/icons/' 'show-keyword-wizard.svg' % resources_path(), **SMALL_ICON_STYLE), tr(' icon in the toolbar.'))) send_static_message(sender, message)
def open_as_pdf(self): """Print the selected report as a PDF product. .. versionadded: 4.3.0 """ # Get output path from datastore report_urls_dict = report_urls(self.impact_function) # get report urls for each product tag as list for key, value in list(report_urls_dict.items()): report_urls_dict[key] = list(value.values()) if self.dock: # create message to user status = m.Message( m.Heading(self.dock.tr('Map Creator'), **INFO_STYLE), m.Paragraph( self.dock. tr('Your PDF was created....opening using the default PDF ' 'viewer on your system.')), m.ImportantText( self.dock.tr('The generated pdfs were saved ' 'as:'))) for path in report_urls_dict.get(pdf_product_tag['key'], []): status.add(m.Paragraph(path)) status.add( m.Paragraph( m.ImportantText( self.dock.tr('The generated htmls were saved as:')))) for path in report_urls_dict.get(html_product_tag['key'], []): status.add(m.Paragraph(path)) status.add( m.Paragraph( m.ImportantText( self.dock.tr('The generated qpts were saved as:')))) for path in report_urls_dict.get(qpt_product_tag['key'], []): status.add(m.Paragraph(path)) send_static_message(self.dock, status) for path in report_urls_dict.get(pdf_product_tag['key'], []): # noinspection PyCallByClass,PyTypeChecker,PyTypeChecker QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(path))
def getting_started_message(): """Generate a message for initial application state. :returns: Information for the user on how to get started. :rtype: safe.messaging.Message """ message = m.Message() message.add(LOGO_ELEMENT) message.add(m.Heading(tr('Getting started'), **INFO_STYLE)) notes = m.Paragraph( tr( 'These are the minimum steps you need to follow in order ' 'to use InaSAFE:')) message.add(notes) basics_list = m.NumberedList() basics_list.add(m.Paragraph( tr('Add at least one '), m.ImportantText(tr('hazard'), **KEYWORD_STYLE), tr(' layer (e.g. earthquake MMI) to QGIS.'))) basics_list.add(m.Paragraph( tr('Add at least one '), m.ImportantText(tr('exposure'), **KEYWORD_STYLE), tr(' layer (e.g. structures) to QGIS.'))) basics_list.add(m.Paragraph( tr( 'Make sure you have defined keywords for your hazard and ' 'exposure layers. You can do this using the ' 'keywords creation wizard '), m.Image( 'file:///%s/img/icons/show-keyword-wizard.svg' % (resources_path()), **SMALL_ICON_STYLE), tr(' in the toolbar.'))) basics_list.add(m.Paragraph( tr('Click on the '), m.ImportantText(tr('Run'), **KEYWORD_STYLE), tr(' button below.'))) message.add(basics_list) message.add(m.Heading(tr('Limitations'), **WARNING_STYLE)) caveat_list = m.NumberedList() for limitation in limitations(): caveat_list.add(limitation) message.add(caveat_list) message.add(m.Heading(tr('Disclaimer'), **WARNING_STYLE)) message.add(m.Paragraph(disclaimer())) return message
def show_keywords_need_review_message(sender, message=None): """Show a message keywords are not adequate to run an analysis. .. versionadded: 4.0 :param message: Additional message to display. :type message: str .. note:: The print button will be disabled if this method is called. """ LOGGER.debug('Showing incorrect keywords for v4 message') message = generate_input_error_message( tr('Layer Keywords Outdated:'), m.Paragraph( tr('Please update the keywords for your layers and then ' 'try to run the analysis again. Use the keyword wizard '), m.Image( 'file:///%s/img/icons/' 'show-keyword-wizard.svg' % resources_path(), **SMALL_ICON_STYLE), tr(' icon in the toolbar to update your layer\'s keywords.'), message)) send_static_message(sender, message)
def show_keyword_version_message(sender, keyword_version, inasafe_version): """Show a message indicating that the keywords version is mismatch .. versionadded: 3.2 :param sender: Sender of the message signal. Default to Any object. :type sender: object :param keyword_version: The version of the layer's keywords :type keyword_version: str :param inasafe_version: The version of the InaSAFE :type inasafe_version: str .. note:: The print button will be disabled if this method is called. """ LOGGER.debug('Showing Mismatch Version Message') message = generate_input_error_message( tr('Layer Keyword\'s Version Mismatch:'), m.Paragraph( tr( 'Your layer\'s keyword\'s version ({layer_version}) does not ' 'match with your InaSAFE version ({inasafe_version}). If you ' 'wish to use it as an exposure, hazard, or aggregation layer ' 'in an analysis, please use the keyword wizard to update the ' 'keywords. You can open the wizard by clicking on ' 'the ').format( layer_version=keyword_version, inasafe_version=inasafe_version), m.Image( 'file:///%s/img/icons/' 'show-keyword-wizard.svg' % resources_path(), **SMALL_ICON_STYLE), tr( ' icon in the toolbar.')) ) send_static_message(sender, message)
def content(): """Helper method that returns just the content. This method was added so that the text could be reused in the dock_help module. .. versionadded:: 4.1.0 :returns: A message object without brand element. :rtype: safe.messaging.message.Message """ message = m.Message() message.add( m.Paragraph( tr('This section of the help documentation is intended for advanced ' 'users who want to modify the internals of InaSAFE. It assumes that ' 'you have basic coding skills. All examples are in python unless ' 'otherwise stated.'))) message.add(m.Heading(tr('Defining a new hazard type'), **SUBSECTION_STYLE)) message.add(m.Heading(tr('Background'), **BLUE_CHAPTER_STYLE)) paragraph = m.Paragraph( tr('In the previous versions of InaSAFE, we spent a lot of effort ' 'building one impact function per hazard/exposure combination (and ' 'sometimes multiple impact functions per combination). In our new ' 'architecture, we try to deal with everything in the same way - by ' 'following a standardized process of converting the hazard dataset ' 'into a classified polygon layer and then calculating the impacted ' 'and affected areas using a standard work-flow. A simplified version ' 'of this work-flow is described in illustration 1.')) message.add(paragraph) paragraph = m.Paragraph( tr('Because of this change, you will no longer see an impact function ' 'selector in the dock widget and there are no longer any \'impact ' 'function options\' as we had in previous versions of InaSAFE. In ' 'the new system, almost all configuration is managed through ' 'metadata (created using the keywords wizard).')) message.add(paragraph) paragraph = m.Paragraph( tr('Also, in all versions prior to Version 4.0, we made heavy use of ' 'interpolation in order to determine whether buildings or other ' 'exposure layers are impacted. While this is a commonly used ' 'technique in GIS, it often leads to non - intuitive looking ' 'reports. Under our new architecture, we always use geometric ' 'overlay operations to make a determination whether an exposure ' 'feature is affected or not. The implication of this is that we ' 'produce intuitive and easily verifiable impact layers. You can ' 'see an example in Illustration 2.')) message.add(paragraph) paragraph = m.Paragraph( tr('Stepping away from the two previously mentioned paradigms allows ' 'us to simply add new hazard types to the metadata driven impact ' 'function by adding new metadata types to the InaSAFE sources. ' 'In the next chapter we show you how this was achieved and how ' 'it can be repeated for further hazards using the example of ' 'tropical cyclones.')) message.add(paragraph) message.add(m.Heading(tr('Adding a new hazard'), **BLUE_CHAPTER_STYLE)) link = m.Link('https://github.com/inasafe/inasafe/pull/3539/files', tr('Pull Request #3539')) paragraph = m.Paragraph( tr('The whole work needed can be looked at in '), link, tr('. Please bear in mind that the paths of the files are now ' 'safe/definitions/xxx.py and not safe/definitionsv4/xxx.py since ' 'v4 is the default codebase. In the next sections we will show ' 'each file that needs to be extended in order to add a new hazard ' 'type.')) message.add(paragraph) # Setting up units message.add( m.Heading(tr('safe/definitions/units.py'), **BLUE_CHAPTER_STYLE)) paragraph = m.Paragraph( tr('If you are adding an hazard that uses units that are not yet known ' 'to InaSAFE, you need to define them in units.py')) message.add(paragraph) paragraph = m.PreformattedText( _get_definition_from_module(units, 'unit_kilometres_per_hour')) message.add(paragraph) # Setting up style message.add(m.Heading('safe/definitions/colors.py', **BLUE_CHAPTER_STYLE)) paragraph = m.Paragraph( 'If you are adding an hazard that has more classes than any other ' 'hazards you’ll need to add additional colors for the additional ' 'classes in colors.py. You might also define other colors if you ' 'don\'t want to use the standard colors. For the sake of homogeneous ' 'map reports, this addition should not be taken lightly.') message.add(paragraph) # Don't translate this paragraph = m.PreformattedText('very_dark_red = Qcolor(\'#710017\')') message.add(paragraph) # Setting up hazard classification message.add( m.Heading('safe/definitions/hazard_classifications.py', **BLUE_CHAPTER_STYLE)) paragraph = m.Paragraph( tr('Add the classifications you want to make available for your new ' 'hazard type. You can add as many classes as you want in the ' 'classes list.')) message.add(paragraph) paragraph = m.Paragraph( tr('Also, a classification can support multiple units so you don\'t ' 'have to define different classifications just to have the same ' 'classification in two or more different units. These are defined ' 'in the multiple_units attribute of the classification.')) message.add(paragraph) paragraph = m.PreformattedText( _get_definition_from_module(hazard_classifications, 'cyclone_au_bom_hazard_classes')) message.add(paragraph) # Setting up wizard questions message.add( m.Heading('safe/gui/tools/wizard/wizard_strings.py', **BLUE_CHAPTER_STYLE)) paragraph = m.Paragraph(tr('Define the questions for the wizard:')) message.add(paragraph) # don not translate message.add( m.PreformattedText( 'cyclone_kilometres_per_hour_question = tr(\'wind speed in km/h\')' )) message.add( m.PreformattedText( 'cyclone_miles_per_hour_question = tr(\'wind speed in mph\')')) message.add( m.PreformattedText( 'cyclone_knots_question = tr(\'wind speed in kn\')')) # Setting up message.add(m.Heading('safe/definitions/hazard.py', **BLUE_CHAPTER_STYLE)) paragraph = m.Paragraph( tr('Finally define new hazard and add it to the hazard_all list:')) message.add(paragraph) paragraph = m.PreformattedText( _get_definition_from_module(hazard, 'hazard_cyclone')) message.add(paragraph) paragraph = m.Paragraph( tr('Finally define new hazard and add it to the hazard_all list:')) message.add(paragraph) paragraph = m.PreformattedText( _get_definition_from_module(hazard, 'hazard_all')) message.add(paragraph) return message
def run(self): """Run any post processors requested by the impact function. """ try: requested_postprocessors = self.function_parameters[ 'postprocessors'] postprocessors = get_postprocessors(requested_postprocessors) except (TypeError, KeyError): # TypeError is for when function_parameters is none # KeyError is for when ['postprocessors'] is unavailable postprocessors = {} feature_names_attribute = self.aggregator.attributes[ self.aggregator.get_default_keyword('AGGR_ATTR_KEY')] if feature_names_attribute is None: self.attribute_title = self.tr('Aggregation unit') else: self.attribute_title = feature_names_attribute name_filed_index = self.aggregator.layer.fieldNameIndex( self.attribute_title) sum_field_index = self.aggregator.layer.fieldNameIndex( self._sum_field_name()) user_defined_female_ratio = False female_ratio_field_index = None female_ratio = None user_defined_age_ratios = False youth_ratio_field_index = None youth_ratio = None adult_ratio_field_index = None adult_ratio = None elderly_ratio_field_index = None elderly_ratio = None if 'Gender' in postprocessors: # look if we need to look for a variable female ratio in a layer try: female_ratio_field = self.aggregator.attributes[ self.aggregator.get_default_keyword( 'FEMALE_RATIO_ATTR_KEY')] female_ratio_field_index = \ self.aggregator.layer.fieldNameIndex(female_ratio_field) # something went wrong finding the female ratio field, # use defaults from below except block if female_ratio_field_index == -1: raise KeyError user_defined_female_ratio = True except KeyError: try: female_ratio = self.keyword_io.read_keywords( self.aggregator.layer, self.aggregator.get_default_keyword( 'FEMALE_RATIO_KEY')) except KeywordNotFoundError: female_ratio = \ self.aggregator.get_default_keyword('FEMALE_RATIO') if 'Age' in postprocessors: # look if we need to look for a variable age ratio in a layer try: youth_ratio_field = self.aggregator.attributes[ self.aggregator.get_default_keyword( 'YOUTH_RATIO_ATTR_KEY')] youth_ratio_field_index = \ self.aggregator.layer.fieldNameIndex(youth_ratio_field) adult_ratio_field = self.aggregator.attributes[ self.aggregator.get_default_keyword( 'ADULT_RATIO_ATTR_KEY')] adult_ratio_field_index = \ self.aggregator.layer.fieldNameIndex(adult_ratio_field) elderly_ratio_field = self.aggregator.attributes[ self.aggregator.get_default_keyword( 'ELDERLY_RATIO_ATTR_KEY')] elderly_ratio_field_index = \ self.aggregator.layer.fieldNameIndex(elderly_ratio_field) # something went wrong finding the youth ratio field, # use defaults from below except block if (youth_ratio_field_index == -1 or adult_ratio_field_index == -1 or elderly_ratio_field_index == -1): raise KeyError user_defined_age_ratios = True except KeyError: try: youth_ratio = self.keyword_io.read_keywords( self.aggregator.layer, self.aggregator.get_default_keyword('YOUTH_RATIO_KEY')) adult_ratio = self.keyword_io.read_keywords( self.aggregator.layer, self.aggregator.get_default_keyword('ADULT_RATIO_KEY')) elderly_ratio = self.keyword_io.read_keywords( self.aggregator.layer, self.aggregator.get_default_keyword( 'ELDERLY_RATIO_KEY')) except KeywordNotFoundError: youth_ratio = \ self.aggregator.get_default_keyword('YOUTH_RATIO') adult_ratio = \ self.aggregator.get_default_keyword('ADULT_RATIO') elderly_ratio = \ self.aggregator.get_default_keyword('ELDERLY_RATIO') # iterate zone features request = QgsFeatureRequest() request.setFlags(QgsFeatureRequest.NoGeometry) provider = self.aggregator.layer.dataProvider() # start data retrieval: fetch no geometry and all attributes for each # feature polygon_index = 0 for feature in provider.getFeatures(request): # if a feature has no field called if name_filed_index == -1: zone_name = str(feature.id()) else: zone_name = feature[name_filed_index] if isinstance(zone_name, QPyNullVariant): # proper format for i186 zone_name = tr('Unnamed Area %(feature_id)s') % { 'feature_id': str(feature.id()) } # create dictionary of attributes to pass to postprocessor general_params = { 'target_field': self.aggregator.target_field, 'function_params': self.function_parameters } impact_total = feature[sum_field_index] general_params['impact_total'] = impact_total try: general_params['impact_attrs'] = ( self.aggregator.impact_layer_attributes[polygon_index]) except IndexError: # rasters and attributeless vectors have no attributes general_params['impact_attrs'] = None for key, value in postprocessors.iteritems(): parameters = general_params user_parameters = self.function_parameters['postprocessors'][ key] user_parameters = dict([(user_parameter.name, user_parameter.value) for user_parameter in user_parameters]) try: # user parameters override default parameters parameters.update(user_parameters) except KeyError: pass if key == 'Gender': if user_defined_female_ratio: female_ratio = feature[female_ratio_field_index] if female_ratio is None: female_ratio = self.aggregator.defaults[ 'FEMALE_RATIO'] LOGGER.warning('Data Driven Female ratio ' 'incomplete, using defaults for' ' aggregation unit' ' %s' % feature.id) parameters['female_ratio'] = female_ratio if key == 'Age': if user_defined_age_ratios: youth_ratio = feature[youth_ratio_field_index] adult_ratio = feature[adult_ratio_field_index] elderly_ratio = feature[elderly_ratio_field_index] if (youth_ratio is None or adult_ratio is None or elderly_ratio is None): LOGGER.debug( '--- only default age ratios used ---') youth_ratio = self.aggregator.defaults[ 'YOUTH_RATIO'] adult_ratio = self.aggregator.defaults[ 'ADULT_RATIO'] elderly_ratio = self.aggregator.defaults[ 'ELDERLY_RATIO'] LOGGER.warning('Data Driven Age ratios ' 'incomplete, using defaults for' ' aggregation unit' ' %s' % feature.id) parameters['youth_ratio'] = youth_ratio parameters['adult_ratio'] = adult_ratio parameters['elderly_ratio'] = elderly_ratio if key == 'BuildingType' or key == 'RoadType': if key == 'BuildingType': key_attribute = self.keyword_io.read_keywords( self.aggregator.exposure_layer, 'structure_class_field') elif key == 'RoadType': key_attribute = self.keyword_io.read_keywords( self.aggregator.exposure_layer, 'road_class_field') else: try: key_attribute = self.keyword_io.read_keywords( self.aggregator.exposure_layer, 'key_attribute') except KeywordNotFoundError: # use 'type' as default key_attribute = 'type' parameters['key_attribute'] = key_attribute LOGGER.debug('key_attribute: %s', key_attribute) value_map = self.keyword_io.read_keywords( self.aggregator.exposure_layer, 'value_mapping') parameters['value_mapping'] = value_map try: value.setup(parameters) value.process() results = value.results() value.clear() if key not in self.output: self.output[key] = [] self.output[key].append([zone_name, results]) except PostProcessorError as e: message = m.Message( m.Heading(self.tr('%s postprocessor problem' % key), **styles.DETAILS_STYLE), m.Paragraph(self.tr(str(e)))) self.error_message = message # increment the index polygon_index += 1 self.remove_empty_columns() self.remove_empty_lines()
def _generate_tables(self, aoi_mode=True): """Parses the postprocessing output as one table per postprocessor. TODO: This should rather return json and then have a helper method to make html from the JSON. :param aoi_mode: adds a Total in aggregation areas row to the calculated table :type aoi_mode: bool :returns: The html. :rtype: str """ message = m.Message() for processor, results_list in self.output.iteritems(): self.current_output_postprocessor = processor # results_list is for example: # [ # (PyQt4.QtCore.QString(u'Entire area'), OrderedDict([ # (u'Total', {'value': 977536, 'metadata': {}}), # (u'Female population', {'value': 508319, 'metadata': {}}), # (u'Weekly hygiene packs', {'value': 403453, 'metadata': { # 'description': 'Females hygiene packs for weekly use'}}) # ])) # ] # sorting using the first indicator of a postprocessor sorted_results = sorted(results_list, key=self._sort_no_data, reverse=True) # init table has_no_data = False table = m.Table(style_class='table table-condensed table-striped') name = get_postprocessor_human_name(processor).lower() translated_name = tr(name) if name == 'building type': table.caption = tr('Closed buildings') elif name == 'road type': table.caption = tr('Closed roads') elif name == 'people': table.caption = tr('Affected people') # Dirty hack to make "evacuated" come out in the report. # Currently only MinimumNeeds that calculate from evacuation # percentage. if processor == 'MinimumNeeds': if 'evacuation_percentage' in self.function_parameters.keys(): table.caption = tr( 'Detailed %s report ' '(for people needing evacuation)') % translated_name else: table.caption = tr('Detailed %s report ' '(affected people)') % translated_name if processor in ['Gender', 'Age']: table.caption = tr('Detailed %s report ' '(affected people)') % translated_name empty_table = not sorted_results[0][1] if empty_table: # Due to an error? The table is empty. message.add(table) message.add( m.EmphasizedText( tr('Could not compute the %s report.') % translated_name)) continue header = m.Row() header.add(str(self.attribute_title).capitalize()) for calculation_name in sorted_results[0][1]: header.add(self.tr(calculation_name)) table.add(header) # used to calculate the totals row as per issue #690 postprocessor_totals = OrderedDict() null_index = 0 # counting how many null value in the data for zone_name, calc in sorted_results: if isinstance(zone_name, QPyNullVariant): # I have made sure that the zone_name won't be Null in # run method. But just in case there is something wrong. zone_name = tr('Unnamed Area %s' % null_index) null_index += 1 if name == 'road type': # We add the unit 'meter' as we are counting roads. # proper format for i186 zone_name = tr('%(zone_name)s (m)') % { 'zone_name': tr(zone_name) } row = m.Row(zone_name) for indicator, calculation_data in calc.iteritems(): value = calculation_data['value'] value = str(unhumanize_number(value)) if value == self.aggregator.get_default_keyword('NO_DATA'): has_no_data = True try: postprocessor_totals[indicator] += 0 except KeyError: postprocessor_totals[indicator] = 0 else: value = int(value) try: postprocessor_totals[indicator] += value except KeyError: postprocessor_totals[indicator] = value row.add(format_int(value)) table.add(row) if not aoi_mode: # add the totals row row = m.Row(self.tr('Total in aggregation areas')) for _, total in postprocessor_totals.iteritems(): row.add(format_int(total)) table.add(row) # add table to message message.add(table) if has_no_data: message.add( m.EmphasizedText( self. tr('"%s" values mean that there where some problems while ' 'calculating them. This did not affect the other ' 'values.') % (self.aggregator.get_default_keyword('NO_DATA')))) caption = m.EmphasizedText( self.tr( 'Columns and rows containing only 0 or "%s" values are ' 'excluded from the tables.' % self.aggregator.get_default_keyword('NO_DATA'))) message.add(m.Paragraph(caption, style_class='caption')) return message
def content(): """Helper method that returns just the content. This method was added so that the text could be reused in the dock_help module. .. versionadded:: 3.2.2 :returns: A message object without brand element. :rtype: safe.messaging.message.Message """ message = m.Message() message.add( m.Paragraph( tr('The InaSAFE options dialog is used to control various aspects of ' 'the InaSAFE analysis and reporting environment. Here are brief ' 'descriptions of all the options available, grouped by the tab ' 'page on which they occur.'))) header = m.Heading(tr('Organisation Profile tab'), **INFO_STYLE) message.add(header) paragraph = m.Paragraph(m.Image( 'file:///%s/img/screenshots/' 'inasafe-options-organisation-screenshot.png' % resources_path()), style_class='text-center') message.add(paragraph) message.add( m.Paragraph( tr('The Organisation Profile tab provides several general settings:' ))) bullets = m.BulletedList() bullets.add( m.Text( m.ImportantText(tr('Organisation')), tr(' - Use this option to specify the name of your organisation.')) ) bullets.add( m.Text( m.ImportantText(tr('Contact email')), tr(' - Use this option to specify the contact person\'s email ' 'address to use in the generated metadata document.'))) bullets.add( m.Text( m.ImportantText(tr('Website')), tr(' - Use this option to set the website address to be used in ' 'the generated metadata document.'))) bullets.add( m.Text( m.ImportantText(tr('Use custom organisation logo')), tr(' - By default, InaSAFE will add the supporters logo to each ' 'map template. The supporters logo is also used at tbe bottom ' 'of the dock panel if the \'show organisation logo in dock\' ' 'option is enabled. You can use this option to replace the ' 'organisation logo with that of your own organisation. The logo ' 'will be rescaled automatically to fill the space provided.'))) bullets.add( m.Text( m.ImportantText(tr('Currency')), tr(' - InaSAFE will use the selected currency for the analysis.'))) bullets.add( m.Text( m.ImportantText(tr('Analysis license')), tr(' - Use this to set the usage and redistribution license for the ' 'generated impact layer.'))) message.add(bullets) header = m.Heading(tr('Population Parameters tab'), **INFO_STYLE) message.add(header) paragraph = m.Paragraph(m.Image( 'file:///%s/img/screenshots/' 'inasafe-options-population-screenshot.png' % resources_path()), style_class='text-center') message.add(paragraph) message.add( m.Paragraph( tr('In this tab you can define some parameters that will be used by ' 'InaSAFE in the analysis of exposed populations. You have the option ' 'to change the parameters for whether the exposed population is ' 'considered to be affected by each hazard type and class, and the ' 'displacement rate that will be used for affected people.'))) bullets = m.BulletedList() bullets.add( m.Text( m.ImportantText(tr('Affected')), tr(' - When this option is checked, people exposed to the hazard ' 'class will be included in the count of affected people.'))) bullets.add( m.Text( m.ImportantText(tr('Displacement Rate')), tr(' - The displacement rate is used to estimate the number of ' 'people displaced for each hazard class. People must be affected ' 'before they can be displaced. '))) message.add(bullets) message.add( m.Paragraph( tr('Please refer to the InaSAFE manual for concept definitions and ' 'more information on the source of the hazard classifications and ' 'default settings. We really encourage you to consider these ' 'parameters carefully and to choose appropriate values for your ' 'local situation based on past events and expert knowledge.'))) header = m.Heading(tr('GIS Environment tab'), **INFO_STYLE) message.add(header) paragraph = m.Paragraph(m.Image( 'file:///%s/img/screenshots/' 'inasafe-options-environment-screenshot.png' % resources_path()), style_class='text-center') message.add(paragraph) message.add( m.Paragraph( tr('The GIS Environment tab provides several general settings:'))) bullets = m.BulletedList() bullets.add( m.Text( m.ImportantText( tr('Always show welcome message when opening QGIS with InaSAFE' )), tr(' - When this option is enabled, the welcome message will be ' 'enabled when opening QGIS with InaSAFE. By default the Welcome ' 'message will be displayed.'))) bullets.add( m.Text( m.ImportantText(tr('Show organisation logo in InaSAFE dock')), tr(' - When this option is enabled, a logo will be displayed at the ' 'bottom of the InaSAFE dock widget. By default the logo used ' 'is the InaSAFE supporters logo, but you can alter this by ' 'setting the \'Use custom organisation logo\' option in ' 'the template options tab (see below).'))) bullets.add( m.Text( m.ImportantText( tr('Show only visible layers in the InaSAFE dock')), tr(' - When this option is enabled layers that are not visible ' 'in the QGIS layers panel will not be shown in the hazard, ' 'exposure and aggregation combo boxes in the dock area.'))) bullets.add( m.Text( m.ImportantText(tr('Set QGIS layer name from title in keywords')), tr(' - If this option is enabled, the InaSAFE keywords title ' 'attribute will be used for the layer name in the QGIS Layers list ' 'when adding a layer.'))) bullets.add( m.Text( m.ImportantText( tr('Zoom to impact layer on scenario estimate completion')), tr(' - When this option is enabled, the map view extents will ' 'be updated to match the extents of the generated impact layer ' 'once the analysis completes.'))) bullets.add( m.Text( m.ImportantText( tr('Hide exposure on scenario estimate completion')), tr(' - Use this option if you prefer to not show the exposure ' 'layer as an underlay behind the generated impact layer.'))) bullets.add( m.Text( m.ImportantText(tr('Show only impact layer on report map')), tr('When this option is enabled, the map report created after an ' 'analysis completes will not show any other layers in your ' 'current project except for the impact layer. '))) bullets.add( m.Text( m.ImportantText( tr('Print atlas report on atlas driven template with the ' 'aggregation layer')), tr('When this option is enabled, InaSAFE will generate an atlas ' 'report based on aggregation area if the template has atlas ' 'generation flag enabled.'))) bullets.add( m.Text( m.ImportantText( tr('Use selected features only with the aggregation layer')), tr('If enabled, running an analysis with some features of the ' 'aggregation layer selected will constrain the analysis to only ' 'those selected aggregation areas, all others will be ignored.') )) bullets.add( m.Text( m.ImportantText(tr('Location for results')), tr(' - By default, InaSAFE will write impact layer and intermediate ' 'outputs to the system temporary directory. On some operating ' 'systems, these temporary files will be deleted on each reboot. ' 'If you wish to, you can specify an alternative directory ' 'to use for storing these temporary files.'))) message.add(bullets) header = m.Heading(tr('Earthquake tab'), **INFO_STYLE) message.add(header) paragraph = m.Paragraph(m.Image( 'file:///%s/img/screenshots/' 'inasafe-options-earthquake-screenshot.png' % resources_path()), style_class='text-center') message.add(paragraph) paragraph = m.Paragraph( tr('In this tab you can select which earthquake fatality model to use ' 'when estimating earthquake impact on population. This option is ' 'global - it will affect all subsequent earthquake analyses carried ' 'out in InaSAFE.')) message.add(paragraph) paragraph = m.Paragraph( tr('When selecting an earthquake analysis model, its details will be ' 'shown below in the text box area.')) message.add(paragraph) header = m.Heading(tr('Template Options tab'), **INFO_STYLE) message.add(header) paragraph = m.Paragraph(m.Image('file:///%s/img/screenshots/' 'inasafe-options-template-screenshot.png' % resources_path()), style_class='text-center') message.add(paragraph) message.add( m.Paragraph( tr('This tab has options relating to the generation of map composer ' 'templates and how reports will be printed:' '.'))) bullets = m.BulletedList() bullets.add( m.Text( m.ImportantText(tr('Use custom north arrow image')), tr(' - InaSAFE provides a basic north arrow which is placed on ' 'generated map compositions and rendered PDF reports. You can ' 'replace this north arrow with one of your own choosing using ' 'this option.'))) bullets.add( m.Text( m.ImportantText(tr('Use custom disclaimer text')), tr(' - By default, InaSAFE will display a disclaimer on reports ' 'advising readers of the report to exercise caution when ' 'interpreting the outputs presented. You can override this ' 'text using this option, though we do advise that you include ' 'a similar statement of caution in your overridden text.'))) message.add(bullets) header = m.Heading(tr('Demographic Defaults tab'), **INFO_STYLE) message.add(header) paragraph = m.Paragraph(m.Image( 'file:///%s/img/screenshots/' 'inasafe-options-demographic-screenshot.png' % resources_path()), style_class='text-center') message.add(paragraph) paragraph = m.Paragraph( tr('In this tab you will find options for setting the default ratios ' 'for demographic groups. There is more detailed help on demographic ' 'groups within the main help page for InaSAFE in the Field Mapping ' 'Tool section. Essentially default ratios for demographic groups ' 'determine what proportion of the population are within each ' 'population group (e.g. infants versus children etc.). The options ' 'defined in this tab are used in cases where you choose to use the ' 'global default ratios while configuring the keywords for an ' 'aggregation layer as shown below.')) message.add(paragraph) paragraph = m.Paragraph( tr('Note that the contents of this tab may changed depending on what ' 'groups have been defined for demographic breakdowns.')) message.add(paragraph) paragraph = m.Paragraph(m.Image( 'file:///%s/img/screenshots/' 'field-mapping-tool-default-ratios-screenshot.png' % resources_path()), style_class='text-center') message.add(paragraph) header = m.Heading(tr('Advanced tab'), **INFO_STYLE) message.add(header) paragraph = m.Paragraph(m.Image('file:///%s/img/screenshots/' 'inasafe-options-advanced-screenshot.png' % resources_path()), style_class='text-center') message.add(paragraph) message.add( m.Paragraph( tr('This tab contains options intended for advanced users only: ')) ) bullets = m.BulletedList() bullets.add( m.Text( m.ImportantText(tr('Keyword cache for remote databases')), tr(' - When InaSAFE is used with remote layers (for example a ' 'database layer or a WFS layer), it is not possible to store the ' 'keywords for the layer with the layer itself. To accommodate for ' 'these types of layers, InaSAFE writes the keywords to a small ' 'file based database (using sqlite) and then retrieves them based ' 'on unique connection details used for that layer. You can ' 'specify a custom path to be used for storing the keywords ' 'database using this option.'))) bullets.add( m.Text( m.ImportantText( tr('Help to improve InaSAFE by submitting errors to a ' 'remote server')), tr(' - With this option enabled, InaSAFE will post any errors that ' 'occur to an online server for analysis by our development team. ' 'This option is disabled by default as some may consider some of ' 'the data submitted (IP Address, logged in user name) to be ' 'sensitive.'))) bullets.add( m.Text( m.ImportantText(tr('Enable developer mode')), tr(' - When this option is enabled, right clicking on the webview ' 'widget in the dock will allow you to debug the generated HTML. ' 'In addition, if the metadata.txt for the running InaSAFE is ' 'set to \'alpha\', an additional icon will be added to the ' 'toolbar to add test layers to the QGIS project.'))) bullets.add( m.Text( m.ImportantText(tr('Generate reports')), tr(' - When this option is enabled, InaSAFE will generate reports. ' ))) bullets.add( m.Text( m.ImportantText(tr('Show memory profile')), tr(' - When this option is enabled, InaSAFE will display the memory ' 'profile when it runs. '))) message.add(bullets) return message
def run(self): """Run any post processors requested by the impact function. """ try: requested_postprocessors = self.function_parameters[ 'postprocessors'] postprocessors = get_postprocessors( requested_postprocessors, self.aggregator.aoi_mode) except (TypeError, KeyError): # TypeError is for when function_parameters is none # KeyError is for when ['postprocessors'] is unavailable postprocessors = {} LOGGER.debug('Running this postprocessors: ' + str(postprocessors)) feature_names_attribute = self.aggregator.attributes[ self.aggregator.get_default_keyword('AGGR_ATTR_KEY')] if feature_names_attribute is None: self.attribute_title = self.tr('Aggregation unit') else: self.attribute_title = feature_names_attribute name_filed_index = self.aggregator.layer.fieldNameIndex( self.attribute_title) sum_field_index = self.aggregator.layer.fieldNameIndex( self._sum_field_name()) user_defined_female_ratio = False female_ratio_field_index = None female_ratio = None user_defined_age_ratios = False youth_ratio_field_index = None youth_ratio = None adult_ratio_field_index = None adult_ratio = None elderly_ratio_field_index = None elderly_ratio = None if 'Gender' in postprocessors: # look if we need to look for a variable female ratio in a layer try: female_ratio_field = self.aggregator.attributes[ self.aggregator.get_default_keyword( 'FEMALE_RATIO_ATTR_KEY')] female_ratio_field_index = \ self.aggregator.layer.fieldNameIndex(female_ratio_field) # something went wrong finding the female ratio field, # use defaults from below except block if female_ratio_field_index == -1: raise KeyError user_defined_female_ratio = True except KeyError: try: female_ratio = self.keyword_io.read_keywords( self.aggregator.layer, self.aggregator.get_default_keyword( 'FEMALE_RATIO_KEY')) except KeywordNotFoundError: female_ratio = \ self.aggregator.get_default_keyword('FEMALE_RATIO') if 'Age' in postprocessors: # look if we need to look for a variable age ratio in a layer try: youth_ratio_field = self.aggregator.attributes[ self.aggregator.get_default_keyword( 'YOUTH_RATIO_ATTR_KEY')] youth_ratio_field_index = \ self.aggregator.layer.fieldNameIndex(youth_ratio_field) adult_ratio_field = self.aggregator.attributes[ self.aggregator.get_default_keyword( 'ADULT_RATIO_ATTR_KEY')] adult_ratio_field_index = \ self.aggregator.layer.fieldNameIndex(adult_ratio_field) elderly_ratio_field = self.aggregator.attributes[ self.aggregator.get_default_keyword( 'ELDERLY_RATIO_ATTR_KEY')] elderly_ratio_field_index = \ self.aggregator.layer.fieldNameIndex(elderly_ratio_field) # something went wrong finding the youth ratio field, # use defaults from below except block if (youth_ratio_field_index == -1 or adult_ratio_field_index == -1 or elderly_ratio_field_index == -1): raise KeyError user_defined_age_ratios = True except KeyError: try: youth_ratio = self.keyword_io.read_keywords( self.aggregator.layer, self.aggregator.get_default_keyword( 'YOUTH_RATIO_KEY')) adult_ratio = self.keyword_io.read_keywords( self.aggregator.layer, self.aggregator.get_default_keyword( 'ADULT_RATIO_KEY')) elderly_ratio = self.keyword_io.read_keywords( self.aggregator.layer, self.aggregator.get_default_keyword( 'ELDERLY_RATIO_KEY')) except KeywordNotFoundError: youth_ratio = \ self.aggregator.get_default_keyword('YOUTH_RATIO') adult_ratio = \ self.aggregator.get_default_keyword('ADULT_RATIO') elderly_ratio = \ self.aggregator.get_default_keyword('ELDERLY_RATIO') if 'BuildingType' or 'RoadType' in postprocessors: try: key_attribute = self.keyword_io.read_keywords( self.aggregator.exposure_layer, 'key_attribute') except KeywordNotFoundError: # use 'type' as default key_attribute = 'type' # iterate zone features request = QgsFeatureRequest() request.setFlags(QgsFeatureRequest.NoGeometry) provider = self.aggregator.layer.dataProvider() # start data retrieval: fetch no geometry and all attributes for each # feature polygon_index = 0 for feature in provider.getFeatures(request): # if a feature has no field called if name_filed_index == -1: zone_name = str(feature.id()) else: zone_name = feature[name_filed_index] # create dictionary of attributes to pass to postprocessor general_params = { 'target_field': self.aggregator.target_field, 'function_params': self.function_parameters} if self.aggregator.statistics_type == 'class_count': general_params['impact_classes'] = ( self.aggregator.statistics_classes) elif self.aggregator.statistics_type == 'sum': impact_total = feature[sum_field_index] general_params['impact_total'] = impact_total try: general_params['impact_attrs'] = ( self.aggregator.impact_layer_attributes[polygon_index]) except IndexError: # rasters and attributeless vectors have no attributes general_params['impact_attrs'] = None for key, value in postprocessors.iteritems(): parameters = general_params try: # look if params are available for this postprocessor parameters.update( self.function_parameters[ 'postprocessors'][key]['params']) except KeyError: pass if key == 'Gender': if user_defined_female_ratio: female_ratio = feature[female_ratio_field_index] if female_ratio is None: female_ratio = self.aggregator.defaults[ 'FEMALE_RATIO'] LOGGER.warning('Data Driven Female ratio ' 'incomplete, using defaults for' ' aggregation unit' ' %s' % feature.id) parameters['female_ratio'] = female_ratio if key == 'Age': if user_defined_age_ratios: youth_ratio = feature[youth_ratio_field_index] adult_ratio = feature[adult_ratio_field_index] elderly_ratio = feature[elderly_ratio_field_index] if (youth_ratio is None or adult_ratio is None or elderly_ratio is None): youth_ratio = self.aggregator.defaults[ 'YOUTH_RATIO'] adult_ratio = self.aggregator.defaults[ 'ADULT_RATIO'] elderly_ratio = self.aggregator.defaults[ 'ELDERLY_RATIO'] LOGGER.warning('Data Driven Age ratios ' 'incomplete, using defaults for' ' aggregation unit' ' %s' % feature.id) parameters['youth_ratio'] = youth_ratio parameters['adult_ratio'] = adult_ratio parameters['elderly_ratio'] = elderly_ratio if key == 'BuildingType' or key == 'RoadType': # TODO: Fix this might be referenced before assignment parameters['key_attribute'] = key_attribute try: value.setup(parameters) value.process() results = value.results() value.clear() # LOGGER.debug(results) # this can raise a KeyError self.output[key].append( (zone_name, results)) except PostProcessorError as e: message = m.Message( m.Heading(self.tr('%s postprocessor problem' % key), **styles.DETAILS_STYLE), m.Paragraph(self.tr(str(e)))) self.error_message = message except KeyError: self.output[key] = [] # TODO: Fix this might be referenced before assignment self.output[key].append((zone_name, results)) # increment the index polygon_index += 1