Пример #1
0
    def emit_pre_run_message(self):
        """Inform the user about parameters before starting the processing."""
        title = tr('Processing started')
        details = tr(
            'Please wait - processing may take a while depending on your '
            'hardware configuration and the analysis extents and data.')
        # trap for issue 706
        try:
            exposure_name = self.exposure.name
            hazard_name = self.hazard.name
            # aggregation layer could be set to AOI so no check for that
        except AttributeError:
            title = tr('No valid layers')
            details = tr(
                'Please ensure your hazard and exposure layers are set '
                'in the question area and then press run again.')
            message = m.Message(LOGO_ELEMENT,
                                m.Heading(title, **WARNING_STYLE),
                                m.Paragraph(details))
            raise NoValidLayerError(message)
        text = m.Text(
            tr('This analysis will calculate the impact of'),
            m.EmphasizedText(hazard_name),
            tr('on'),
            m.EmphasizedText(exposure_name),
        )
        if self.aggregation is not None:
            try:
                aggregation_name = self.aggregation.name
                # noinspection PyTypeChecker
                text.add(
                    m.Text(tr('and bullet list the results'),
                           m.ImportantText(tr('aggregated by')),
                           m.EmphasizedText(aggregation_name)))
            except AttributeError:
                pass
        text.add('.')
        message = m.Message(LOGO_ELEMENT,
                            m.Heading(title, **PROGRESS_UPDATE_STYLE),
                            m.Paragraph(details), m.Paragraph(text))
        try:
            # add which postprocessors will run when appropriated
            # noinspection PyTypeChecker
            post_processors_names = self.parameters['postprocessors']
            post_processors = get_postprocessors(post_processors_names)
            message.add(
                m.Paragraph(tr('The following postprocessors will be used:')))

            bullet_list = m.BulletedList()

            for name, post_processor in post_processors.iteritems():
                bullet_list.add('%s: %s' % (get_postprocessor_human_name(name),
                                            post_processor.description()))
            message.add(bullet_list)

        except (TypeError, KeyError):
            # TypeError is for when function_parameters is none
            # KeyError is for when ['postprocessors'] is unavailable
            pass
        send_static_message(self, message)
Пример #2
0
    def format_postprocessing(self):
        """Format postprocessing.

        :returns: The postprocessing.
        :rtype: safe.messaging.Message
        """
        # List of post processor that can't be sum up. Issue #3118
        no_total = ['Age', 'Gender', 'MinimumNeeds']

        if not self.postprocessing:
            return False
        message = m.Message()
        for postprocessor, 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'))
                if postprocessor not in no_total:
                    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(self.format_int(val),
                                           align='right'))
                        except ValueError:
                            # Catch no data value. Align left strings.
                            row.add(m.Cell(value, align='left'))
                    if postprocessor not in no_total:
                        row.add(
                            m.Cell(self.format_int(round(total)),
                                   align='right'))
                    table.add(row)

            message.add(table)

            for note in v['notes']:
                message.add(m.EmphasizedText(note))

        return message
Пример #3
0
def ready_message():
    """Helper to create a message indicating inasafe is ready.

    :returns Message: A localised message indicating we are ready to run.
    """
    title = m.Heading(tr('Ready'), **PROGRESS_UPDATE_STYLE)
    notes = m.Paragraph(
        tr('You can now proceed to run your analysis by clicking the '),
        m.EmphasizedText(tr('Run'), **KEYWORD_STYLE), tr('button.'))
    message = m.Message(LOGO_ELEMENT, title, notes)
    return message
Пример #4
0
    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
Пример #5
0
    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')
            table.caption = self.tr('Detailed %s report') % (tr(
                get_postprocessor_human_name(processor)).lower())

            # Dirty hack to make "evacuated" comes 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 = self.tr(
                        'Detailed %s report (for people needing '
                        'evacuation)') % (
                            tr(get_postprocessor_human_name(processor)).lower()
                        )
                else:
                    table.caption = self.tr(
                        'Detailed %s report (affected people)') % (
                            tr(get_postprocessor_human_name(processor)).lower()
                        )

            if processor in ['Gender', 'Age']:
                table.caption = self.tr(
                    'Detailed %s report (affected people)') % (
                        tr(get_postprocessor_human_name(processor)).lower())

            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()

            for zone_name, calc in sorted_results:
                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
                        value += ' *'
                        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'))))

        return message
Пример #6
0
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(tr(
        'This document describes the usage of the InaSAFE \'dock panel\''
        '- which is an interface for running risk scenarios within the QGIS '
        'environment. If you are a new user, you may also consider using the '
        '\'Impact Function Centric Wizard\' to run the analysis. You can '
        'launch the wizard by clicking on this icon in the toolbar:'),
        m.Image(
            'file:///%s/img/icons/'
            'show-wizard.svg' % resources_path(),
            **SMALL_ICON_STYLE),

    )
    message.add(paragraph)
    paragraph = m.Paragraph(tr(
        'You can drag and drop the dock panel to reposition it in the user '
        'interface. For example, dragging the panel towards the right margin '
        'of the QGIS application will dock it to the right side of the screen.'
    ))
    message.add(paragraph)

    message.add(m.Paragraph(tr(
        'There are three main areas to the dock panel:')))
    bullets = m.BulletedList()
    bullets.add(tr('the Questions area'))
    bullets.add(tr('the Results area'))
    bullets.add(tr('the Buttons area'))
    message.add(bullets)
    message.add(m.Paragraph(tr(
        'At any time you can obtain help in InaSAFE by clicking on the '
        'help buttons provided on each dock and dialog.')))

    header = m.Heading(tr('The questions area'), **INFO_STYLE)
    message.add(header)
    message.add(m.Paragraph(tr(
        'The intention of InaSAFE is to make it really simple and easy to '
        'perform your impact analysis. The question area provides a simple '
        'way for you to formulate what it is you want to find out? All '
        'questions are formulated in the form:'),
        m.EmphasizedText(tr(
            'In the event of a [hazard], how many [exposure] might be '
            'affected?'))))
    message.add(m.Paragraph(tr(
        'For example: "If there is a flood, how many buildings might be '
        'affected?"')))
    message.add(m.Paragraph(tr(
        'In order to answer such questions, the InaSAFE developers have '
        'built a number of Impact Functions that cover scenarios such as '
        'flood, tsunami, volcanic fall, earthquake and so on.')))
    message.add(m.Paragraph(tr(
        'The formulation of these questions if carried out by loading layers '
        'into QGIS that represent either hazard scenarios or exposure data.'
        'A hazard, for example, may be represented as, a raster layer in '
        'QGIS where each pixel in the raster represents the current flood '
        'depth following an inundation event. An exposure layer could be '
        'represented, for example, as vector polygon data representing '
        'building outlines, or a raster outline where each pixel represents '
        'the number of people thought to be resident in that cell.')))
    message.add(m.Paragraph(tr(
        'The impact function will combine these two input layers in a '
        'mathematical model in order to derive what the impacts of the '
        'hazard will be on the exposure infrastructure or people. By '
        'selecting a combination from the hazard and exposure combo boxes, '
        'an appropriate set of impact functions will be listed in the '
        'combo box. You may be wondering how the InaSAFE plugin determines '
        'whether a layer should be listed in the hazard or exposure combo '
        'boxes? The plugin relies on simple keyword metadata to be associated '
        'with each layer. You can define these keywords by selecting a layer '
        'and then clicking the InaSAFE Keywords Wizard icon on the toolbar: '),
        m.Image(
            'file:///%s/img/icons/'
            'show-keyword-wizard.svg' % resources_path(),
            **SMALL_ICON_STYLE),
        tr(
            'The wizard will guide you through the process of defining the '
            'keywords for that layer.')))
    message.add(m.Paragraph(tr(
        'Based on the combination of hazard and exposure layers that are '
        'selected, the Impact Function list (shown in the combo box under '
        '"Might" in the InaSAFE dock panel)  will be updated. Each impact '
        'function can only work with specific combinations of hazard and '
        'exposure types, so the options shown here will be limited '
        'accordingly. The chosen impact function can be configured (if '
        'applicable) by pressing the small ellipses (...) button next to '
        'the chosen impact function. This is explained in more detail below '
        'under the heading "Setting Analysis Parameters".')))
    message.add(m.Paragraph(tr(
        'Aggregation is the process whereby we group the results of the '
        'analysis by district so that you can see how many people, roads or '
        'buildings were affected in each area. This will help you to '
        'understand where the most critical needs are. Aggregation is '
        'optional in InaSAFE - if you do not use aggregation, the entire '
        'analysis area will be used for the data summaries. Typically '
        'aggregation layers in InaSAFE have as attributes the name of the '
        'district or reporting area. It is also possible to use extended '
        'attributes to indicate the ratio of men and women; youth, adults '
        'and elderly living in each area. Where these are provided and the '
        'exposure layer is population, InaSAFE will provide a demographic '
        'breakdown per aggregation area indicating how many men, women etc. '
        'were probably affected in that area.'
    )))

    header = m.Heading(tr('The results area'), **INFO_STYLE)
    message.add(header)

    message.add(m.Paragraph(tr(
        'After running an analysis, the question area is hidden to maximise '
        'the amount of space allocated to the results area. You can '
        're-open the question area at any time by pressing the "show question '
        'form" button.')))

    message.add(m.Paragraph(tr(
        'The Results area is used to display various useful feedback items to '
        'the user. Once an impact scenario has been run, a summary table will '
        'be shown.')))

    message.add(m.Paragraph(tr(
        'If you select an impact layer (i.e. a layer that was produced using '
        'an InaSAFE impact function), in the QGIS layers list, this summary '
        'will also be displayed in the results area. When you select a hazard '
        'or exposure layer in the QGIS layers list, the keywords for that '
        'layer will be shown in the Results area, making it easy to '
        'understand what metadata exists for that layer.')))

    message.add(m.Paragraph(tr(
        'The Results area is also used to display status information. For '
        'example, when a suitable combination of hazard, exposure and impact '
        'function are selected, the results area will be updated to indicate '
        'that you can proceed to run the impact scenario calculation. The Run '
        'Button will be activated.'
    )))

    message.add(m.Paragraph(tr(
        'Finally, the Results area is also used to display any error messages '
        'so that the user is informed as to what went wrong and why. You '
        'might want to scroll down a bit in the messaging window to view the '
        'message completely.'
    )))

    message.add(m.Paragraph(tr(
        'To have more space for the results available your Question is '
        'automatically hidden to make the results area as large as possible '
        'to display the results. If you want to have a look again what the '
        'question was that you formulated click on the Show question form '
        'button on top of the result area.'
    )))

    message.add(m.Paragraph(tr(
        'If you want to hide the question area again to have more space to '
        'display the results again, just make the Layer you just calculated '
        'with InaSAFE active again in the Layers list of QGIS.'
    )))

    header = m.Heading(tr('The Buttons Area'), **INFO_STYLE)
    message.add(header)

    message.add(m.Paragraph(tr(
        'The buttons area contains four buttons:')))
    bullets = m.BulletedList()
    bullets.add(m.Text(
        m.ImportantText(tr('Help')),
        tr(
            '- click on this if you need context help, such as the document '
            'you are reading right now!')))
    bullets.add(m.Text(
        m.ImportantText(tr('About')),
        tr(
            '- click on this to see short credits for the InaSAFE project.')))
    bullets.add(m.Text(
        m.ImportantText(tr('Help')),
        tr(
            'Print... - click on this if you wish to create a pdf of your '
            'impact scenarion project or just generate report and open it in '
            'composer for further tuning. An impact layer must be active '
            'before the Print button will be enabled.')))
    bullets.add(m.Text(
        m.ImportantText(tr('Run')),
        tr(
            '- Run - if the combination of options in the Questions area\'s '
            'combo boxes will allow you to run a scenario, this button is '
            'enabled.')))
    message.add(bullets)

    header = m.Heading(tr('Data conversions'), **INFO_STYLE)
    message.add(header)

    message.add(m.Paragraph(tr(
        'When running a scenario, the data being used needs to be processed '
        'into a state where it is acceptable for use by the impact function. '
        'In particular it should be noted that:')))

    bullets = m.BulletedList()
    bullets.add(tr(
        'Remote datasets will be copied locally before processing.'))
    bullets.add(m.Text(
        tr(
            'All datasets will be clipped to the intersection of the hazard '
            'layer, exposure layer and the current view extents unless '
            'you have specified a different clipping behaviour in the '
            'extents selector dialog.'),
        m.Image(
            'file:///%s/img/icons/'
            'set-extents-tool.svg' % resources_path(),
            **SMALL_ICON_STYLE)
    ))
    bullets.add(tr(
        'All clipped datasets will be converted (reprojected) to Geographic '
        '(EPSG:4326) coordinate reference system before analysis.'))
    message.add(bullets)

    header = m.Heading(tr('Analysis parameters'), **INFO_STYLE)
    message.add(header)
    # this adds the help content from the IF options dialog
    message.add(options())

    header = m.Heading(tr('Generating impact reports'), **INFO_STYLE)
    message.add(header)

    message.add(m.Paragraph(tr(
        'When the scenario analysis completed you may want to generate a '
        'report. Usually the "Print..."  button will be enabled immediately '
        'after analysis. Selecting an InaSAFE impact layer in QGIS Layers '
        'panel will also enable it.'
    )))

    # This adds the help content of the print dialog
    message.add(report())
    return message
Пример #7
0
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/'
                                    'minimum-needs-screenshot.png' %
                                    resources_path()),
                            style_class='text-center')
    message.add(paragraph)
    message.add(
        m.Paragraph(
            tr('During and after a disaster, providing for the basic human minimum '
               'needs of food, water, hygiene and shelter is an important element of '
               'your contingency plan. InaSAFE has a customisable minimum needs '
               'system that allows you to define country or region specific '
               'requirements for compiling a needs report where the exposure '
               'layer represents population.')))
    message.add(
        m.Paragraph(
            tr('By default InaSAFE uses minimum needs defined for Indonesia - '
               'and ships with additional profiles for the Philippines and Tanzania. '
               'You can customise these or add your own region-specific profiles too.'
               )))
    message.add(
        m.Paragraph(
            tr('Minimum needs are grouped into regional or linguistic \'profiles\'. '
               'The default profile is \'BNPB_en\' - the english profile for the '
               'national disaster agency in Indonesia. '
               'You will see that this profile defines requirements for displaced '
               'persons in terms of Rice, Drinking Water, Clean Water (for bathing '
               'etc.), Family Kits (with personal hygiene items) and provision of '
               'toilets.')))
    message.add(
        m.Paragraph(
            tr('Each item in the profile can be customised or removed. For example '
               'selecting the first item in the list and then clicking on the '
               '\'pencil\' icon will show the details of how it was defined. '
               'If you scroll up and down in the panel you will see that for each '
               'item, you can set a name, description, units (in singular, '
               'plural and abbreviated forms), specify maxima and minima for the '
               'quantity of item allowed, a default and a frequency. You would use '
               'the maxima and minima to ensure that disaster managers never '
               'allocate amounts that will not be sufficient for human livelihood, '
               'and also that will not overtax the logistics operation for those '
               'providing humanitarian relief.')))
    message.add(
        m.Paragraph(
            tr('The final item in the item configuration is the \'readable '
               'sentence\' which bears special discussion. Using a simple system of '
               'tokens you can construct a sentence that will be used in the '
               'generated needs report.')))
    message.add(m.Heading(tr('Minimum needs profiles'), **INFO_STYLE))
    message.add(
        m.Paragraph(
            tr('A profile is a collection of resources that define the minimum needs '
               'for a particular country or region. Typically a profile should be '
               'based on a regional, national or international standard. The '
               'actual definition of which resources are needed in a given '
               'profile is dependent on the local conditions and customs for the '
               'area where the contingency plan is being devised.')))
    message.add(
        m.Paragraph(
            tr('For example in the middle east, rice is a staple food whereas in '
               'South Africa, maize meal is a staple food and thus the contingency '
               'planning should take these localised needs into account.')))

    message.add(m.Heading(tr('Minimum needs resources'), **INFO_STYLE))
    message.add(
        m.Paragraph(
            tr('Each item in a minimum needs profile is a resource. Each resource '
               'is described as a simple natural language sentence e.g.:')))

    message.add(
        m.EmphasizedText(
            tr('Each person should be provided with 2.8 kilograms of Rice weekly.'
               )))
    message.add(
        m.Paragraph(
            tr('By clicking on a resource entry in the profile window, and then '
               'clicking the black pencil icon you will be able to edit the '
               'resource using the resource editor. Alternatively you can create a '
               'new resource for a profile by clicking on the black + icon in '
               'the profile manager. You can also remove any resource from a '
               'profile using the - icon in the profile manager.')))

    message.add(m.Heading(tr('Resource Editor'), **INFO_STYLE))
    message.add(
        m.Paragraph(
            tr('When switching to edit or add resource mode, the minimum needs '
               'manager will be updated to show the resource editor. Each '
               'resource is described in terms of:')))
    bullets = m.BulletedList()
    bullets.add(
        m.Text(m.ImportantText(tr('resource name')), tr(' - e.g. Rice')))
    bullets.add(
        m.Text(m.ImportantText(tr('a description of the resource')),
               tr(' - e.g. Basic food')))
    bullets.add(
        m.Text(m.ImportantText(tr('unit in which the resource is provided')),
               tr(' - e.g. kilogram')))
    bullets.add(
        m.Text(m.ImportantText(tr('pluralised form of the units')),
               tr(' - e.g. kilograms')))
    bullets.add(
        m.Text(m.ImportantText(tr('abbreviation for the unit')),
               tr(' - e.g. kg')))
    bullets.add(
        m.Text(
            m.ImportantText(tr('the default allocation for the resource')),
            tr(' - e.g. 2.8. This number can be overridden on a '
               'per-analysis basis')))
    bullets.add(
        m.Text(
            m.ImportantText(
                tr('minimum allowed which is used to prevent allocating')),
            tr(' - e.g. no drinking water to displaced persons')))
    bullets.add(
        m.ImportantText(
            tr('maximum allowed which is used to set a sensible upper '
               'limit for the resource')))
    bullets.add(
        m.ImportantText(
            tr('a readable sentence which is used to compile the '
               'sentence describing the resource in reports.')))
    message.add(bullets)

    message.add(
        m.Paragraph(
            tr('These parameters are probably all fairly self explanatory, but '
               'the readable sentence probably needs further detail. The '
               'sentence is compiled using a simple keyword token replacement '
               'system. The following tokens can be used:')))

    bullets = m.BulletedList()
    bullets.add(m.Text('{{ Default }}'))
    bullets.add(m.Text('{{ Unit }}'))
    bullets.add(m.Text('{{ Units }}'))
    bullets.add(m.Text('{{ Unit abbreviation }}'))
    bullets.add(m.Text('{{ Resource name }}'))
    bullets.add(m.Text('{{ Frequency }}'))
    bullets.add(m.Text('{{ Minimum allowed }}'))
    bullets.add(m.Text('{{ Maximum allowed }}'))
    message.add(bullets)

    message.add(
        m.Paragraph(
            tr('When the token is placed in the sentence it will be replaced with '
               'the actual value at report generation time. This contrived example '
               'shows a tokenised sentence that includes all possible keywords:'
               )))

    message.add(
        m.EmphasizedText(
            tr('A displaced person should be provided with {{ %s }} '
               '{{ %s }}/{{ %s }}/{{ %s }} of {{ %s }}. Though no less than {{ %s }} '
               'and no more than {{ %s }}. This should be provided {{ %s }}.' %
               ('Default', 'Unit', 'Units', 'Unit abbreviation',
                'Resource name', 'Minimum allowed', 'Maximum allowed',
                'Frequency'))))
    message.add(
        m.Paragraph(tr('Would generate a human readable sentence like this:')))

    message.add(
        m.ImportantText(
            tr('A displaced person should be provided with 2.8 kilogram/kilograms/kg '
               'of rice. Though no less than 0 and no more than 100. This should '
               'be provided daily.')))
    message.add(
        m.Paragraph(
            tr('Once you have populated the resource elements, click the Save '
               'resource button to return to the profile view. You will see the '
               'new resource added in the profile\'s resource list.')))

    message.add(m.Heading(tr('Managing profiles'), **INFO_STYLE))
    message.add(
        m.Paragraph(
            tr('In addition to the profiles that come as standard with InaSAFE, you '
               'can create new ones, either from scratch, or based on an existing '
               'one (which you can then modify).')))
    message.add(
        m.Paragraph(
            tr('Use the New button to create new profile. When prompted, give your '
               'profile a name e.g. \'JakartaProfile\'.')))
    message.add(
        m.Paragraph(
            tr('Note: The profile must be saved in your home directory under '
               '(QGIS profile path)/minimum_needs in order '
               'for InaSAFE to successfully '
               'detect it.')))
    message.add(
        m.Paragraph(
            tr('An alternative way to create a new profile is to use the Save as to '
               'clone an existing profile. The clone profile can then be edited '
               'according to your specific needs.')))
    message.add(m.Heading(tr('Active profile'), **INFO_STYLE))
    message.add(
        m.Paragraph(
            tr('It is important to note, that which ever profile you select in the '
               'Profile pick list, will be considered active and will be used as '
               'the basis for all minimum needs analysis. You need to restart '
               'QGIS before the changed profile become active.')))
    return message
Пример #8
0
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(
        tr('InaSAFE is free software that produces realistic natural hazard '
           'impact scenarios for better planning, preparedness and response '
           'activities. It provides a simple but rigourous way to combine data '
           'from scientists, local governments and communities to provide '
           'insights into the likely impacts of future disaster events.'))
    message.add(paragraph)
    paragraph = m.Paragraph(
        tr('The InaSAFE \'dock panel\' helps you to run hazard impact analysis '
           'within the QGIS environment. It helps you create your hazard impact '
           'analysis question and shows the results of this analysis. If you are '
           'a new user, you may also consider using the \'Impact Function '
           'Centric Wizard\' to run the analysis. This wizard will guide you '
           'through the process of running an InaSAFE assessment, with '
           'interactive step by step instructions. You can launch the wizard '
           'by clicking on this icon in the toolbar:'),
        m.Image('file:///%s/img/icons/'
                'show-wizard.svg' % resources_path(), **SMALL_ICON_STYLE),
    )
    message.add(paragraph)
    paragraph = m.Paragraph(
        tr('You can drag and drop the dock panel to reposition it on the screen. '
           'For example, dragging the panel towards the right margin of the QGIS '
           'application will dock it to the right side of the screen.'))
    message.add(paragraph)

    message.add(
        m.Paragraph(tr('There are three main areas to the dock panel:')))
    bullets = m.BulletedList()
    bullets.add(
        m.Text(
            # format 'the __questions__ area' for proper i18n
            tr('the %s area') %
            (m.ImportantText(tr('questions')).to_html(), )))
    bullets.add(
        m.Text(
            # format 'the __results__ area' for proper i18n
            tr('the %s area') % (m.ImportantText(tr('results')).to_html(), )))
    bullets.add(
        m.Text(
            # format 'the __buttons__ area' for proper i18n
            tr('the %s area') % (m.ImportantText(tr('buttons')).to_html(), )))
    message.add(bullets)
    message.add(
        m.Paragraph(
            tr('You can get help at any time in InaSAFE by clicking on the '
               'help buttons provided on each dock and dialog.')))

    header = m.Heading(tr('The questions area'), **INFO_STYLE)
    message.add(header)
    message.add(
        m.Paragraph(
            tr('The intention of InaSAFE is to make it easy to perform your impact '
               'analysis. We start the analysis in the questions area. This area '
               'contains three drop down menus. You create your question by using '
               'these drop down menus to select the hazard and exposure data you '
               'wish to perform the analysis on. '
               'All questions follow this form:'),
            m.EmphasizedText(
                tr('In the event of a [hazard], how many [exposure] might be '
                   '[impacted]?'))))
    message.add(
        m.Paragraph(
            tr('For example: "If there is a flood, how many buildings might be '
               'flooded?"')))
    message.add(
        m.Paragraph(
            tr('InaSAFE can be used to answer such questions for hazards such as '
               'flood, tsunami, volcanic ash fall and earthquake and exposures '
               'such as population, roads, structures, land cover etc.')))
    message.add(
        m.Paragraph(
            tr('The first step in answering these questions is to load layers that '
               'represent either hazard scenarios or exposure data into QGIS. '
               'A hazard, for example, may be represented as a raster layer in '
               'QGIS where each pixel in the raster represents the flood depth '
               'following an inundation event. An exposure layer could be '
               'represented, for example, as vector polygon data representing '
               'building outlines, or a raster outline where each pixel represents '
               'the number of people thought to be living in that cell.')))
    message.add(
        m.Paragraph(
            tr('InaSAFE will combine these two layers in a '
               'mathematical model. The results of this model will show what the '
               'effect of the hazard will be on the exposed infrastructure or '
               'people. The plugin relies on simple keyword metadata '
               'associated with each layer to determine what kind of information the '
               'layer represents. You can define these keywords by '
               'selecting a layer and then clicking the InaSAFE Keywords Wizard icon '
               'on the toolbar: '),
            m.Image(
                'file:///%s/img/icons/'
                'show-keyword-wizard.svg' % resources_path(),
                **SMALL_ICON_STYLE),
            tr('The wizard will guide you through the process of defining the '
               'keywords for that layer.')))
    message.add(
        m.Paragraph(
            tr('Aggregation is the process whereby we group the analysis results '
               'by district so that you can see how many people, roads or '
               'buildings were affected in each area. This will help you to '
               'understand where the most critical needs are.  Aggregation is '
               'optional in InaSAFE - if you do not use aggregation, the entire '
               'analysis area will be used for the data summaries. Typically '
               'aggregation layers in InaSAFE have the name of the district or '
               'reporting area as attributes. It is also possible to use extended '
               'attributes to indicate the ratio of men and women; youth, adults '
               'and elderly living in each area. Where these are provided and the '
               'exposure layer is population, InaSAFE will provide a demographic '
               'breakdown per aggregation area indicating how many men, women, etc. '
               'were probably affected in that area.')))

    header = m.Heading(tr('The results area'), **INFO_STYLE)
    message.add(header)

    message.add(
        m.Paragraph(
            tr('After running an analysis, the question area is hidden to maximise '
               'the amount of space allocated to the results area. You can '
               're-open the question area at any time by pressing the \'show '
               'question form\' button.')))

    message.add(
        m.Paragraph(
            tr('The results area is used to display various useful feedback items to '
               'the user. Once an impact scenario has been run, a summary table will '
               'be shown.')))

    message.add(
        m.Paragraph(
            tr('If you select an impact layer (i.e. a layer that was produced using '
               'an InaSAFE Impact Function), in the QGIS layers list, this summary '
               'will also be displayed in the results area. When you select a hazard '
               'or exposure layer in the QGIS layers list, the keywords for that '
               'layer will be shown in the results area, making it easy to '
               'understand what metadata exists for that layer.')))

    message.add(
        m.Paragraph(
            tr('The results area is also used to display status information. For '
               'example, during the analysis process, the status area will display '
               'notes about each step in the analysis process. The \'Run\' '
               'button will be activated when both a valid hazard and valid exposure '
               'layer have been added in QGIS.')))

    message.add(
        m.Paragraph(
            tr('Finally, the results area is also used to display any error messages '
               'so that you can see what went wrong and why. You may need to '
               'scroll down to view the message completely to see all of the error '
               'message details.')))

    message.add(
        m.Paragraph(
            tr('After running the impact scenario calculation, the question is '
               'automatically hidden to make the results area as large as possible. '
               'If you want to see what the question used in the analysis was, click '
               'on the \'Show question form\' button at the top of the results area.'
               )))

    message.add(
        m.Paragraph(
            tr('If you want to hide the question area again to have more space to '
               'display the results, click on the layer you just calculated '
               'with InaSAFE in the Layers list of QGIS to make it active.')))

    header = m.Heading(tr('The buttons area'), **INFO_STYLE)
    message.add(header)

    message.add(m.Paragraph(tr('The buttons area contains four buttons:')))
    bullets = m.BulletedList()
    bullets.add(
        m.Text(
            m.ImportantText(tr('Help')),
            tr('- click on this if you need context help, such as the document '
               'you are reading right now!')))
    bullets.add(
        m.Text(
            m.ImportantText(tr('About')),
            tr('- click on this to see short credits for the InaSAFE project.')
        ))
    bullets.add(
        m.Text(
            m.ImportantText(tr('Print')),
            tr('... - click on this if you wish to create a pdf of your '
               'impact scenario project or generate a report to open in '
               'composer for further tuning. An impact layer must be active '
               'before the \'Print\' button will be enabled.')))
    bullets.add(
        m.Text(
            m.ImportantText(tr('Run')),
            tr('- this button is enabled when the combination of hazard and '
               'exposure selected in the questions area\'s drop down menus will '
               'allow you to run a scenario.')))
    message.add(bullets)

    header = m.Heading(tr('Data conversions'), **INFO_STYLE)
    message.add(header)

    message.add(
        m.Paragraph(
            tr('When running a scenario, the data being used needs to be processed '
               'into a state where it is acceptable for use by InaSAFE. '
               'In particular it should be noted that:')))

    bullets = m.BulletedList()
    bullets.add(
        tr('Remote datasets will be copied locally before processing.'))
    bullets.add(
        m.Text(
            tr('All datasets will be clipped to the behaviours defined in the '
               'analysis extents dialog if you do not use an aggregation layer.'
               ),
            m.Image(
                'file:///%s/img/icons/'
                'set-extents-tool.svg' % resources_path(),
                **SMALL_ICON_STYLE)))
    bullets.add(
        m.Text(
            tr('You can visualise the area that will be used for the analysis '
               'by enabling the "Toggle Scenario Outlines" tool. When this tool '
               'is enabled, a line (green by default) will be drawn around the '
               'outermost boundary of the analysis area.'),
            m.Image(
                'file:///%s/img/icons/'
                'toggle-rubber-bands.svg' % resources_path(),
                **SMALL_ICON_STYLE)))
    bullets.add(
        m.Text(
            tr('When you have selected an aggregation layer the analysis area '
               'will be the outline of the aggregation layer. If you select one '
               'or more polygons in the aggregation layer (by using the QGIS '
               'feature selection tools), the analysis boundary will be reduced '
               'to just the outline of these selected polygons. If the "Toggle '
               'Scenario Outlines" tool is enabled, the preview of the effective '
               'analysis area will be updated to reflect the selected features.'
               ), ))
    bullets.add(
        tr('All clipped datasets will be converted (reprojected) to the '
           'Coordinate Reference System of the exposure layer '
           'before analysis.'))
    message.add(bullets)

    header = m.Heading(tr('Generating impact reports'), **INFO_STYLE)
    message.add(header)

    message.add(
        m.Paragraph(
            tr('When the impact analysis has completed you may want to generate a '
               'report. Usually the \'Print...\'  button will be enabled immediately '
               'after analysis. Selecting an InaSAFE impact layer in QGIS Layers '
               'panel will also enable it.')))

    # This adds the help content of the print dialog
    message.add(report())
    return message