def test_result_styling(self): """Test that ouputs from a model are correctly styled (colours and opacity. """ # Push OK with the left mouse button print '--------------------' print combos_to_string(DOCK) result, message = setup_scenario( DOCK, hazard='A flood in Jakarta like in 2007', exposure='People', function='Need evacuation', function_id='Flood Evacuation Function') self.assertTrue(result, message) # Enable on-the-fly reprojection set_canvas_crs(GEOCRS, True) set_jakarta_extent(DOCK) DOCK.accept() # DOCK.analysis.get_impact_layer() safe_layer = DOCK.analysis.get_impact_layer() qgis_layer = read_impact_layer(safe_layer) style = safe_layer.get_style_info() setRasterStyle(qgis_layer, style) # simple test for now - we could test explicity for style state # later if needed. message = ('Raster layer was not assigned a Singleband pseudocolor' ' renderer as expected.') self.assertTrue( qgis_layer.renderer().type() == 'singlebandpseudocolor', message)
def completed(self, zero_impact): """Slot activated when the process is done. :param zero_impact: Flag for zero impact. :type zero_impact: bool .. note:: Adapted from the dock """ # Try to run completion code # Show the result in the dock from layer if there is an impact. if not zero_impact: try: from datetime import datetime LOGGER.debug(datetime.now()) LOGGER.debug('get engine impact layer') LOGGER.debug(self.impact_function is None) # Load impact layer into QGIS qgis_impact_layer = read_impact_layer( self.impact_function.impact) report = self.show_results() except Exception, e: # pylint: disable=W0703 # FIXME (Ole): This branch is not covered by the tests self.analysis_error(e, self.tr('Error loading impact layer.')) else: # On success, display generated report impact_path = qgis_impact_layer.source() message = m.Message(report) # noinspection PyTypeChecker send_static_message(self, message) self.parent.step_fc_analysis.wvResults.impact_path = \ impact_path
def test_result_styling(self): """Test that colours and opacity from a model are correctly styled.""" # Push OK with the left mouse button print '--------------------' print combos_to_string(self.dock) result, message = setup_scenario( self.dock, hazard='Continuous Flood', exposure='Population', function='Need evacuation', function_id='FloodEvacuationRasterHazardFunction') self.assertTrue(result, message) # Enable on-the-fly reprojection set_canvas_crs(GEOCRS, True) set_jakarta_extent(self.dock) self.dock.accept() # self.dock.analysis.get_impact_layer() safe_layer = self.dock.analysis.impact_layer qgis_layer = read_impact_layer(safe_layer) style = safe_layer.get_style_info() setRasterStyle(qgis_layer, style) # simple test for now - we could test explicity for style state # later if needed. message = ( 'Raster layer was not assigned a Singleband pseudocolor' ' renderer as expected.') self.assertTrue( qgis_layer.renderer().type() == 'singlebandpseudocolor', message)
def test_result_styling(self): """Test that colours and opacity from a model are correctly styled.""" settings = QtCore.QSettings() settings.setValue('inasafe/analysis_extents_mode', 'HazardExposure') result, message = setup_scenario( self.dock, hazard='Continuous Flood', exposure='Population', function='Need evacuation', function_id='FloodEvacuationRasterHazardFunction') self.assertTrue(result, message) # Enable on-the-fly reprojection set_canvas_crs(GEOCRS, True) set_jakarta_extent(self.dock) self.dock.accept() safe_layer = self.dock.impact_function.impact qgis_layer = read_impact_layer(safe_layer) style = safe_layer.get_style_info() setRasterStyle(qgis_layer, style) # simple test for now - we could test explicitly for style state # later if needed. message = ( 'Raster layer was not assigned a Singleband pseudocolor ' 'renderer as expected.') self.assertEquals( qgis_layer.renderer().type(), 'singlebandpseudocolor', message)
def test_result_styling(self): """Test that colours and opacity from a model are correctly styled.""" settings = QtCore.QSettings() settings.setValue('inasafe/analysis_extents_mode', 'HazardExposure') result, message = setup_scenario( self.dock, hazard='Continuous Flood', exposure='Population', function='Need evacuation', function_id='FloodEvacuationRasterHazardFunction') self.assertTrue(result, message) # Enable on-the-fly reprojection set_canvas_crs(GEOCRS, True) set_jakarta_extent(self.dock) self.dock.accept() safe_layer = self.dock.impact_function.impact qgis_layer = read_impact_layer(safe_layer) style = safe_layer.get_style_info() setRasterStyle(qgis_layer, style) # simple test for now - we could test explicitly for style state # later if needed. message = ('Raster layer was not assigned a Singleband pseudocolor ' 'renderer as expected.') self.assertEquals(qgis_layer.renderer().type(), 'singlebandpseudocolor', message)
def completed(self, zero_impact): """Slot activated when the process is done. :param zero_impact: Flag for zero impact. :type zero_impact: bool .. note:: Adapted from the dock """ # Try to run completion code # Show the result in the dock from layer if there is an impact. if not zero_impact: try: from datetime import datetime LOGGER.debug(datetime.now()) LOGGER.debug('get engine impact layer') LOGGER.debug(self.impact_function is None) # Load impact layer into QGIS qgis_impact_layer = read_impact_layer( self.impact_function.impact) report = self.show_results() except Exception, e: # pylint: disable=W0703 # FIXME (Ole): This branch is not covered by the tests self.analysis_error(e, self.tr('Error loading impact layer.')) else: # On success, display generated report impact_path = qgis_impact_layer.source() message = m.Message(report) # noinspection PyTypeChecker send_static_message(self, message) self.parent.step_fc_analysis.wvResults.impact_path = \ impact_path
def completed(self): """Slot activated when the process is done. .. note:: Adapted from the dock """ # Try to run completion code try: from datetime import datetime LOGGER.debug(datetime.now()) LOGGER.debug('get engine impact layer') LOGGER.debug(self.impact_function is None) # Load impact layer into QGIS qgis_impact_layer = read_impact_layer(self.impact_function.impact) report = self.show_results() except Exception, e: # pylint: disable=W0703 # FIXME (Ole): This branch is not covered by the tests self.analysis_error(e, self.tr('Error loading impact layer.'))
def completed(self): """Slot activated when the process is done. .. note:: Adapted from the dock """ # Try to run completion code try: from datetime import datetime LOGGER.debug(datetime.now()) LOGGER.debug('get engine impact layer') LOGGER.debug(self.analysis is None) engine_impact_layer = self.analysis.get_impact_layer() # Load impact layer into QGIS qgis_impact_layer = read_impact_layer(engine_impact_layer) report = self.show_results(qgis_impact_layer, engine_impact_layer) except Exception, e: # pylint: disable=W0703 # FIXME (Ole): This branch is not covered by the tests self.analysis_error(e, self.tr('Error loading impact layer.'))
def show_results(self): """Helper function for slot activated when the process is done. .. versionchanged:: 3.4 - removed parameters. .. note:: If you update this function, please report your change to safe.gui.widgets.dock.show_results too. :returns: Provides a report for writing to the dock. :rtype: str """ qgis_exposure = self.impact_function.exposure.qgis_layer() qgis_hazard = self.impact_function.hazard.qgis_layer() qgis_aggregation = self.impact_function.aggregation.qgis_layer() safe_impact_layer = self.impact_function.impact qgis_impact_layer = read_impact_layer(safe_impact_layer) keywords = self.keyword_io.read_keywords(qgis_impact_layer) json_path = os.path.splitext(qgis_impact_layer.source())[0] + '.json' # write postprocessing report to keyword postprocessor_data = self.impact_function.postprocessor_manager.\ get_json_data(self.impact_function.aggregator.aoi_mode) post_processing_report = m.Message() if os.path.exists(json_path): with open(json_path) as json_file: impact_data = json.load( json_file, object_pairs_hook=OrderedDict) impact_data['post processing'] = postprocessor_data with open(json_path, 'w') as json_file_2: json.dump(impact_data, json_file_2, indent=2) else: post_processing_report = self.impact_function.\ postprocessor_manager.get_output( self.impact_function.aggregator.aoi_mode) keywords['postprocessing_report'] = post_processing_report.to_html( suppress_newlines=True) self.keyword_io.write_keywords(qgis_impact_layer, keywords) # Get tabular information from impact layer report = m.Message() report.add(LOGO_ELEMENT) report.add(m.Heading(self.tr('Analysis Results'), **INFO_STYLE)) # If JSON Impact Data Exist, use JSON json_path = qgis_impact_layer.source()[:-3] + 'json' LOGGER.debug('JSON Path %s' % json_path) if os.path.exists(json_path): impact_template = get_report_template(json_file=json_path) impact_report = impact_template.generate_message_report() report.add(impact_report) else: report.add(self.keyword_io.read_keywords( qgis_impact_layer, 'impact_summary')) # append postprocessing report report.add(post_processing_report.to_html()) # Layer attribution comes last report.add(impact_attribution(keywords).to_html(True)) # Get requested style for impact layer of either kind style = safe_impact_layer.get_style_info() style_type = safe_impact_layer.get_style_type() # Determine styling for QGIS layer if safe_impact_layer.is_vector: if not style: # Set default style if possible pass elif style_type == 'categorizedSymbol': LOGGER.debug('use categorized') set_vector_categorized_style(qgis_impact_layer, style) elif style_type == 'graduatedSymbol': LOGGER.debug('use graduated') set_vector_graduated_style(qgis_impact_layer, style) elif safe_impact_layer.is_raster: if not style: qgis_impact_layer.setDrawingStyle("SingleBandPseudoColor") else: setRasterStyle(qgis_impact_layer, style) else: message = self.tr( 'Impact layer %s was neither a raster or a vector layer') % ( qgis_impact_layer.source()) # noinspection PyExceptionInherit raise ReadLayerError(message) legend = self.iface.legendInterface() # Insert the aggregation output above the input aggregation layer if self.show_intermediate_layers: add_above_layer( self.impact_function.aggregator.layer, qgis_aggregation) legend.setLayerVisible(self.impact_function.aggregator.layer, True) if self.hide_exposure_flag: # Insert the impact always above the hazard add_above_layer( qgis_impact_layer, qgis_hazard) else: # Insert the impact above the hazard and the exposure if # we don't hide the exposure. See #2899 add_above_layer( qgis_impact_layer, qgis_exposure, qgis_hazard) # In QGIS 2.14.2 and GDAL 1.11.3, if the exposure is in 3857, # the impact layer is in 54004, we need to change it. See issue #2790. if qgis_exposure.crs().authid() == 'EPSG:3857': if qgis_impact_layer.crs().authid() != 'EPSG:3857': epsg_3857 = QgsCoordinateReferenceSystem(3857) qgis_impact_layer.setCrs(epsg_3857) # make sure it is active in the legend - needed since QGIS 2.4 self.iface.setActiveLayer(qgis_impact_layer) # then zoom to it if self.zoom_to_impact_flag: self.iface.zoomToActiveLayer() if self.hide_exposure_flag: exposure_layer = self.get_exposure_layer() legend.setLayerVisible(exposure_layer, False) # Make the layer visible. Might be hidden by default. See #2925 legend.setLayerVisible(qgis_impact_layer, True) # Return text to display in report panel return report
def run_task(self, task_item, status_item, count=0, index=''): """Run a single task. :param task_item: Table task_item containing task name / details. :type task_item: QTableWidgetItem :param status_item: Table task_item that holds the task status. :type status_item: QTableWidgetItem :param count: Count of scenarios that have been run already. :type count: :param index: The index for the table item that will be run. :type index: int :returns: Flag indicating if the task succeeded or not. :rtype: bool """ self.enable_busy_cursor() # set status to 'running' status_item.setText(self.tr('Running')) # .. see also:: :func:`appendRow` to understand the next 2 lines variant = task_item.data(QtCore.Qt.UserRole) value = variant[0] result = True if isinstance(value, str): filename = value # run script try: self.run_script(filename) # set status to 'OK' status_item.setText(self.tr('Script OK')) except Exception as e: # pylint: disable=W0703 # set status to 'fail' status_item.setText(self.tr('Script Fail')) LOGGER.exception('Running macro failed. The exception: ' + str(e)) result = False elif isinstance(value, dict): path = str(self.output_directory.text()) title = str(task_item.text()) # Its a dict containing files for a scenario result = self.run_scenario(value) if not result: status_item.setText(self.tr('Analysis Fail')) else: # NOTE(gigih): # Usually after analysis is done, the impact layer # become the active layer. <--- WRONG # noinspection PyUnresolvedReferences impact_layer = self.dock.analysis.get_impact_layer() # Load impact layer into QGIS qgis_layer = read_impact_layer(impact_layer) QgsMapLayerRegistry.instance().addMapLayer( qgis_layer, addToLegend=False) # noinspection PyBroadException try: status_item.setText(self.tr('Analysis Ok')) self.create_pdf( title, path, qgis_layer, count, index) status_item.setText(self.tr('Report Ok')) except Exception: # pylint: disable=W0703 LOGGER.exception('Unable to render map: "%s"' % value) status_item.setText(self.tr('Report Failed')) result = False else: LOGGER.exception('Data type not supported: "%s"' % value) result = False self.disable_busy_cursor() return result
def run_task(self, task_item, status_item, count=0, index=''): """Run a single task. :param task_item: Table task_item containing task name / details. :type task_item: QTableWidgetItem :param status_item: Table task_item that holds the task status. :type status_item: QTableWidgetItem :param count: Count of scenarios that have been run already. :type count: :param index: The index for the table item that will be run. :type index: int :returns: Flag indicating if the task succeeded or not. :rtype: bool """ self.enable_busy_cursor() # set status to 'running' status_item.setText(self.tr('Running')) # .. see also:: :func:`appendRow` to understand the next 2 lines variant = task_item.data(QtCore.Qt.UserRole) value = variant[0] result = True if isinstance(value, str): filename = value # run script try: self.run_script(filename) # set status to 'OK' status_item.setText(self.tr('Script OK')) except Exception as e: # pylint: disable=W0703 # set status to 'fail' status_item.setText(self.tr('Script Fail')) LOGGER.exception('Running macro failed. The exception: ' + str(e)) result = False elif isinstance(value, dict): path = str(self.output_directory.text()) title = str(task_item.text()) # Its a dict containing files for a scenario result = self.run_scenario(value) if not result: status_item.setText(self.tr('Analysis Fail')) else: # NOTE(gigih): # Usually after analysis is done, the impact layer # become the active layer. <--- WRONG # noinspection PyUnresolvedReferences impact_layer = self.dock.analysis.impact_layer # Load impact layer into QGIS qgis_layer = read_impact_layer(impact_layer) QgsMapLayerRegistry.instance().addMapLayer( qgis_layer, addToLegend=False) # noinspection PyBroadException try: status_item.setText(self.tr('Analysis Ok')) self.create_pdf( title, path, qgis_layer, count, index) status_item.setText(self.tr('Report Ok')) except Exception: # pylint: disable=W0703 LOGGER.exception('Unable to render map: "%s"' % value) status_item.setText(self.tr('Report Failed')) result = False else: LOGGER.exception('Data type not supported: "%s"' % value) result = False self.disable_busy_cursor() return result
def show_results(self): """Helper function for slot activated when the process is done. .. versionchanged:: 3.4 - removed parameters. .. note:: If you update this function, please report your change to safe.gui.widgets.dock.show_results too. :returns: Provides a report for writing to the dock. :rtype: str """ qgis_exposure = self.impact_function.exposure.qgis_layer() qgis_hazard = self.impact_function.hazard.qgis_layer() qgis_aggregation = self.impact_function.aggregation.qgis_layer() safe_impact_layer = self.impact_function.impact qgis_impact_layer = read_impact_layer(safe_impact_layer) keywords = self.keyword_io.read_keywords(qgis_impact_layer) json_path = os.path.splitext(qgis_impact_layer.source())[0] + '.json' # write postprocessing report to keyword postprocessor_data = self.impact_function.postprocessor_manager.\ get_json_data(self.impact_function.aggregator.aoi_mode) post_processing_report = m.Message() if os.path.exists(json_path): with open(json_path) as json_file: impact_data = json.load(json_file, object_pairs_hook=OrderedDict) impact_data['post processing'] = postprocessor_data write_json(impact_data, json_path) else: post_processing_report = self.impact_function.\ postprocessor_manager.get_output( self.impact_function.aggregator.aoi_mode) keywords['postprocessing_report'] = post_processing_report.to_html( suppress_newlines=True) self.keyword_io.write_keywords(qgis_impact_layer, keywords) # Get tabular information from impact layer report = m.Message() report.add(LOGO_ELEMENT) report.add(m.Heading(self.tr('Analysis Results'), **INFO_STYLE)) # If JSON Impact Data Exist, use JSON json_path = qgis_impact_layer.source()[:-3] + 'json' LOGGER.debug('JSON Path %s' % json_path) if os.path.exists(json_path): impact_template = get_report_template(json_file=json_path) impact_report = impact_template.generate_message_report() report.add(impact_report) else: report.add( self.keyword_io.read_keywords(qgis_impact_layer, 'impact_summary')) # append postprocessing report report.add(post_processing_report.to_html()) # Layer attribution comes last report.add(impact_attribution(keywords).to_html(True)) # Get requested style for impact layer of either kind style = safe_impact_layer.get_style_info() style_type = safe_impact_layer.get_style_type() # Determine styling for QGIS layer if safe_impact_layer.is_vector: if not style: # Set default style if possible pass elif style_type == 'categorizedSymbol': LOGGER.debug('use categorized') set_vector_categorized_style(qgis_impact_layer, style) elif style_type == 'graduatedSymbol': LOGGER.debug('use graduated') set_vector_graduated_style(qgis_impact_layer, style) elif safe_impact_layer.is_raster: if not style: qgis_impact_layer.setDrawingStyle("SingleBandPseudoColor") else: setRasterStyle(qgis_impact_layer, style) else: message = self.tr( 'Impact layer %s was neither a raster or a vector layer') % ( qgis_impact_layer.source()) # noinspection PyExceptionInherit raise ReadLayerError(message) legend = self.iface.legendInterface() # Insert the aggregation output above the input aggregation layer if self.show_intermediate_layers: add_above_layer(self.impact_function.aggregator.layer, qgis_aggregation) legend.setLayerVisible(self.impact_function.aggregator.layer, True) if self.hide_exposure_flag: # Insert the impact always above the hazard add_above_layer(qgis_impact_layer, qgis_hazard) else: # Insert the impact above the hazard and the exposure if # we don't hide the exposure. See #2899 add_above_layer(qgis_impact_layer, qgis_exposure, qgis_hazard) # In QGIS 2.14.2 and GDAL 1.11.3, if the exposure is in 3857, # the impact layer is in 54004, we need to change it. See issue #2790. if qgis_exposure.crs().authid() == 'EPSG:3857': if qgis_impact_layer.crs().authid() != 'EPSG:3857': epsg_3857 = QgsCoordinateReferenceSystem(3857) qgis_impact_layer.setCrs(epsg_3857) # make sure it is active in the legend - needed since QGIS 2.4 self.iface.setActiveLayer(qgis_impact_layer) # then zoom to it if self.zoom_to_impact_flag: self.iface.zoomToActiveLayer() if self.hide_exposure_flag: exposure_layer = self.get_exposure_layer() legend.setLayerVisible(exposure_layer, False) # Make the layer visible. Might be hidden by default. See #2925 legend.setLayerVisible(qgis_impact_layer, True) # Return text to display in report panel return report