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