Example #1
0
    def test_print_default_template(self):
        """Test printing report to pdf using default template works."""
        impact_layer_path = test_data_path(
            'impact', 'population_affected_entire_area.shp')
        layer, _ = load_layer(impact_layer_path)
        # noinspection PyUnresolvedReferences,PyArgumentList
        QgsMapLayerRegistry.instance().addMapLayer(layer)
        # noinspection PyCallingNonCallable
        rect = QgsRectangle(106.8194, -6.2108, 106.8201, -6.1964)
        CANVAS.setExtent(rect)
        CANVAS.refresh()

        template = resources_path('qgis-composer-templates',
                                  'a4-portrait-blue.qpt')
        report = ImpactReport(IFACE, template, layer)
        out_path = unique_filename(prefix='map_default_template_test',
                                   suffix='.pdf',
                                   dir=temp_dir('test'))
        report.print_map_to_pdf(out_path)

        # Check the file exists
        message = 'Rendered output does not exist: %s' % out_path
        self.assertTrue(os.path.exists(out_path), message)

        # Check the file is not corrupt
        message = 'The output file %s is corrupt' % out_path
        out_size = os.stat(out_path).st_size
        self.assertTrue(out_size > 0, message)

        # Check the components in composition are default components
        if qgis_version() < 20500:
            safe_logo = report.composition.getComposerItemById(
                'inasafe-logo').pictureFile()
            north_arrow = report.composition.getComposerItemById(
                'north-arrow').pictureFile()
            org_logo = report.composition.getComposerItemById(
                'organisation-logo').pictureFile()
        else:
            safe_logo = report.composition.getComposerItemById(
                'white-inasafe-logo').picturePath()
            north_arrow = report.composition.getComposerItemById(
                'north-arrow').picturePath()
            org_logo = report.composition.getComposerItemById(
                'organisation-logo').picturePath()

        expected_safe_logo = resources_path('img', 'logos',
                                            'inasafe-logo-url-white.svg')
        expected_north_arrow = resources_path('img', 'north_arrows',
                                              'simple_north_arrow.png')
        expected_org_logo = resources_path('img', 'logos', 'supporters.png')

        message = ('The safe logo path is not the default one: %s isn\'t %s' %
                   (expected_safe_logo, safe_logo))
        self.assertEqual(expected_safe_logo, safe_logo, message)

        message = 'The north arrow path is not the default one'
        self.assertEqual(expected_north_arrow, north_arrow, message)

        message = 'The organisation logo path is not the default one'
        self.assertEqual(expected_org_logo, org_logo, message)
    def test_print_default_template(self):
        """Test printing report to pdf using default template works."""
        impact_layer_path = test_data_path(
            'impact', 'population_affected_entire_area.shp')
        layer, _ = load_layer(impact_layer_path)
        # noinspection PyUnresolvedReferences
        QgsMapLayerRegistry.instance().addMapLayer(layer)
        # noinspection PyCallingNonCallable
        rect = QgsRectangle(106.8194, -6.2108, 106.8201, -6.1964)
        CANVAS.setExtent(rect)
        CANVAS.refresh()

        template = resources_path(
            'qgis-composer-templates', 'inasafe-portrait-a4.qpt')
        report = ImpactReport(IFACE, template, layer)
        out_path = unique_filename(
            prefix='map_default_template_test',
            suffix='.pdf',
            dir=temp_dir('test'))
        report.print_map_to_pdf(out_path)

        # Check the file exists
        message = 'Rendered output does not exist: %s' % out_path
        self.assertTrue(os.path.exists(out_path), message)

        # Check the file is not corrupt
        message = 'The output file %s is corrupt' % out_path
        out_size = os.stat(out_path).st_size
        self.assertTrue(out_size > 0, message)

        # Check the components in composition are default components
        if qgis_version() < 20500:
            safe_logo = report.composition.getComposerItemById(
                'safe-logo').pictureFile()
            north_arrow = report.composition.getComposerItemById(
                'north-arrow').pictureFile()
            org_logo = report.composition.getComposerItemById(
                'organisation-logo').pictureFile()
        else:
            safe_logo = report.composition.getComposerItemById(
                'safe-logo').picturePath()
            north_arrow = report.composition.getComposerItemById(
                'north-arrow').picturePath()
            org_logo = report.composition.getComposerItemById(
                'organisation-logo').picturePath()

        expected_safe_logo = resources_path(
            'img', 'logos', 'inasafe-logo-url.svg')
        expected_north_arrow = resources_path(
            'img', 'north_arrows', 'simple_north_arrow.png')
        expected_org_logo = resources_path('img', 'logos', 'supporters.png')

        message = 'The safe logo path is not the default one'
        self.assertEqual(expected_safe_logo, safe_logo, message)

        message = 'The north arrow path is not the default one'
        self.assertEqual(expected_north_arrow, north_arrow, message)

        message = 'The organisation logo path is not the default one'
        self.assertEqual(expected_org_logo, org_logo, message)
Example #3
0
def generate_impact_report(impact_function, iface):
    """Generate the impact report from an impact function.

    :param impact_function: The impact function used.
    :type impact_function: ImpactFunction

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface

    """
    # create impact report instance
    report_metadata = ReportMetadata(
        metadata_dict=standard_impact_report_metadata_pdf)
    impact_report = ImpactReport(
        iface,
        report_metadata,
        impact_function=impact_function)

    # generate report folder

    # no other option for now
    # TODO: retrieve the information from data store
    if isinstance(impact_function.datastore.uri, QDir):
        layer_dir = impact_function.datastore.uri.absolutePath()
    else:
        # No other way for now
        return

    # We will generate it on the fly without storing it after datastore
    # supports
    impact_report.output_folder = os.path.join(layer_dir, 'output')
    return impact_report.process_components()
Example #4
0
def generate_impact_report(cli_arguments, impact_function, iface):
    """Generate the impact report from an impact function.

    :param cli_arguments: User inputs.
    :type cli_arguments: CommandLineArguments

    :param impact_function: The impact function used.
    :type impact_function: ImpactFunction

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface

    .. versionadded:: 4.0

    """
    # create impact report instance
    report_metadata = ReportMetadata(
        metadata_dict=standard_impact_report_metadata_pdf)
    impact_report = ImpactReport(
        iface,
        report_metadata,
        impact_function=impact_function)
    impact_report.output_folder = cli_arguments.output_dir

    return impact_report.process_components()
Example #5
0
    def Xtest_print_impact_table(self):
        """Test print impact table to pdf."""
        impact_layer_path = test_data_path(
            'impact', 'population_affected_entire_area.shp')
        layer, _ = load_layer(impact_layer_path)
        # noinspection PyUnresolvedReferences,PyArgumentList
        QgsMapLayerRegistry.instance().addMapLayer(layer)
        # noinspection PyCallingNonCallable
        rect = QgsRectangle(106.8194, -6.2108, 106.8201, -6.1964)
        CANVAS.setExtent(rect)
        CANVAS.refresh()

        template = resources_path(
            'qgis-composer-templates', 'a4-portrait-blue.qpt')
        report = ImpactReport(IFACE, template, layer)
        report.template = template  # just to cover set template
        out_path = unique_filename(
            prefix='test_print_impact_table',
            suffix='.pdf',
            dir=temp_dir('test'))
        report.print_impact_table(out_path)

        # Check the file exists
        message = 'Rendered output does not exist: %s' % out_path
        self.assertTrue(os.path.exists(out_path), message)

        # Check the file is not corrupt
        message = 'The output file %s is corrupt' % out_path
        out_size = os.stat(out_path).st_size
        self.assertTrue(out_size > 0, message)
Example #6
0
    def test_print_impact_table(self):
        """Test print impact table to pdf."""
        impact_layer_path = test_data_path(
            'impact', 'population_affected_entire_area.shp')
        layer, _ = load_layer(impact_layer_path)
        # noinspection PyUnresolvedReferences
        QgsMapLayerRegistry.instance().addMapLayer(layer)
        # noinspection PyCallingNonCallable
        rect = QgsRectangle(106.8194, -6.2108, 106.8201, -6.1964)
        CANVAS.setExtent(rect)
        CANVAS.refresh()

        template = resources_path('qgis-composer-templates',
                                  'inasafe-portrait-a4.qpt')
        report = ImpactReport(IFACE, template, layer)
        report.template = template  # just to cover set template
        out_path = unique_filename(prefix='test_print_impact_table',
                                   suffix='.pdf',
                                   dir=temp_dir('test'))
        report.print_impact_table(out_path)

        # Check the file exists
        message = 'Rendered output does not exist: %s' % out_path
        self.assertTrue(os.path.exists(out_path), message)

        # Check the file is not corrupt
        message = 'The output file %s is corrupt' % out_path
        out_size = os.stat(out_path).st_size
        self.assertTrue(out_size > 0, message)
Example #7
0
    def create_pdf(self, title, output_directory, impact_layer, count=0, index=None):
        """Create PDF report from impact layer.

        Create map & table report PDF based from impact_layer data.

        :param title: Report title.
        :type title: str

        :param output_directory: Output directory.
        :type output_directory: str

        :param impact_layer: Impact layer instance.
        :type impact_layer: QgsMapLayer

        :param count: The number of scenarios that were run.
        :type count: int

        :param index: A sequential number to place at the beginning of the
            file name.
        :type index: int, None

        See also:
            Dock.printMap()
        """
        # FIXME: check if impact_layer is the real impact layer...
        template = resources_path("qgis-composer-templates", "inasafe-portrait-a4.qpt")
        impact_report = ImpactReport(self.iface, template, impact_layer)

        LOGGER.debug("Create Report: %s" % title)
        map_path, table_path = self.report_path(output_directory, title, count, index)

        # create map and table pdf
        map_path, table_path = impact_report.print_to_pdf(map_path)

        LOGGER.debug("Report done %s %s" % (map_path, table_path))
Example #8
0
def generate_impact_map_report(impact_function, iface):
    """Generate impact map pdf from impact function.

    :param impact_function: The impact function used.
    :type impact_function: ImpactFunction

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface
    """
    # get the extra layers that we need
    extra_layers = []
    print_atlas = setting('print_atlas_report', False, bool)
    if print_atlas:
        extra_layers.append(impact_function.aggregation_summary)

    # get the hazard and exposure type
    hazard_layer = impact_function.hazard
    exposure_layer = impact_function.exposure

    hazard_type = layer_definition_type(hazard_layer)
    exposure_type = layer_definition_type(exposure_layer)

    # create impact report instance
    report_metadata = ReportMetadata(metadata_dict=update_template_component(
        component=map_report, hazard=hazard_type, exposure=exposure_type))
    impact_report = ImpactReport(iface,
                                 report_metadata,
                                 impact_function=impact_function,
                                 extra_layers=extra_layers)

    # Get other setting
    logo_path = setting('organisation_logo_path', None, str)
    impact_report.inasafe_context.organisation_logo = logo_path

    disclaimer_text = setting('reportDisclaimer', None, str)
    impact_report.inasafe_context.disclaimer = disclaimer_text

    north_arrow_path = setting('north_arrow_path', None, str)
    impact_report.inasafe_context.north_arrow = north_arrow_path

    # get the extent of impact layer
    impact_report.qgis_composition_context.extent = \
        impact_function.impact.extent()

    # generate report folder

    # no other option for now
    # TODO: retrieve the information from data store
    if isinstance(impact_function.datastore.uri, QDir):
        layer_dir = impact_function.datastore.uri.absolutePath()
    else:
        # No other way for now
        return

    # We will generate it on the fly without storing it after datastore
    # supports
    impact_report.output_folder = os.path.join(layer_dir, 'output')
    return impact_report.process_components()
Example #9
0
    def retrieve_paths(self, products, report_path, suffix=None):
        """Helper method to retrieve path from particular report metadata.

        :param products: Report products.
        :type products: list

        :param report_path: Path of the IF output.
        :type report_path: str

        :param suffix: Expected output product file type (extension).
        :type suffix: str

        :return: List of absolute path of the output product.
        :rtype: list
        """
        paths = []
        for product in products:
            path = ImpactReport.absolute_output_path(
                join(report_path, 'output'),
                products,
                product.key)
            if isinstance(path, list):
                for p in path:
                    paths.append(p)
            elif isinstance(path, dict):
                for p in list(path.values()):
                    paths.append(p)
            else:
                paths.append(path)
        if suffix:
            paths = [p for p in paths if p.endswith(suffix)]

        paths = [p for p in paths if exists(p)]
        return paths
Example #10
0
    def retrieve_paths(self, products, report_path, suffix=None):
        """Helper method to retrieve path from particular report metadata.

        :param products: Report products.
        :type products: list

        :param report_path: Path of the IF output.
        :type report_path: str

        :param suffix: Expected output product file type (extension).
        :type suffix: str

        :return: List of absolute path of the output product.
        :rtype: list
        """
        paths = []
        for product in products:
            path = ImpactReport.absolute_output_path(
                join(report_path, 'output'), products, product.key)
            if isinstance(path, list):
                for p in path:
                    paths.append(p)
            elif isinstance(path, dict):
                for p in list(path.values()):
                    paths.append(p)
            else:
                paths.append(path)
        if suffix:
            paths = [p for p in paths if p.endswith(suffix)]

        paths = [p for p in paths if exists(p)]
        return paths
Example #11
0
    def test_custom_logo(self):
        """Test that setting user-defined logo works."""
        LOGGER.info('Testing custom_logo')
        impact_layer_path = test_data_path(
            'impact', 'population_affected_entire_area.shp')
        layer, _ = load_layer(impact_layer_path)
        # noinspection PyUnresolvedReferences
        QgsMapLayerRegistry.instance().addMapLayer(layer)
        # noinspection PyCallingNonCallable
        rect = QgsRectangle(106.8194, -6.2108, 106.8201, -6.1964)
        CANVAS.setExtent(rect)
        CANVAS.refresh()

        template = resources_path('qgis-composer-templates',
                                  'inasafe-portrait-a4.qpt')
        report = ImpactReport(IFACE, template, layer)

        # Set custom logo
        custom_logo_path = resources_path('img', 'logos', 'logo-flower.png')
        report.organisation_logo = custom_logo_path

        out_path = unique_filename(prefix='map_custom_logo_test',
                                   suffix='.pdf',
                                   dir=temp_dir('test'))
        report.print_map_to_pdf(out_path)

        # Check the file exists
        message = 'Rendered output does not exist: %s' % out_path
        self.assertTrue(os.path.exists(out_path), message)

        # Check the file is not corrupt
        message = 'The output file %s is corrupt' % out_path
        out_size = os.stat(out_path).st_size
        self.assertTrue(out_size > 0, message)

        # Check the organisation logo in composition sets correctly to
        # logo-flower
        if qgis_version() < 20500:
            custom_img_path = report.composition.getComposerItemById(
                'organisation-logo').pictureFile()
        else:
            custom_img_path = report.composition.getComposerItemById(
                'organisation-logo').picturePath()

        message = 'The custom logo path is not set correctly'
        self.assertEqual(custom_logo_path, custom_img_path, message)
Example #12
0
def generate_impact_map_report(impact_function, iface):
    """Generate impact map pdf from impact function.

    :param impact_function: The impact function used.
    :type impact_function: ImpactFunction

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface
    """
    # create impact report instance
    report_metadata = ReportMetadata(
        metadata_dict=map_report_component(report_a4_blue))
    impact_report = ImpactReport(
        iface,
        report_metadata,
        impact_function=impact_function)

    # Get other setting
    logo_path = setting('organisation_logo_path', None, str)
    impact_report.inasafe_context.organisation_logo = logo_path

    disclaimer_text = setting('reportDisclaimer', None, str)
    impact_report.inasafe_context.disclaimer = disclaimer_text

    north_arrow_path = setting('north_arrow_path', None, str)
    impact_report.inasafe_context.north_arrow = north_arrow_path

    # get the extent of impact layer
    impact_report.qgis_composition_context.extent = \
        impact_function.impact.extent()

    # generate report folder

    # no other option for now
    # TODO: retrieve the information from data store
    if isinstance(impact_function.datastore.uri, QDir):
        layer_dir = impact_function.datastore.uri.absolutePath()
    else:
        # No other way for now
        return

    # We will generate it on the fly without storing it after datastore
    # supports
    impact_report.output_folder = os.path.join(layer_dir, 'output')
    return impact_report.process_components()
Example #13
0
    def test_custom_logo(self):
        """Test that setting user-defined logo works."""
        LOGGER.info('Testing custom_logo')
        impact_layer_path = test_data_path(
            'impact', 'population_affected_entire_area.shp')
        layer, _ = load_layer(impact_layer_path)
        # noinspection PyUnresolvedReferences,PyArgumentList
        QgsMapLayerRegistry.instance().addMapLayer(layer)
        # noinspection PyCallingNonCallable
        rect = QgsRectangle(106.8194, -6.2108, 106.8201, -6.1964)
        CANVAS.setExtent(rect)
        CANVAS.refresh()

        template = resources_path(
            'qgis-composer-templates', 'a4-portrait-blue.qpt')
        report = ImpactReport(IFACE, template, layer)

        # Set custom logo
        custom_logo_path = resources_path('img', 'logos', 'supporters.png')
        report.organisation_logo = custom_logo_path

        out_path = unique_filename(
            prefix='map_custom_logo_test', suffix='.pdf', dir=temp_dir('test'))
        report.print_map_to_pdf(out_path)

        # Check the file exists
        message = 'Rendered output does not exist: %s' % out_path
        self.assertTrue(os.path.exists(out_path), message)

        # Check the file is not corrupt
        message = 'The output file %s is corrupt' % out_path
        out_size = os.stat(out_path).st_size
        self.assertTrue(out_size > 0, message)

        # Check the organisation logo in composition sets correctly to
        # logo-flower
        if qgis_version() < 20500:
            custom_img_path = report.composition.getComposerItemById(
                'organisation-logo').pictureFile()
        else:
            custom_img_path = report.composition.getComposerItemById(
                'organisation-logo').picturePath()

        message = 'The custom logo path is not set correctly'
        self.assertEqual(custom_logo_path, custom_img_path, message)
Example #14
0
    def generate_pdf_report(self, impact_function, iface, scenario_name):
        """Generate and store map and impact report from impact function.

        Directory where the report stored is specified by user input from the
        dialog. This function is adapted from analysis_utilities.py

        :param impact_function: Impact Function.
        :type impact_function: ImpactFunction()

        :param iface: iface.
        :type iface: iface

        :param scenario_name: name of the scenario
        :type scenario_name: str
        """
        # output folder
        output_dir = self.output_directory.text()
        file_path = os.path.join(output_dir, scenario_name)

        # create impact table report instance
        table_report_metadata = ReportMetadata(
            metadata_dict=standard_impact_report_metadata_pdf)
        impact_table_report = ImpactReport(
            iface,
            table_report_metadata,
            impact_function=impact_function)
        impact_table_report.output_folder = file_path
        impact_table_report.process_components()

        # create impact map report instance
        map_report_metadata = ReportMetadata(
            metadata_dict=update_template_component(map_report))
        impact_map_report = ImpactReport(
            iface,
            map_report_metadata,
            impact_function=impact_function)
        # TODO: Get from settings file

        # get the extent of impact layer
        impact_map_report.qgis_composition_context.extent = \
            impact_function.impact.extent()
        impact_map_report.output_folder = file_path
        impact_map_report.process_components()
Example #15
0
    def create_pdf(
            self,
            title,
            output_directory,
            impact_layer,
            count=0,
            index=None):
        """Create PDF report from impact layer.

        Create map & table report PDF based from impact_layer data.

        :param title: Report title.
        :type title: str

        :param output_directory: Output directory.
        :type output_directory: str

        :param impact_layer: Impact layer instance.
        :type impact_layer: QgsMapLayer

        :param count: The number of scenarios that were run.
        :type count: int

        :param index: A sequential number to place at the beginning of the
            file name.
        :type index: int, None

        See also:
            Dock.printMap()
        """
        # FIXME: check if impact_layer is the real impact layer...
        template = resources_path(
            'qgis-composer-templates', 'a4-portrait-blue.qpt')
        impact_report = ImpactReport(self.iface, template, impact_layer)

        LOGGER.debug('Create Report: %s' % title)
        map_path, table_path = self.report_path(
            output_directory, title, count, index)

        # create map and table pdf
        map_path, table_path = impact_report.print_to_pdf(map_path)

        LOGGER.debug("Report done %s %s" % (map_path, table_path))
Example #16
0
    def test_missing_elements(self):
        """Test missing elements set correctly."""
        impact_layer_path = test_data_path(
            'impact', 'population_affected_entire_area.shp')
        layer, _ = load_layer(impact_layer_path)

        template = resources_path(
            'qgis-composer-templates', 'a4-portrait-blue.qpt')
        report = ImpactReport(IFACE, template, layer)
        # There are missing elements in the template
        component_ids = ['safe-logo', 'north-arrow', 'organisation-logo',
                         'impact-map', 'impact-legend',
                         'i-added-element-id-here-nooo']
        report.component_ids = component_ids
        expected_missing_elements = ['i-added-element-id-here-nooo']
        message = 'The missing_elements should be %s, but it returns %s' % (
            report.missing_elements, expected_missing_elements)
        self.assertEqual(
            expected_missing_elements, report.missing_elements, message)
Example #17
0
    def test_missing_elements(self):
        """Test missing elements set correctly."""
        impact_layer_path = standard_data_path(
            'impact', 'population_affected_entire_area.shp')
        layer, _ = load_layer(impact_layer_path)

        template = resources_path(
            'qgis-composer-templates', 'a4-portrait-blue.qpt')
        report = ImpactReport(IFACE, template, layer)
        # There are missing elements in the template
        component_ids = ['safe-logo', 'north-arrow', 'organisation-logo',
                         'impact-map', 'impact-legend',
                         'i-added-element-id-here-nooo']
        report.component_ids = component_ids
        expected_missing_elements = ['i-added-element-id-here-nooo']
        message = 'The missing_elements should be %s, but it returns %s' % (
            report.missing_elements, expected_missing_elements)
        self.assertEqual(
            expected_missing_elements, report.missing_elements, message)
Example #18
0
def build_report(cli_arguments):
    """Produces pdf products.

        To be called after shapefile has been written into
        arguments.output_file.

    .. versionadded:: 3.2

    :param cli_arguments: User inputs.
    :type cli_arguments: CommandLineArguments

    :raises: Exception
    """
    try:
        LOGGER.info('Building a report')
        basename, ext = os.path.splitext(cli_arguments.output_file)
        if ext == '.shp':
            impact_layer = QgsVectorLayer(cli_arguments.output_file,
                                          'Impact Layer', 'ogr')
        elif ext == '.tif':
            impact_layer = QgsRasterLayer(cli_arguments.output_file,
                                          'Impact Layer')
        layer_registry = QgsMapLayerRegistry.instance()
        layer_registry.removeAllMapLayers()
        layer_registry.addMapLayer(impact_layer)
        CANVAS.setExtent(impact_layer.extent())
        CANVAS.refresh()
        report = ImpactReport(IFACE, cli_arguments.report_template,
                              impact_layer)
        LOGGER.debug(os.path.splitext(cli_arguments.output_file)[0] + '.pdf')
        map_path = report.print_map_to_pdf(
            os.path.splitext(cli_arguments.output_file)[0] + '.pdf')
        print "Impact Map : " + map_path
        table_path = report.print_impact_table(
            os.path.splitext(cli_arguments.output_file)[0] + '_table.pdf')
        print "Impact Summary Table : " + table_path
        layer_registry.removeAllMapLayers()

    except Exception as exception:
        print exception.message
        print exception.__doc__
        raise RuntimeError
Example #19
0
def build_report(cli_arguments):
    """Produces pdf products.

        To be called after shapefile has been written into
        arguments.output_file.

    .. versionadded:: 3.2

    :param cli_arguments: User inputs.
    :type cli_arguments: CommandLineArguments

    :raises: Exception
    """
    try:
        LOGGER.info('Building a report')
        impact_layer = get_layer(cli_arguments.output_file, 'Impact Layer')
        hazard_layer = get_layer(cli_arguments.hazard, 'Hazard Layer')
        layer_registry = QgsMapLayerRegistry.instance()
        layer_registry.removeAllMapLayers()
        extra_layers = [hazard_layer]
        layer_registry.addMapLayer(impact_layer)
        layer_registry.addMapLayers(extra_layers)
        CANVAS.setExtent(impact_layer.extent())
        CANVAS.refresh()
        report = ImpactReport(
            IFACE, cli_arguments.report_template, impact_layer,
            extra_layers=extra_layers)
        report.extent = CANVAS.fullExtent()
        LOGGER.debug(os.path.splitext(cli_arguments.output_file)[0] + '.pdf')
        map_path = report.print_map_to_pdf(
            os.path.splitext(cli_arguments.output_file)[0] + '.pdf')
        print "Impact Map : " + map_path
        table_path = report.print_impact_table(
            os.path.splitext(cli_arguments.output_file)[0] + '_table.pdf')
        print "Impact Summary Table : " + table_path
        layer_registry.removeAllMapLayers()

    except Exception as exception:
        print exception.message
        print exception.__doc__
        raise RuntimeError
Example #20
0
def generate_infographic_report(impact_function, iface):
    """Generate impact map pdf from impact function.

    :param impact_function: The impact function used.
    :type impact_function: ImpactFunction

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface
    """
    # get the extra layers that we need
    extra_layers = []
    print_atlas = setting('print_atlas_report', False, bool)
    if print_atlas:
        extra_layers.append(impact_function.aggregation_summary)
    # create impact report instance
    report_metadata = ReportMetadata(
        metadata_dict=update_template_component(infographic_report))
    impact_report = ImpactReport(
        iface,
        report_metadata,
        impact_function=impact_function,
        extra_layers=extra_layers)

    # get the extent of impact layer
    impact_report.qgis_composition_context.extent = \
        impact_function.impact.extent()

    # generate report folder

    # no other option for now
    # TODO: retrieve the information from data store
    if isinstance(impact_function.datastore.uri, QDir):
        layer_dir = impact_function.datastore.uri.absolutePath()
    else:
        # No other way for now
        return

    # We will generate it on the fly without storing it after datastore
    # supports
    impact_report.output_folder = os.path.join(layer_dir, 'output')
    return impact_report.process_components()
def generate_infographic_report(impact_function, iface):
    """Generate impact map pdf from impact function.

    :param impact_function: The impact function used.
    :type impact_function: ImpactFunction

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface
    """
    # get the extra layers that we need
    extra_layers = []
    print_atlas = setting('print_atlas_report', False, bool)
    if print_atlas:
        extra_layers.append(impact_function.aggregation_summary)
    # create impact report instance
    report_metadata = ReportMetadata(
        metadata_dict=update_template_component(infographic_report))
    impact_report = ImpactReport(
        iface,
        report_metadata,
        impact_function=impact_function,
        extra_layers=extra_layers)

    # get the extent of impact layer
    impact_report.qgis_composition_context.extent = \
        impact_function.impact.extent()

    # generate report folder

    # no other option for now
    # TODO: retrieve the information from data store
    if isinstance(impact_function.datastore.uri, QDir):
        layer_dir = impact_function.datastore.uri.absolutePath()
    else:
        # No other way for now
        return

    # We will generate it on the fly without storing it after datastore
    # supports
    impact_report.output_folder = os.path.join(layer_dir, 'output')
    return impact_report.process_components()
Example #22
0
 def test_handle_missing_map_title(self):
     """Missing map title from the keywords fails gracefully"""
     # Use hazard layer as it won't have 'map_title' keyword
     layer_path = test_data_path('hazard', 'tsunami_wgs84.tif')
     layer, _ = load_layer(layer_path)
     template = resources_path('qgis-composer-templates',
                               'inasafe-portrait-a4.qpt')
     report = ImpactReport(IFACE, template, layer)
     title = report.map_title
     expected_title = None
     message = 'Expected: %s\nGot:\n %s' % (expected_title, title)
     self.assertEqual(title, expected_title, message)
Example #23
0
    def test_get_map_title(self):
        """Getting the map title from the keywords"""
        impact_layer_path = test_data_path(
            'impact', 'population_affected_entire_area.shp')
        layer, _ = load_layer(impact_layer_path)

        template = resources_path('qgis-composer-templates',
                                  'inasafe-portrait-a4.qpt')
        report = ImpactReport(IFACE, template, layer)
        title = report.map_title
        expected_title = 'People affected by flood prone areas'
        message = 'Expected: %s\nGot:\n %s' % (expected_title, title)
        self.assertEqual(title, expected_title, message)
Example #24
0
    def test_hello_world_report(self):
        """Test for creating hello world report.

        .. versionadded:: 4.1
        """
        QGIS_APP, CANVAS, IFACE, PARENT = get_qgis_app()
        output_folder = self.fixtures_dir('../output/hello_world_report')

        # sneaky monkey patch
        ImpactFunction.outputs = ['Not implemented']
        impact_function = ImpactFunction()

        template_metadata = ReportMetadata(
            metadata_dict=hello_world_metadata_html)

        impact_report = ImpactReport(iface=IFACE,
                                     template_metadata=template_metadata,
                                     impact_function=impact_function)

        impact_report.output_folder = output_folder

        impact_report.process_components()
Example #25
0
    def test_hello_world_report(self):
        """Test for creating hello world report.

        .. versionadded:: 4.1
        """
        QGIS_APP, CANVAS, IFACE, PARENT = get_qgis_app(qsetting=INASAFE_TEST)
        output_folder = self.fixtures_dir('../output/hello_world_report')

        # sneaky monkey patch
        ImpactFunction.outputs = ['Not implemented']
        impact_function = ImpactFunction()

        template_metadata = ReportMetadata(
            metadata_dict=hello_world_metadata_html)

        impact_report = ImpactReport(
            iface=IFACE,
            template_metadata=template_metadata,
            impact_function=impact_function)

        impact_report.output_folder = output_folder

        impact_report.process_components()
Example #26
0
def build_report(cli_arguments):
    """Produces pdf products.

        To be called after shapefile has been written into
        arguments.output_file.

    .. versionadded:: 3.2

    :param cli_arguments: User inputs.
    :type cli_arguments: CommandLineArguments

    :raises: Exception
    """
    try:
        LOGGER.info("Building a report")
        basename, ext = os.path.splitext(cli_arguments.output_file)
        if ext == ".shp":
            impact_layer = QgsVectorLayer(cli_arguments.output_file, "Impact Layer", "ogr")
        elif ext == ".tif":
            impact_layer = QgsRasterLayer(cli_arguments.output_file, "Impact Layer")
        layer_registry = QgsMapLayerRegistry.instance()
        layer_registry.removeAllMapLayers()
        layer_registry.addMapLayer(impact_layer)
        CANVAS.setExtent(impact_layer.extent())
        CANVAS.refresh()
        report = ImpactReport(IFACE, cli_arguments.report_template, impact_layer)
        LOGGER.debug(os.path.splitext(cli_arguments.output_file)[0] + ".pdf")
        map_path = report.print_map_to_pdf(os.path.splitext(cli_arguments.output_file)[0] + ".pdf")
        print "Impact Map : " + map_path
        table_path = report.print_impact_table(os.path.splitext(cli_arguments.output_file)[0] + "_table.pdf")
        print "Impact Summary Table : " + table_path
        layer_registry.removeAllMapLayers()

    except Exception as exception:
        print exception.message
        print exception.__doc__
        raise RuntimeError
Example #27
0
def generate_impact_map_report(cli_arguments, impact_function, iface):
    """Generate impact map pdf from impact function.

    :param cli_arguments: User inputs.
    :type cli_arguments: CommandLineArguments

    :param impact_function: The impact function used.
    :type impact_function: ImpactFunction

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface

    .. versionadded:: 4.0
    """
    layers = [impact_function.hazard, impact_function.exposure]
    aggregation_layer = impact_function.aggregation
    if aggregation_layer:
        layers.append(aggregation_layer)
    layer_registry = QgsMapLayerRegistry.instance()
    layer_registry.addMapLayers(layers)
    layer_registry.addMapLayers(impact_function.outputs)

    # create impact report instance
    report_metadata = ReportMetadata(
        metadata_dict=update_template_component(map_report)
    )
    impact_report = ImpactReport(
        iface,
        report_metadata,
        impact_function=impact_function)
    # get the extent of impact layer
    impact_report.qgis_composition_context.extent = \
        impact_function.impact.extent()
    # set the ouput folder
    impact_report.output_folder = cli_arguments.output_dir

    return impact_report.process_components()
Example #28
0
    def generate_pdf_report(self, impact_function, iface, scenario_name):
        """Generate and store map and impact report from impact function.

        Directory where the report stored is specified by user input from the
        dialog. This function is adapted from analysis_utilities.py

        :param impact_function: Impact Function.
        :type impact_function: ImpactFunction()

        :param iface: iface.
        :type iface: iface

        :param scenario_name: name of the scenario
        :type scenario_name: str
        """
        # output folder
        output_dir = self.output_directory.text()
        file_path = os.path.join(output_dir, scenario_name)

        # create impact table report instance
        table_report_metadata = ReportMetadata(
            metadata_dict=standard_impact_report_metadata_pdf)
        impact_table_report = ImpactReport(
            iface,
            table_report_metadata,
            impact_function=impact_function)
        impact_table_report.output_folder = file_path
        impact_table_report.process_components()

        # create impact map report instance
        map_report_metadata = ReportMetadata(
            metadata_dict=update_template_component(map_report))
        impact_map_report = ImpactReport(
            iface,
            map_report_metadata,
            impact_function=impact_function)
        # TODO: Get from settings file

        # get the extent of impact layer
        impact_map_report.qgis_composition_context.extent = \
            impact_function.impact.extent()
        impact_map_report.output_folder = file_path
        impact_map_report.process_components()
Example #29
0
    def retrieve_paths(products, report_path, suffix):
        """Helper method to retrieve path from particular report metadata.
        """
        paths = {}
        for product in products:
            path = ImpactReport.absolute_output_path(report_path, products,
                                                     product.key)
            if isinstance(path, list):
                for p in path:
                    if p.endswith(suffix) and exists(p):
                        paths[product.key] = p
            elif isinstance(path, dict):
                for p in path.itervalues():
                    if p.endswith(suffix) and exists(p):
                        paths[product.key] = p
            elif exists(path):
                paths[product.key] = path

        return paths
    def retrieve_paths(products, report_path, suffix):
        """Helper method to retrieve path from particular report metadata.
        """
        paths = {}
        for product in products:
            path = ImpactReport.absolute_output_path(
                report_path,
                products,
                product.key)
            if isinstance(path, list):
                for p in path:
                    if p.endswith(suffix) and exists(p):
                        paths[product.key] = p
            elif isinstance(path, dict):
                for p in list(path.values()):
                    if p.endswith(suffix) and exists(p):
                        paths[product.key] = p
            elif exists(path):
                paths[product.key] = path

        return paths
Example #31
0
    def generate_report(self):
        # Generate pdf report from impact
        if not self.impact_exists:
            # Cannot generate report when no impact layer present
            return

        layer_registry = QgsMapLayerRegistry.instance()
        layer_registry.removeAllMapLayers()
        impact_qgis_layer = read_qgis_layer(self.impact_layer.filename)
        layer_registry.addMapLayer(impact_qgis_layer)
        CANVAS.setExtent(impact_qgis_layer.extent())
        CANVAS.refresh()
        report = ImpactReport(IFACE, template=None, layer=impact_qgis_layer)

        report.print_map_to_pdf(self.map_report_path)
        report.print_impact_table(self.table_report_path)
        layer_registry.removeAllMapLayers()
    def print_map(self, mode="pdf"):
        """Open impact report dialog that used to tune report when print map
            button pressed."""
        # Check if selected layer is valid
        impact_layer = self.iface.activeLayer()
        if impact_layer is None:
            # noinspection PyCallByClass,PyTypeChecker
            QtGui.QMessageBox.warning(
                self.parent,
                self.tr('InaSAFE'),
                self.tr('Please select a valid impact layer before '
                        'trying to print.'))
            return

        # Open Impact Report Dialog
        print_dialog = ImpactReportDialog(self.iface)
        print_dialog.button_ok = QtGui.QPushButton(self.tr('OK'))
        print_dialog.buttonBox.addButton(
            print_dialog.button_ok,
            QtGui.QDialogButtonBox.ActionRole)

        print_dialog.button_ok.clicked.connect(print_dialog.accept)

        print_dialog.button_save_pdf.hide()
        print_dialog.button_open_composer.hide()

        if not print_dialog.exec_() == QtGui.QDialog.Accepted:
            self.show_dynamic_message(
                self,
                m.Message(
                    m.Heading(self.tr('Map Creator'), **WARNING_STYLE),
                    m.Text(self.tr('Report generation cancelled!'))))
            return

        # Get the extent of the map for report
        use_full_extent = print_dialog.analysis_extent_radio.isChecked()
        if use_full_extent:
            map_crs = self.iface.mapCanvas().mapRenderer().destinationCrs()
            layer_crs = self.iface.activeLayer().crs()
            layer_extent = self.iface.activeLayer().extent()
            if map_crs != layer_crs:
                # noinspection PyCallingNonCallable
                transform = QgsCoordinateTransform(layer_crs, map_crs)
                layer_extent = transform.transformBoundingBox(layer_extent)
            area_extent = layer_extent
        else:
            area_extent = self.iface.mapCanvas().extent()

        # Get selected template path to use
        if print_dialog.default_template_radio.isChecked():
            template_path = print_dialog.template_combo.itemData(
                print_dialog.template_combo.currentIndex())
        else:
            template_path = print_dialog.template_path.text()
            if not os.path.exists(template_path):
                # noinspection PyCallByClass,PyTypeChecker
                QtGui.QMessageBox.warning(
                    self.parent,
                    self.tr('InaSAFE'),
                    self.tr('Please select a valid template before printing. '
                            'The template you choose does not exist.'))
                return

        # Open in PDF or Open in Composer Flag (not used, the button is hidden
        #  by this class. The wizard has two its own buttons for Open In PDF
        # and Open In Composer buttons. Use variable 'mode' from param instead)
        create_pdf_flag = print_dialog.create_pdf

        # Instantiate and prepare Report
        self.show_dynamic_message(
            self,
            m.Message(
                m.Heading(self.tr('Map Creator'), **PROGRESS_UPDATE_STYLE),
                m.Text(self.tr('Preparing map and report'))))

        impact_report = ImpactReport(self.iface, template_path, impact_layer)
        impact_report.extent = area_extent

        # Get other setting
        settings = QSettings()
        logo_path = settings.value(
            'inasafe/organisation_logo_path', '', type=str)
        impact_report.organisation_logo = logo_path

        disclaimer_text = settings.value(
            'inasafe/reportDisclaimer', '', type=str)
        impact_report.disclaimer = disclaimer_text

        north_arrow_path = settings.value(
            'inasafe/north_arrow_path', '', type=str)
        impact_report.north_arrow = north_arrow_path

        template_warning_verbose = bool(settings.value(
            'inasafe/template_warning_verbose', True, type=bool))

        # Check if there's missing elements needed in the template
        component_ids = ['safe-logo', 'north-arrow', 'organisation-logo',
                         'impact-map', 'impact-legend']
        impact_report.component_ids = component_ids
        if template_warning_verbose and \
                        len(impact_report.missing_elements) != 0:
            title = self.tr('Template is missing some elements')
            question = self.tr(
                'The composer template you are printing to is missing '
                'these elements: %s. Do you still want to continue') % (
                    ', '.join(impact_report.missing_elements))
            # noinspection PyCallByClass,PyTypeChecker
            answer = QtGui.QMessageBox.question(
                self.parent,
                title,
                question,
                QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
            if answer == QtGui.QMessageBox.No:
                return

        create_pdf_flag = bool(mode == 'pdf')
        self.show_busy()
        if create_pdf_flag:
            self.print_map_to_pdf(impact_report)
        else:
            self.open_map_in_composer(impact_report)

        self.hide_busy()
    def test_earthquake_population_without_aggregation(self):
        """Testing Earthquake in Population without aggregation.

        .. versionadded:: 4.0
        """
        output_folder = self.fixtures_dir('../output/earthquake_population')

        # Classified vector with building-points
        shutil.rmtree(output_folder, ignore_errors=True)

        hazard_layer = load_test_raster_layer(
            'hazard', 'earthquake.tif')
        exposure_layer = load_test_raster_layer(
            'exposure', 'pop_binary_raster_20_20.asc')

        impact_function = ImpactFunction()
        impact_function.exposure = exposure_layer
        impact_function.hazard = hazard_layer
        impact_function.prepare()
        return_code, message = impact_function.run()

        self.assertEqual(return_code, ANALYSIS_SUCCESS, message)

        report_metadata = ReportMetadata(
            metadata_dict=standard_impact_report_metadata_html)

        impact_report = ImpactReport(
            IFACE,
            report_metadata,
            impact_function=impact_function)
        impact_report.output_folder = output_folder
        return_code, message = impact_report.process_components()

        self.assertEqual(
            return_code, ImpactReport.REPORT_GENERATION_SUCCESS, message)

        """Checking generated context"""
        empty_component_output_message = 'Empty component output'

        # Check Analysis Summary
        analysis_summary = impact_report.metadata.component_by_key(
            general_report_component['key'])
        """:type: safe.report.report_metadata.Jinja2ComponentsMetadata"""

        expected_context = {
            'table_header': (
                u'Estimated Number of people affected per MMI intensity'),
            'header': u'General Report',
            'summary': [
                {
                    'header_label': u'Hazard Zone',
                    'rows': [
                        {'value': 0, 'name': u'X', 'key': 'X'},
                        {'value': 0, 'name': u'IX', 'key': 'IX'},
                        {'value': '200', 'name': u'VIII', 'key': 'VIII'},
                        {'value': 0, 'name': u'VII', 'key': 'VII'},
                        {'value': 0, 'name': u'VI', 'key': 'VI'},
                        {'value': 0, 'name': u'V', 'key': 'V'},
                        {'value': 0, 'name': u'IV', 'key': 'IV'},
                        {'value': 0, 'name': u'III', 'key': 'III'},
                        {'value': 0, 'name': u'II', 'key': 'II'},
                        {'value': 0, 'name': u'I', 'key': 'I'},
                        {
                            'as_header': True,
                            'key': 'total_field',
                            'name': u'Total',
                            'value': '200'
                        }
                    ],
                    'value_label': u'Count'
                },
                {
                    'header_label': u'Population',
                    'rows': [
                        {
                            'value': '200',
                            'name': u'Affected',
                            'key': 'total_affected_field',
                        }, {
                            'key': 'total_not_affected_field',
                            'name': u'Not Affected',
                            'value': '0'
                        }, {
                            'key': 'total_not_exposed_field',
                            'name': u'Not Exposed',
                            'value': '0'},
                        {
                            'value': '200',
                            'name': u'Displaced',
                            'key': 'displaced_field'
                        }, {
                            'value': '0 - 100',
                            'name': u'Fatalities',
                            'key': 'fatalities_field'
                        }],
                    'value_label': u'Count'
                }
            ],
            'notes': [
                'Exposed People: People who are present in hazard zones and '
                'are thereby subject to potential losses. In InaSAFE, people '
                'who are exposed are those people who are within the extent '
                'of the hazard.',
                'Affected People: People who are affected by a hazardous '
                'event. People can be affected directly or indirectly. '
                'Affected people may experience short-term or long-term '
                'consequences to their lives, livelihoods or health and in '
                'the economic, physical, social, cultural and environmental '
                'assets. In InaSAFE, people who are killed during the event '
                'are also considered affected.',
                'Displaced People: Displaced people are people who, for '
                'different reasons and circumstances because of risk or '
                'disaster, have to leave their place of residence. '
                'In InaSAFE, demographic and minimum needs reports are based '
                'on displaced / evacuated people.'
            ]
        }
        actual_context = analysis_summary.context

        self.assertDictEqual(expected_context, actual_context)
        self.assertTrue(
            analysis_summary.output, empty_component_output_message)

        report_metadata = ReportMetadata(
            metadata_dict=infographic_report)
        infographic_impact_report = ImpactReport(
            IFACE,
            report_metadata,
            impact_function=impact_function)

        infographic_impact_report.output_folder = output_folder
        return_code, message = infographic_impact_report.process_components()

        self.assertEqual(
            return_code, ImpactReport.REPORT_GENERATION_SUCCESS, message)

        # check population pie chart if we have 100% donut slice
        population_chart_svg = (
            infographic_impact_report.metadata.component_by_key(
                population_chart_svg_component['key'])
        )

        expected_slices = [
            {
                'value': 200,
                'show_label': True,
                'center': (224.0, 128.0),
                'stroke_opacity': 1,
                'path': 'M128.000000,0.000000a128.000000,128.000000 0 0 1 '
                        '0.000000,256.000000l-0.000000,-64.000000a64.000000,'
                        '64.000000 0 0 0 0.000000,-128.000000Z',
                'percentage': 100,
                'label': u'VIII',
                'stroke': u'#ff7000',
                'label_position': (256, 0),
                'fill': u'#ff7000'
            }, {
                'value': 100,
                'show_label': False,
                'center': (32.0, 128.0),
                'stroke_opacity': 1,
                'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
                        '-0.000000,-256.000000l0.000000,64.000000a64.000000,'
                        '64.000000 0 0 0 0.000000,128.000000Z',
                'percentage': 50.0,
                'label': '',
                'stroke': u'#ff7000',
                'label_position': (256, 0),
                'fill': u'#ff7000'
            }, {
                'value': 0,
                'show_label': False,
                'center': (128.0, 224.0),
                'stroke_opacity': 1,
                'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
                        '0.000000,0.000000l-0.000000,-64.000000a64.000000,'
                        '64.000000 0 0 0 0.000000,0.000000Z',
                'percentage': 0.0,
                'label': u'Total Not Affected',
                'stroke': '#fff',
                'label_position': (256, 0),
                'fill': u'#1a9641'
            }]

        actual_context = population_chart_svg.context['context']
        actual_slices = actual_context.slices

        self.assertEqual(expected_slices, actual_slices)
        self.assertTrue(
            population_chart_svg.output, empty_component_output_message)

        shutil.rmtree(output_folder, ignore_errors=True)
Example #34
0
    def print_map(self, mode="pdf"):
        """Open impact report dialog that used to tune report when print map
            button pressed."""
        # Check if selected layer is valid
        impact_layer = self.iface.activeLayer()
        if impact_layer is None:
            # noinspection PyCallByClass,PyTypeChecker
            QtGui.QMessageBox.warning(
                self.parent, self.tr('InaSAFE'),
                self.tr('Please select a valid impact layer before '
                        'trying to print.'))
            return

        # Open Impact Report Dialog
        print_dialog = ImpactReportDialog(self.iface)
        print_dialog.button_ok = QtGui.QPushButton(self.tr('OK'))
        print_dialog.buttonBox.addButton(print_dialog.button_ok,
                                         QtGui.QDialogButtonBox.ActionRole)

        print_dialog.button_ok.clicked.connect(print_dialog.accept)

        print_dialog.button_save_pdf.hide()
        print_dialog.button_open_composer.hide()

        if not print_dialog.exec_() == QtGui.QDialog.Accepted:
            self.show_dynamic_message(
                self,
                m.Message(m.Heading(self.tr('Map Creator'), **WARNING_STYLE),
                          m.Text(self.tr('Report generation cancelled!'))))
            return

        # Get the extent of the map for report
        use_full_extent = print_dialog.analysis_extent_radio.isChecked()
        if use_full_extent:
            map_crs = self.iface.mapCanvas().mapRenderer().destinationCrs()
            layer_crs = self.iface.activeLayer().crs()
            layer_extent = self.iface.activeLayer().extent()
            if map_crs != layer_crs:
                # noinspection PyCallingNonCallable
                transform = QgsCoordinateTransform(layer_crs, map_crs)
                layer_extent = transform.transformBoundingBox(layer_extent)
            area_extent = layer_extent
        else:
            area_extent = self.iface.mapCanvas().extent()

        # Get selected template path to use
        if print_dialog.default_template_radio.isChecked():
            template_path = print_dialog.template_combo.itemData(
                print_dialog.template_combo.currentIndex())
        else:
            template_path = print_dialog.template_path.text()
            if not os.path.exists(template_path):
                # noinspection PyCallByClass,PyTypeChecker
                QtGui.QMessageBox.warning(
                    self.parent, self.tr('InaSAFE'),
                    self.tr('Please select a valid template before printing. '
                            'The template you choose does not exist.'))
                return

        # Open in PDF or Open in Composer Flag (not used, the button is hidden
        #  by this class. The wizard has two its own buttons for Open In PDF
        # and Open In Composer buttons. Use variable 'mode' from param instead)
        create_pdf_flag = print_dialog.create_pdf

        # Instantiate and prepare Report
        self.show_dynamic_message(
            self,
            m.Message(
                m.Heading(self.tr('Map Creator'), **PROGRESS_UPDATE_STYLE),
                m.Text(self.tr('Preparing map and report'))))

        impact_report = ImpactReport(self.iface, template_path, impact_layer)
        impact_report.extent = area_extent

        # Get other setting
        settings = QSettings()
        logo_path = settings.value('inasafe/organisation_logo_path',
                                   '',
                                   type=str)
        impact_report.organisation_logo = logo_path

        disclaimer_text = settings.value('inasafe/reportDisclaimer',
                                         '',
                                         type=str)
        impact_report.disclaimer = disclaimer_text

        north_arrow_path = settings.value('inasafe/north_arrow_path',
                                          '',
                                          type=str)
        impact_report.north_arrow = north_arrow_path

        template_warning_verbose = bool(
            settings.value('inasafe/template_warning_verbose', True,
                           type=bool))

        # Check if there's missing elements needed in the template
        component_ids = [
            'safe-logo', 'north-arrow', 'organisation-logo', 'impact-map',
            'impact-legend'
        ]
        impact_report.component_ids = component_ids
        if template_warning_verbose and \
                        len(impact_report.missing_elements) != 0:
            title = self.tr('Template is missing some elements')
            question = self.tr(
                'The composer template you are printing to is missing '
                'these elements: %s. Do you still want to continue') % (
                    ', '.join(impact_report.missing_elements))
            # noinspection PyCallByClass,PyTypeChecker
            answer = QtGui.QMessageBox.question(
                self.parent, title, question,
                QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
            if answer == QtGui.QMessageBox.No:
                return

        create_pdf_flag = bool(mode == 'pdf')
        self.show_busy()
        if create_pdf_flag:
            self.print_map_to_pdf(impact_report)
        else:
            self.open_map_in_composer(impact_report)

        self.hide_busy()
    def test_earthquake_population_without_aggregation(self):
        """Testing Earthquake in Population without aggregation.

        .. versionadded:: 4.0
        """
        output_folder = self.fixtures_dir('../output/earthquake_population')

        # Classified vector with building-points
        shutil.rmtree(output_folder, ignore_errors=True)

        hazard_layer = load_test_raster_layer('hazard', 'earthquake.tif')
        exposure_layer = load_test_raster_layer('exposure',
                                                'pop_binary_raster_20_20.asc')

        impact_function = ImpactFunction()
        impact_function.exposure = exposure_layer
        impact_function.hazard = hazard_layer
        impact_function.crs = QgsCoordinateReferenceSystem(4326)
        impact_function.prepare()
        return_code, message = impact_function.run()

        self.assertEqual(return_code, ANALYSIS_SUCCESS, message)

        report_metadata = ReportMetadata(
            metadata_dict=standard_impact_report_metadata_html)

        impact_report = ImpactReport(IFACE,
                                     report_metadata,
                                     impact_function=impact_function)
        impact_report.output_folder = output_folder
        return_code, message = impact_report.process_components()

        self.assertEqual(return_code, ImpactReport.REPORT_GENERATION_SUCCESS,
                         message)
        """Checking generated context."""
        empty_component_output_message = 'Empty component output'

        # Check Analysis Summary
        analysis_summary = impact_report.metadata.component_by_key(
            general_report_component['key'])
        """:type: safe.report.report_metadata.Jinja2ComponentsMetadata"""

        expected_context = {
            'table_header':
            (u'Estimated Number of people affected per MMI intensity'),
            'header':
            u'General Report',
            'summary': [{
                'header_label':
                u'Hazard Zone',
                'rows': [{
                    'numbers': ['0'],
                    'name': u'X',
                    'key': 'X'
                }, {
                    'numbers': ['0'],
                    'name': u'IX',
                    'key': 'IX'
                }, {
                    'numbers': ['200'],
                    'name': u'VIII',
                    'key': 'VIII'
                }, {
                    'numbers': ['0'],
                    'name': u'VII',
                    'key': 'VII'
                }, {
                    'numbers': ['0'],
                    'name': u'VI',
                    'key': 'VI'
                }, {
                    'numbers': ['0'],
                    'name': u'V',
                    'key': 'V'
                }, {
                    'numbers': ['0'],
                    'name': u'IV',
                    'key': 'IV'
                }, {
                    'numbers': ['0'],
                    'name': u'III',
                    'key': 'III'
                }, {
                    'numbers': ['0'],
                    'name': u'II',
                    'key': 'II'
                }, {
                    'numbers': ['0'],
                    'name': u'I',
                    'key': 'I'
                }, {
                    'as_header': True,
                    'key': 'total_exposed_field',
                    'name': u'Total Exposed',
                    'numbers': ['200']
                }],
                'value_labels': [u'Count']
            }, {
                'header_label':
                u'Population',
                'rows': [{
                    'numbers': ['200'],
                    'name': u'Affected',
                    'key': 'total_affected_field',
                }, {
                    'key': 'total_not_affected_field',
                    'name': u'Not Affected',
                    'numbers': ['0']
                }, {
                    'key': 'total_not_exposed_field',
                    'name': u'Not Exposed',
                    'numbers': ['0']
                }, {
                    'numbers': ['200'],
                    'name': u'Displaced',
                    'key': 'displaced_field'
                }, {
                    'numbers': ['0 - 100'],
                    'name': u'Fatalities',
                    'key': 'fatalities_field'
                }],
                'value_labels': [u'Count']
            }],
            'notes': [
                u'Exposed People: People who are present in hazard zones and '
                u'are thereby subject to potential losses. In InaSAFE, people '
                u'who are exposed are those people who are within the extent '
                u'of the hazard.',
                u'Affected People: People who are affected by a hazardous '
                u'event. People can be affected directly or indirectly. '
                u'Affected people may experience short-term or long-term '
                u'consequences to their lives, livelihoods or health and in '
                u'the economic, physical, social, cultural and environmental '
                u'assets. In InaSAFE, people who are killed during the event '
                u'are also considered affected.',
                u'Displaced People: Displaced people are people who, for '
                u'different reasons and circumstances because of risk or '
                u'disaster, have to leave their place of residence. '
                u'In InaSAFE, demographic and minimum needs reports are based '
                u'on displaced / evacuated people.'
            ]
        }
        actual_context = analysis_summary.context

        self.assertDictEqual(expected_context, actual_context)
        self.assertTrue(analysis_summary.output,
                        empty_component_output_message)

        report_metadata = ReportMetadata(metadata_dict=infographic_report)
        infographic_impact_report = ImpactReport(
            IFACE, report_metadata, impact_function=impact_function)

        infographic_impact_report.output_folder = output_folder
        return_code, message = infographic_impact_report.process_components()

        self.assertEqual(return_code, ImpactReport.REPORT_GENERATION_SUCCESS,
                         message)

        # check population pie chart if we have 100% donut slice
        population_chart_svg = (
            infographic_impact_report.metadata.component_by_key(
                population_chart_svg_component['key']))

        expected_slices = [{
            'value':
            200,
            'show_label':
            True,
            'center': (224.0, 128.0),
            'stroke_opacity':
            1,
            'path':
            'M128.000000,0.000000a128.000000,128.000000 0 0 1 '
            '0.000000,256.000000l-0.000000,-64.000000a64.000000,'
            '64.000000 0 0 0 0.000000,-128.000000Z',
            'percentage':
            100,
            'label':
            u'VIII',
            'stroke':
            u'#ff7000',
            'label_position': (256, 0),
            'fill':
            u'#ff7000'
        }, {
            'value':
            100,
            'show_label':
            False,
            'center': (32.0, 128.0),
            'stroke_opacity':
            1,
            'path':
            'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
            '-0.000000,-256.000000l0.000000,64.000000a64.000000,'
            '64.000000 0 0 0 0.000000,128.000000Z',
            'percentage':
            50.0,
            'label':
            '',
            'stroke':
            u'#ff7000',
            'label_position': (256, 0),
            'fill':
            u'#ff7000'
        }, {
            'value':
            0,
            'show_label':
            False,
            'center': (128.0, 224.0),
            'stroke_opacity':
            1,
            'path':
            'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
            '0.000000,0.000000l-0.000000,-64.000000a64.000000,'
            '64.000000 0 0 0 0.000000,0.000000Z',
            'percentage':
            0.0,
            'label':
            u'Total Not Affected',
            'stroke':
            '#fff',
            'label_position': (256, 0),
            'fill':
            u'#1a9641'
        }]

        actual_context = population_chart_svg.context['context']
        actual_slices = actual_context.slices

        self.assertEqual(expected_slices, actual_slices)
        self.assertTrue(population_chart_svg.output,
                        empty_component_output_message)

        shutil.rmtree(output_folder, ignore_errors=True)
Example #36
0
def generate_impact_map_report(impact_function, iface):
    """Generate impact map pdf from impact function.

    :param impact_function: The impact function used.
    :type impact_function: ImpactFunction

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface
    """
    # get the extra layers that we need
    extra_layers = []
    print_atlas = setting('print_atlas_report', False, bool)
    if print_atlas:
        extra_layers.append(impact_function.aggregation_summary)

    # get the hazard and exposure type
    hazard_layer = impact_function.hazard
    exposure_layer = impact_function.exposure

    hazard_type = layer_definition_type(hazard_layer)
    exposure_type = layer_definition_type(exposure_layer)

    # create impact report instance
    report_metadata = ReportMetadata(
        metadata_dict=update_template_component(
            component=map_report,
            hazard=hazard_type,
            exposure=exposure_type))
    impact_report = ImpactReport(
        iface,
        report_metadata,
        impact_function=impact_function,
        extra_layers=extra_layers)

    # Get other setting
    logo_path = setting('organisation_logo_path', None, str)
    impact_report.inasafe_context.organisation_logo = logo_path

    disclaimer_text = setting('reportDisclaimer', None, str)
    impact_report.inasafe_context.disclaimer = disclaimer_text

    north_arrow_path = setting('north_arrow_path', None, str)
    impact_report.inasafe_context.north_arrow = north_arrow_path

    # get the extent of impact layer
    impact_report.qgis_composition_context.extent = \
        impact_function.impact.extent()

    # generate report folder

    # no other option for now
    # TODO: retrieve the information from data store
    if isinstance(impact_function.datastore.uri, QDir):
        layer_dir = impact_function.datastore.uri.absolutePath()
    else:
        # No other way for now
        return

    # We will generate it on the fly without storing it after datastore
    # supports
    impact_report.output_folder = os.path.join(layer_dir, 'output')
    return impact_report.process_components()
    def test_earthquake_population_without_aggregation(self):
        """Testing Earthquake in Population without aggregation.

        .. versionadded:: 4.0
        """
        output_folder = self.fixtures_dir('../output/earthquake_population')

        # Classified vector with building-points
        shutil.rmtree(output_folder, ignore_errors=True)

        hazard_layer = load_test_raster_layer(
            'hazard', 'earthquake.tif')
        exposure_layer = load_test_raster_layer(
            'exposure', 'pop_binary_raster_20_20.asc')

        impact_function = ImpactFunction()
        impact_function.exposure = exposure_layer
        impact_function.hazard = hazard_layer
        impact_function.prepare()
        return_code, message = impact_function.run()

        self.assertEqual(return_code, ANALYSIS_SUCCESS, message)

        report_metadata = ReportMetadata(
            metadata_dict=standard_impact_report_metadata_html)

        impact_report = ImpactReport(
            IFACE,
            report_metadata,
            impact_function=impact_function)
        impact_report.output_folder = output_folder
        return_code, message = impact_report.process_component()

        self.assertEqual(
            return_code, ImpactReport.REPORT_GENERATION_SUCCESS, message)

        """Checking generated context"""
        empty_component_output_message = 'Empty component output'

        # Check Analysis Summary
        analysis_summary = impact_report.metadata.component_by_key(
            general_report_component['key'])
        """:type: safe.report.report_metadata.Jinja2ComponentsMetadata"""

        expected_context = {
            'table_header': u'Estimated Number of people',
            'header': u'General Report',
            'summary': [
                {
                    'header_label': u'Hazard Zone',
                    'rows': [{'value': '0', 'name': u'X', 'key': 'X'},
                             {'value': '0', 'name': u'IX', 'key': 'IX'},
                             {'value': '200', 'name': u'VIII', 'key': 'VIII'},
                             {'value': '0', 'name': u'VII', 'key': 'VII'},
                             {'value': '0', 'name': u'VI', 'key': 'VI'},
                             {'value': '0', 'name': u'V', 'key': 'V'},
                             {'value': '0', 'name': u'IV', 'key': 'IV'},
                             {'value': '0', 'name': u'III', 'key': 'III'},
                             {'value': '0', 'name': u'II', 'key': 'II'},
                             {'value': '0', 'name': u'I', 'key': 'I'}],
                    'value_label': u'Count'
                },
                {
                    'header_label': u'Population',
                    'rows': [{'value': '200',
                              'name': u'Displaced',
                              'key':
                                  'displaced_field'},
                             {'value': '0 - 100',
                              'name':
                                  u'Fatalities',
                              'key':
                                  'fatalities_field'}],
                    'value_label': u'Count'
                }
            ]
        }
        actual_context = analysis_summary.context

        self.assertDictEqual(expected_context, actual_context)
        self.assertTrue(
            analysis_summary.output, empty_component_output_message)

        # check population pie chart if we have 100% donut slice
        population_chart_svg = impact_report.metadata.component_by_key(
            population_chart_svg_component['key'])

        expected_slices = [
            {'value': 0, 'show_label': False, 'center': (128.0, 32.0),
             'stroke_opacity': 1,
             'path': 'M128.000000,0.000000a128.000000,128.000000 0 0 1 '
                     '0.000000,0.000000l-0.000000,64.000000a64.000000,'
                     '64.000000 0 0 0 0.000000,0.000000Z',
             'percentage': 0.0, 'label': u'X', 'stroke': '#fff',
             'label_position': (256, 0), 'fill': u'#dd0000'},
            {'value': 0, 'show_label': False, 'center': (128.0, 32.0),
             'stroke_opacity': 1,
             'path': 'M128.000000,0.000000a128.000000,128.000000 0 0 1 '
                     '0.000000,0.000000l-0.000000,64.000000a64.000000,'
                     '64.000000 0 0 0 0.000000,0.000000Z',
             'percentage': 0.0, 'label': u'IX', 'stroke': '#fff',
             'label_position': (256, 0), 'fill': u'#ff0000'},
            {'value': 200, 'show_label': True, 'center': (224.0, 128.0),
             'stroke_opacity': 1,
             'path': 'M128.000000,0.000000a128.000000,128.000000 0 0 1 '
                     '0.000000,256.000000l-0.000000,-64.000000a64.000000,'
                     '64.000000 0 0 0 0.000000,-128.000000Z',
             'percentage': 100, 'label': u'VIII', 'stroke': u'#ff7000',
             'label_position': (256, 0), 'fill': u'#ff7000'},
            {'value': 100, 'show_label': False, 'center': (32.0, 128.0),
             'stroke_opacity': 1,
             'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
                     '-0.000000,-256.000000l0.000000,64.000000a64.000000,'
                     '64.000000 0 0 0 0.000000,128.000000Z',
             'percentage': 50.0, 'label': '', 'stroke': u'#ff7000',
             'label_position': (256, 0), 'fill': u'#ff7000'},
            {'value': 0, 'show_label': False, 'center': (128.0, 224.0),
             'stroke_opacity': 1,
             'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
                     '0.000000,0.000000l-0.000000,-64.000000a64.000000,'
                     '64.000000 0 0 0 0.000000,0.000000Z',
             'percentage': 0.0, 'label': u'VII', 'stroke': '#fff',
             'label_position': (256, 0), 'fill': u'#ffa800'},
            {'value': 0, 'show_label': False, 'center': (128.0, 224.0),
             'stroke_opacity': 1,
             'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
                     '0.000000,0.000000l-0.000000,-64.000000a64.000000,'
                     '64.000000 0 0 0 0.000000,0.000000Z',
             'percentage': 0.0, 'label': u'VI', 'stroke': '#fff',
             'label_position': (256, 0), 'fill': u'#fff000'},
            {'value': 0, 'show_label': False, 'center': (128.0, 224.0),
             'stroke_opacity': 1,
             'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
                     '0.000000,0.000000l-0.000000,-64.000000a64.000000,'
                     '64.000000 0 0 0 0.000000,0.000000Z',
             'percentage': 0.0, 'label': u'V', 'stroke': '#fff',
             'label_position': (256, 0), 'fill': u'#aaffff'},
            {'value': 0, 'show_label': False, 'center': (128.0, 224.0),
             'stroke_opacity': 1,
             'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
                     '0.000000,0.000000l-0.000000,-64.000000a64.000000,'
                     '64.000000 0 0 0 0.000000,0.000000Z',
             'percentage': 0.0, 'label': u'IV', 'stroke': '#fff',
             'label_position': (256, 0), 'fill': u'#55ffff'},
            {'value': 0, 'show_label': False, 'center': (128.0, 224.0),
             'stroke_opacity': 1,
             'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
                     '0.000000,0.000000l-0.000000,-64.000000a64.000000,'
                     '64.000000 0 0 0 0.000000,0.000000Z',
             'percentage': 0.0, 'label': u'III', 'stroke': '#fff',
             'label_position': (256, 0), 'fill': u'#00cfff'},
            {'value': 0, 'show_label': False, 'center': (128.0, 224.0),
             'stroke_opacity': 1,
             'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 '
                     '0.000000,0.000000l-0.000000,-64.000000a64.000000,'
                     '64.000000 0 0 0 0.000000,0.000000Z',
             'percentage': 0.0, 'label': u'II', 'stroke': '#fff',
             'label_position': (256, 0), 'fill': u'#209fff'}]

        actual_context = population_chart_svg.context['context']
        actual_slices = actual_context.slices

        self.assertEqual(expected_slices, actual_slices)
        self.assertTrue(
            population_chart_svg.output, empty_component_output_message)

        shutil.rmtree(output_folder, ignore_errors=True)