def exposure_summary_layer(): """Helper method for retrieving exposure summary layer. If the analysis is multi-exposure, then it will return the exposure summary layer from place exposure analysis. """ project_context_scope = QgsExpressionContextUtils.projectScope( QgsProject.instance()) project = QgsProject.instance() key = provenance_layer_analysis_impacted_id['provenance_key'] analysis_summary_layer = project.mapLayer( project_context_scope.variable(key)) if not analysis_summary_layer: key = provenance_layer_analysis_impacted['provenance_key'] if project_context_scope.hasVariable(key): analysis_summary_layer = load_layer( project_context_scope.variable(key))[0] if not analysis_summary_layer: return None keywords = KeywordIO.read_keywords(analysis_summary_layer) extra_keywords = keywords.get(property_extra_keywords['key'], {}) is_multi_exposure = extra_keywords.get(extra_keyword_analysis_type['key']) key = provenance_layer_exposure_summary_id['provenance_key'] if is_multi_exposure: key = ('{provenance}__{exposure}').format( provenance=provenance_multi_exposure_summary_layers_id[ 'provenance_key'], exposure=exposure_place['key']) if not project_context_scope.hasVariable(key): return None exposure_summary_layer = project.mapLayer( project_context_scope.variable(key)) if not exposure_summary_layer: key = provenance_layer_exposure_summary['provenance_key'] if is_multi_exposure: key = ('{provenance}__{exposure}').format( provenance=provenance_multi_exposure_summary_layers[ 'provenance_key'], exposure=exposure_place['key']) if project_context_scope.hasVariable(key): exposure_summary_layer = load_layer( project_context_scope.variable(key))[0] else: return None return exposure_summary_layer
def exposure_summary_layer(): """Helper method for retrieving exposure summary layer. If the analysis is multi-exposure, then it will return the exposure summary layer from place exposure analysis. """ project_context_scope = QgsExpressionContextUtils.projectScope( QgsProject.instance()) project = QgsProject.instance() key = provenance_layer_analysis_impacted_id['provenance_key'] analysis_summary_layer = project.mapLayer( project_context_scope.variable(key)) if not analysis_summary_layer: key = provenance_layer_analysis_impacted['provenance_key'] if project_context_scope.hasVariable(key): analysis_summary_layer = load_layer( project_context_scope.variable(key))[0] if not analysis_summary_layer: return None keywords = KeywordIO.read_keywords(analysis_summary_layer) extra_keywords = keywords.get(property_extra_keywords['key'], {}) is_multi_exposure = extra_keywords.get(extra_keyword_analysis_type['key']) key = provenance_layer_exposure_summary_id['provenance_key'] if is_multi_exposure: key = ('{provenance}__{exposure}').format( provenance=provenance_multi_exposure_summary_layers_id[ 'provenance_key'], exposure=exposure_place['key']) if not project_context_scope.hasVariable(key): return None exposure_summary_layer = project.mapLayer( project_context_scope.variable(key)) if not exposure_summary_layer: key = provenance_layer_exposure_summary['provenance_key'] if is_multi_exposure: key = ('{provenance}__{exposure}').format( provenance=provenance_multi_exposure_summary_layers[ 'provenance_key'], exposure=exposure_place['key']) if project_context_scope.hasVariable(key): exposure_summary_layer = load_layer( project_context_scope.variable(key))[0] else: return None return exposure_summary_layer
def test_layer_hazard_classification(self): """Test layer_hazard_classification method. .. versionadded:: 4.0 """ layer_paths = self.layer_paths_list expected_classifications = [ generic_hazard_classes, earthquake_mmi_scale, tsunami_hazard_classes, cyclone_au_bom_hazard_classes, None, None, None, None, ] for layer_path, expected_classification in zip( layer_paths, expected_classifications): path = standard_data_path(*layer_path) layer, _ = load_layer(path) # inject classification keyword if expected_classification: layer.keywords['classification'] = ( expected_classification['key']) actual_classification = layer_hazard_classification(layer) try: self.assertEqual(expected_classification, actual_classification) except Exception as e: LOGGER.error('Layer path: {path}'.format(path=path)) LOGGER.error( 'Expected {name}'.format(**expected_classification)) LOGGER.error('Actual {name}'.format(**actual_classification)) raise e
def hazard_extra_keyword(keyword, feature, parent): """Given a keyword, it will return the value of the keyword from the hazard layer's extra keywords. For instance: * hazard_extra_keyword( 'depth' ) -> will return the value of 'depth' in current hazard layer's extra keywords. """ _ = feature, parent # NOQA hazard_layer_path = QgsExpressionContextUtils. \ projectScope(QgsProject.instance()).variable( 'hazard_layer') hazard_layer = load_layer(hazard_layer_path)[0] keywords = KeywordIO.read_keywords(hazard_layer) extra_keywords = keywords.get('extra_keywords') if extra_keywords: value = extra_keywords.get(keyword) if value: value_definition = definition(value) if value_definition: return value_definition['name'] return value else: return tr('Keyword %s is not found' % keyword) return tr('No extra keywords found')
def test_retrieve_exposure_classes_lists(self): """Test retrieve_exposure_classes_lists method. .. versionadded:: 4.0 """ layer_paths = self.layer_paths_list expected_classes_lists = [ None, None, None, None, generic_structure_classes['classes'], generic_structure_classes['classes'], None, generic_road_classes['classes'] ] for layer_path, expected_classes in zip(layer_paths, expected_classes_lists): path = standard_data_path(*layer_path) layer, _ = load_layer(path) actual_classes = retrieve_exposure_classes_lists(layer.keywords) try: self.assertEqual(expected_classes, actual_classes) except Exception as e: LOGGER.error('Layer path: {path}'.format(path=path)) LOGGER.error( 'Expected {classes}'.format(classes=expected_classes)) LOGGER.error('Actual {classes}'.format(classes=actual_classes)) raise e
def hazard_extra_keyword(keyword, feature, parent): """Given a keyword, it will return the value of the keyword from the hazard layer's extra keywords. For instance: * hazard_extra_keyword( 'depth' ) -> will return the value of 'depth' in current hazard layer's extra keywords. """ _ = feature, parent # NOQA hazard_layer_path = QgsExpressionContextUtils. \ projectScope(QgsProject.instance()).variable( 'hazard_layer') hazard_layer = load_layer(hazard_layer_path)[0] keywords = KeywordIO.read_keywords(hazard_layer) extra_keywords = keywords.get('extra_keywords') if extra_keywords: value = extra_keywords.get(keyword) if value: value_definition = definition(value) if value_definition: return value_definition['name'] return value else: return tr('Keyword %s is not found' % keyword) return tr('No extra keywords found')
def test_layer_definition_type(self): """Test layer_definition_type method. .. versionadded:: 4.0 """ layer_paths = self.layer_paths_list expected_definitions = [ hazard_generic, hazard_earthquake, hazard_tsunami, hazard_cyclone, exposure_structure, exposure_structure, exposure_population, exposure_road, ] for layer_path, expected_definition in zip(layer_paths, expected_definitions): path = standard_data_path(*layer_path) layer, _ = load_layer(path) actual_definition = layer_definition_type(layer) try: self.assertEqual(expected_definition, actual_definition) except Exception as e: LOGGER.error('Layer path: {path}'.format(path=path)) LOGGER.error('Expected {name}'.format(**expected_definition)) LOGGER.error('Actual {name}'.format(**actual_definition)) raise e
def test_load_layer_from_uri(self): """Test we can load a layer with different parameters.""" # Without provider path = standard_data_path( 'gisv4', 'aggregation', 'small_grid.geojson') layer, purpose = load_layer(path) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'small_grid') self.assertEqual(purpose, 'aggregation') layer, purpose = load_layer(path, 'foo') self.assertEqual(layer.name(), 'foo') # With internal URI internal_uri = full_layer_uri(layer) self.assertTrue( internal_uri.endswith('small_grid.geojson|qgis_provider=ogr'), internal_uri ) layer, purpose = load_layer(full_layer_uri(layer)) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'small_grid') self.assertEqual(purpose, 'aggregation') # path plus extra layer parameter path = standard_data_path( 'gisv4', 'aggregation', 'small_grid.geojson') path += '|layerid=0' layer, purpose = load_layer(path) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'small_grid') self.assertEqual(purpose, 'aggregation') # CSV path = standard_data_path( 'gisv4', 'impacts', 'exposure_summary_table.csv') layer, purpose = load_layer(path) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'exposure_summary_table') self.assertEqual(purpose, 'undefined') self.assertEqual(len(layer.fields()), 4)
def test_load_layer_from_uri(self): """Test we can load a layer with different parameters.""" # Without provider path = standard_data_path('gisv4', 'aggregation', 'small_grid.geojson') layer, purpose = load_layer(path) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'small_grid') self.assertEqual(purpose, 'aggregation') layer, purpose = load_layer(path, 'foo') self.assertEqual(layer.name(), 'foo') # With internal URI internal_uri = full_layer_uri(layer) self.assertTrue( internal_uri.endswith('small_grid.geojson|qgis_provider=ogr'), internal_uri) layer, purpose = load_layer(full_layer_uri(layer)) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'small_grid') self.assertEqual(purpose, 'aggregation') # path plus extra layer parameter path = standard_data_path('gisv4', 'aggregation', 'small_grid.geojson') path += '|layerid=0' layer, purpose = load_layer(path) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'small_grid') self.assertEqual(purpose, 'aggregation') # CSV path = standard_data_path('gisv4', 'impacts', 'exposure_summary_table.csv') layer, purpose = load_layer(path) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'exposure_summary_table') self.assertEqual(purpose, 'undefined') self.assertEqual(len(layer.fields()), 4)
def earthquake_contour_preprocessor(impact_function): """Preprocessor to create contour from an earthquake :param impact_function: Impact function to run. :type impact_function: ImpactFunction :return: The contour layer. :rtype: QgsMapLayer """ contour_path = create_smooth_contour(impact_function.hazard) if os.path.exists(contour_path): from safe.gis.tools import load_layer return load_layer(contour_path, tr('Contour'), 'ogr')[0]
def earthquake_contour_preprocessor(impact_function): """Preprocessor to create contour from an earthquake :param impact_function: Impact function to run. :type impact_function: ImpactFunction :return: The contour layer. :rtype: QgsMapLayer """ contour_path = create_smooth_contour(impact_function.hazard) if os.path.exists(contour_path): from safe.gis.tools import load_layer return load_layer(contour_path, tr('Contour'), 'ogr')[0]
def load_layers( layer_list, clear_flag=True, dock=None): """Helper function to load layers as defined in a python list. :param dock: A valid dock instance. :type dock: Dock :param clear_flag: Whether to clear currently loaded layers before loading the new layers. :type clear_flag: bool :param layer_list: A list of layer's paths to load. :type layer_list: list(str) """ # First unload any layers that may already be loaded if clear_flag: # noinspection PyArgumentList QgsProject.instance().removeAllMapLayers() # Now go ahead and load our layers exposure_layer_count = 0 hazard_layer_count = 0 map_layer_list = [] # Now create our new layers for layer_file in layer_list: layer, layer_type = load_layer(layer_file) if layer_type == 'hazard': hazard_layer_count += 1 elif layer_type == 'exposure': exposure_layer_count += 1 # Add layer to the registry (that Qgis knows about) a slot # in qgis_interface will also ensure it gets added to the canvas # noinspection PyArgumentList map_layer_list.append(layer) # noinspection PyArgumentList QgsProject.instance().addMapLayers(map_layer_list) if dock is not None: dock.get_layers() # Add MCL's to the CANVAS return hazard_layer_count, exposure_layer_count
def load_layers( layer_list, clear_flag=True, dock=None): """Helper function to load layers as defined in a python list. :param dock: A valid dock instance. :type dock: Dock :param clear_flag: Whether to clear currently loaded layers before loading the new layers. :type clear_flag: bool :param layer_list: A list of layer's paths to load. :type layer_list: list(str) """ # First unload any layers that may already be loaded if clear_flag: # noinspection PyArgumentList QgsProject.instance().removeAllMapLayers() # Now go ahead and load our layers exposure_layer_count = 0 hazard_layer_count = 0 map_layer_list = [] # Now create our new layers for layer_file in layer_list: layer, layer_type = load_layer(layer_file) if layer_type == 'hazard': hazard_layer_count += 1 elif layer_type == 'exposure': exposure_layer_count += 1 # Add layer to the registry (that Qgis knows about) a slot # in qgis_interface will also ensure it gets added to the canvas # noinspection PyArgumentList map_layer_list.append(layer) # noinspection PyArgumentList QgsProject.instance().addMapLayers(map_layer_list) if dock is not None: dock.get_layers() # Add MCL's to the CANVAS return hazard_layer_count, exposure_layer_count
def test_load_layer_from_uri(self): """Test we can load a layer with different parameters.""" # Without provider path = standard_data_path( 'gisv4', 'aggregation', 'small_grid.geojson') layer, purpose = load_layer(path) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'small_grid') self.assertEqual(purpose, 'aggregation') layer, purpose = load_layer(path, 'foo') self.assertEqual(layer.name(), 'foo') # With internal URI internal_uri = full_layer_uri(layer) self.assertTrue( internal_uri.endswith('small_grid.geojson|qgis_provider=ogr'), internal_uri ) layer, purpose = load_layer(full_layer_uri(layer)) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'small_grid') self.assertEqual(purpose, 'aggregation') # path plus extra layer parameter path = standard_data_path( 'gisv4', 'aggregation', 'small_grid.geojson') path += '|layerid=0' layer, purpose = load_layer(path) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'small_grid') self.assertEqual(purpose, 'aggregation') # CSV path = standard_data_path( 'gisv4', 'impacts', 'exposure_summary_table.csv') layer, purpose = load_layer(path) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'exposure_summary_table') self.assertEqual(purpose, 'undefined') self.assertEqual(len(layer.fields()), 4) # QLR # This QLR contains a file based reference layer to # small_grid.geojson, and it should work the same way # as if we load small_grid.geojson # In practice we could put the non file-based layer (PostGIS/WFS) # and load it from QLR path = standard_data_path( 'gisv4', 'aggregation', 'small_grid.qlr') layer, purpose = load_layer(path) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'small_grid') self.assertEqual(purpose, 'aggregation')
def test_load_layer_from_uri_with_postgis(self): """Test we can load a layer with different parameters in POSTGIS.""" uri = ('dbname=\'stdm\' ' 'host=localhost ' 'port=5433 ' 'user=\'etienne\' ' 'sslmode=disable ' 'key=\'id\' ' 'srid=4326 ' 'type=MultiPolygon ' 'table="public"."buildings" (geom) sql=') layer, purpose = load_layer(uri) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'buildings') self.assertEqual(purpose, 'undefined') expected = '"public"."buildings" (geom) sql=|qgis_provider=postgres' internal_uri = full_layer_uri(layer) self.assertTrue(internal_uri.endswith(expected), internal_uri)
def test_load_layer_from_uri_with_postgis(self): """Test we can load a layer with different parameters in POSTGIS.""" uri = ( 'dbname=\'stdm\' ' 'host=localhost ' 'port=5433 ' 'user=\'etienne\' ' 'sslmode=disable ' 'key=\'id\' ' 'srid=4326 ' 'type=MultiPolygon ' 'table="public"."buildings" (geom) sql=' ) layer, purpose = load_layer(uri) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'buildings') self.assertEqual(purpose, 'undefined') expected = '"public"."buildings" (geom) sql=|qgis_provider=postgres' internal_uri = full_layer_uri(layer) self.assertTrue( internal_uri.endswith(expected), internal_uri)
def add_layers_to_canvas_with_custom_orders( order, impact_function, iface=None): """Helper to add layers to the map canvas following a specific order. From top to bottom in the legend: [ ('FromCanvas', layer name, full layer URI, QML), ('FromAnalysis', layer purpose, layer group, None), ... ] The full layer URI is coming from our helper. :param order: Special structure the list of layers to add. :type order: list :param impact_function: The multi exposure impact function used. :type impact_function: MultiExposureImpactFunction :param iface: QGIS QgisAppInterface instance. :type iface: QgisAppInterface """ root = QgsProject.instance().layerTreeRoot() # Make all layers hidden. for child in root.children(): child.setItemVisibilityChecked(False) group_analysis = root.insertGroup(0, impact_function.name) group_analysis.setItemVisibilityChecked(True) group_analysis.setCustomProperty(MULTI_EXPOSURE_ANALYSIS_FLAG, True) # Insert layers in the good order in the group. for layer_definition in order: if layer_definition[0] == FROM_CANVAS['key']: style = QDomDocument() style.setContent(layer_definition[3]) layer = load_layer(layer_definition[2], layer_definition[1])[0] layer.importNamedStyle(style) QgsProject.instance().addMapLayer(layer, False) layer_node = group_analysis.addLayer(layer) layer_node.setItemVisibilityChecked(True) else: if layer_definition[2] == impact_function.name: for layer in impact_function.outputs: if layer.keywords['layer_purpose'] == layer_definition[1]: QgsProject.instance().addMapLayer( layer, False) layer_node = group_analysis.addLayer(layer) layer_node.setItemVisibilityChecked(True) try: title = layer.keywords['title'] if qgis_version() >= 21800: layer.setName(title) else: layer.setLayerName(title) except KeyError: pass break else: for sub_impact_function in impact_function.impact_functions: # Iterate over each sub impact function used in the # multi exposure analysis. if sub_impact_function.name == layer_definition[2]: for layer in sub_impact_function.outputs: purpose = layer_definition[1] if layer.keywords['layer_purpose'] == purpose: QgsProject.instance().addMapLayer( layer, False) layer_node = group_analysis.addLayer( layer) layer_node.setItemVisibilityChecked(True) try: title = layer.keywords['title'] if qgis_version() >= 21800: layer.setName(title) else: layer.setLayerName(title) except KeyError: pass break if iface: iface.setActiveLayer(impact_function.analysis_impacted)
def add_layers_to_canvas_with_custom_orders(order, impact_function, iface=None): """Helper to add layers to the map canvas following a specific order. From top to bottom in the legend: [ ('FromCanvas', layer name, full layer URI, QML), ('FromAnalysis', layer purpose, layer group, None), ... ] The full layer URI is coming from our helper. :param order: Special structure the list of layers to add. :type order: list :param impact_function: The multi exposure impact function used. :type impact_function: MultiExposureImpactFunction :param iface: QGIS QGisAppInterface instance. :type iface: QGisAppInterface """ root = QgsProject.instance().layerTreeRoot() root.setVisible(False) # Make all layers hidden. group_analysis = root.insertGroup(0, impact_function.name) group_analysis.setVisible(Qt.Checked) group_analysis.setCustomProperty(MULTI_EXPOSURE_ANALYSIS_FLAG, True) # Insert layers in the good order in the group. for layer_definition in order: if layer_definition[0] == FROM_CANVAS['key']: style = QDomDocument() style.setContent(get_string(layer_definition[3])) layer = load_layer(layer_definition[2], layer_definition[1])[0] layer.importNamedStyle(style) QgsMapLayerRegistry.instance().addMapLayer(layer, False) layer_node = group_analysis.addLayer(layer) layer_node.setVisible(Qt.Checked) else: if layer_definition[2] == impact_function.name: for layer in impact_function.outputs: if layer.keywords['layer_purpose'] == layer_definition[1]: QgsMapLayerRegistry.instance().addMapLayer( layer, False) layer_node = group_analysis.addLayer(layer) layer_node.setVisible(Qt.Checked) try: title = layer.keywords['title'] if qgis_version() >= 21800: layer.setName(title) else: layer.setLayerName(title) except KeyError: pass break else: for sub_impact_function in impact_function.impact_functions: # Iterate over each sub impact function used in the # multi exposure analysis. if sub_impact_function.name == layer_definition[2]: for layer in sub_impact_function.outputs: purpose = layer_definition[1] if layer.keywords['layer_purpose'] == purpose: QgsMapLayerRegistry.instance().addMapLayer( layer, False) layer_node = group_analysis.addLayer(layer) layer_node.setVisible(Qt.Checked) try: title = layer.keywords['title'] if qgis_version() >= 21800: layer.setName(title) else: layer.setLayerName(title) except KeyError: pass break if iface: iface.setActiveLayer(impact_function.analysis_impacted)