def test_provenance_without_aggregation(self): """Test provenance of impact function without aggregation.""" hazard_layer = load_test_vector_layer( 'gisv4', 'hazard', 'classified_vector.geojson') exposure_layer = load_test_vector_layer( 'gisv4', 'exposure', 'building-points.geojson') hazard = definition(hazard_layer.keywords['hazard']) exposure = definition(exposure_layer.keywords['exposure']) hazard_category = definition(hazard_layer.keywords['hazard_category']) expected_provenance = { 'gdal_version': gdal.__version__, 'host_name': gethostname(), 'map_title': get_map_title(hazard, exposure, hazard_category), 'map_legend_title': exposure['layer_legend_title'], 'inasafe_version': get_version(), 'pyqt_version': PYQT_VERSION_STR, 'qgis_version': QGis.QGIS_VERSION, 'qt_version': QT_VERSION_STR, 'user': getpass.getuser(), 'os': readable_os_version(), 'aggregation_layer': None, 'aggregation_layer_id': None, 'exposure_layer': exposure_layer.source(), 'exposure_layer_id': exposure_layer.id(), 'hazard_layer': hazard_layer.source(), 'hazard_layer_id': hazard_layer.id(), 'analysis_question': get_analysis_question(hazard, exposure), 'aggregation_keywords': None, 'exposure_keywords': deepcopy(exposure_layer.keywords), 'hazard_keywords': deepcopy(hazard_layer.keywords), } # Set up impact function impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) self.maxDiff = None expected_provenance.update({ 'action_checklist': impact_function.action_checklist(), 'analysis_extent': impact_function.analysis_extent.exportToWkt(), 'impact_function_name': impact_function.name, 'impact_function_title': impact_function.title, 'notes': impact_function.notes(), 'requested_extent': impact_function.requested_extent, 'data_store_uri': impact_function.datastore.uri_path, 'start_datetime': impact_function.start_datetime, 'end_datetime': impact_function.end_datetime, 'duration': impact_function.duration }) self.assertDictEqual(expected_provenance, impact_function.provenance)
def _dict_to_row(keyword_value): """Helper to make a message row from a keyword where value is a dict. .. versionadded:: 3.2 Use this when constructing a table from keywords to display as part of a message object. This variant will unpack the dict and present it nicely in the keyword value area as a nested table in the cell. We are expecting keyword value would be something like this: "{'high': ['Kawasan Rawan Bencana III'], " "'medium': ['Kawasan Rawan Bencana II'], " "'low': ['Kawasan Rawan Bencana I']}" Or by passing a python dict object with similar layout to above. i.e. A string representation of a dict where the values are lists. :param keyword_value: Value of the keyword to be rendered. This must be a string representation of a dict, or a dict. :type keyword_value: basestring, dict :returns: A table to be added into a cell in the keywords table. :rtype: safe.messaging.items.table """ if isinstance(keyword_value, basestring): keyword_value = literal_eval(keyword_value) table = m.Table(style_class='table table-condensed') for key, value in keyword_value.items(): row = m.Row() # First the heading if definition(key): name = definition(key)['name'] else: name = tr(key.capitalize()) row.add(m.Cell(m.ImportantText(name))) # Then the value. If it contains more than one element we # present it as a bullet list, otherwise just as simple text if isinstance(value, (tuple, list, dict, set)): if len(value) > 1: bullets = m.BulletedList() for item in value: bullets.add(item) row.add(m.Cell(bullets)) elif len(value) == 0: row.add(m.Cell("")) else: row.add(m.Cell(value[0])) else: row.add(m.Cell(value)) table.add(row) return table
def layer_definition_type(layer): """Returned relevant layer definition based on layer purpose. Returned the the correct definition of layer based on its purpose. For example, if a layer have layer_purpose: exposure, and exposure: roads then it will return definition for exposure_roads. That's why it only supports hazard layer or exposure layer. :param layer: hazard layer or exposure layer :type layer: qgis.core.QgsVectorLayer :return: Layer definitions. :rtype: dict .. versionadded:: 4.0 """ layer_purposes = ['exposure', 'hazard'] layer_purpose = [p for p in layer_purposes if p in layer.keywords] if not layer_purpose: return None layer_purpose = layer_purpose[0] return definition(layer.keywords[layer_purpose])
def __init__(self, coordinate_reference_system, geometry_type, exposure_key): """Constructor for the size calculator. :param coordinate_reference_system: The Coordinate Reference System of the layer. :type coordinate_reference_system: QgsCoordinateReferenceSystem :param exposure_key: The geometry type of the layer. :type exposure_key: qgis.core.QgsWkbTypes.GeometryType """ self.calculator = QgsDistanceArea() self.calculator.setSourceCrs(coordinate_reference_system, QgsProject.instance().transformContext()) self.calculator.setEllipsoid('WGS84') if geometry_type == QgsWkbTypes.LineGeometry: self.default_unit = unit_metres LOGGER.info('The size calculator is set to use {unit}'.format( unit=distance_unit[self.calculator.lengthUnits()])) else: self.default_unit = unit_square_metres LOGGER.info('The size calculator is set to use {unit}'.format( unit=distance_unit[self.calculator.areaUnits()])) self.geometry_type = geometry_type self.output_unit = None if exposure_key: exposure_definition = definition(exposure_key) self.output_unit = exposure_definition['size_unit']
def set_widgets(self): """Set widgets on the Classification tab.""" self.clear_further_steps() purpose = self.parent.step_kw_purpose.selected_purpose()['name'] subcategory = self.parent.step_kw_subcategory.\ selected_subcategory()['name'] self.lstClassifications.clear() self.lblDescribeClassification.setText('') self.lblSelectClassification.setText(classification_question % (subcategory, purpose)) classifications = self.classifications_for_layer() for classification in classifications: if not isinstance(classification, dict): classification = definition(classification) item = QListWidgetItem(classification['name'], self.lstClassifications) item.setData(QtCore.Qt.UserRole, classification['key']) self.lstClassifications.addItem(item) # Set values based on existing keywords (if already assigned) classification_keyword = self.parent.get_existing_keyword( 'classification') if classification_keyword: classifications = [] for index in xrange(self.lstClassifications.count()): item = self.lstClassifications.item(index) classifications.append(item.data(QtCore.Qt.UserRole)) if classification_keyword in classifications: self.lstClassifications.setCurrentRow( classifications.index(classification_keyword)) self.auto_select_one_item(self.lstClassifications)
def inasafe_field_header(field, feature, parent): """Retrieve a header name of the field name from definitions. For instance: inasafe_field_header('minimum_needs__clean_water') -> 'Clean water' """ _ = feature, parent # NOQA age_fields = [under_5_displaced_count_field, over_60_displaced_count_field] symbol_mapping = {'over': '>', 'under': '<'} field_definition = definition(field, 'field_name') if field_definition: if field_definition in age_fields: header_format = tr('{symbol} {age} y.o') field_name = field_definition.get('field_name') if field_name: symbol, age = field_name.split('_')[:2] if symbol.lower() in symbol_mapping.keys(): header_name = header_format.format( symbol=symbol_mapping[symbol.lower()], age=age) return header_name header_name = field_definition.get('header_name') name = field_definition.get('name') if header_name: return header_name.capitalize() else: return name.capitalize() return None
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 inasafe_field_header(field, feature, parent): """Retrieve a header name of the field name from definitions. For instance: inasafe_field_header('minimum_needs__clean_water') -> 'Clean water' """ _ = feature, parent # NOQA age_fields = [under_5_displaced_count_field, over_60_displaced_count_field] symbol_mapping = { 'over': '>', 'under': '<' } field_definition = definition(field, 'field_name') if field_definition: if field_definition in age_fields: header_format = tr('{symbol} {age} y.o') field_name = field_definition.get('field_name') if field_name: symbol, age = field_name.split('_')[:2] if symbol.lower() in symbol_mapping.keys(): header_name = header_format.format( symbol=symbol_mapping[symbol.lower()], age=age ) return header_name header_name = field_definition.get('header_name') name = field_definition.get('name') if header_name: return header_name.capitalize() else: return name.capitalize() return None
def __init__( self, coordinate_reference_system, geometry_type, exposure_key): """Constructor for the size calculator. :param coordinate_reference_system: The Coordinate Reference System of the layer. :type coordinate_reference_system: QgsCoordinateReferenceSystem :param exposure_key: The geometry type of the layer. :type exposure_key: qgis.core.QgsWkbTypes.GeometryType """ self.calculator = QgsDistanceArea() self.calculator.setSourceCrs( coordinate_reference_system, QgsProject.instance().transformContext() ) self.calculator.setEllipsoid('WGS84') if geometry_type == QgsWkbTypes.LineGeometry: self.default_unit = unit_metres LOGGER.info('The size calculator is set to use {unit}'.format( unit=distance_unit[self.calculator.lengthUnits()])) else: self.default_unit = unit_square_metres LOGGER.info('The size calculator is set to use {unit}'.format( unit=distance_unit[self.calculator.areaUnits()])) self.geometry_type = geometry_type self.output_unit = None if exposure_key: exposure_definition = definition(exposure_key) self.output_unit = exposure_definition['size_unit']
def layer_definition_type(layer): """Returned relevant layer definition based on layer purpose. Returned the the correct definition of layer based on its purpose. For example, if a layer have layer_purpose: exposure, and exposure: roads then it will return definition for exposure_roads. That's why it only supports hazard layer or exposure layer. :param layer: hazard layer or exposure layer :type layer: qgis.core.QgsVectorLayer :return: Layer definitions. :rtype: dict .. versionadded:: 4.0 """ layer_purposes = ['exposure', 'hazard'] layer_purpose = [p for p in layer_purposes if p in layer.keywords] if not layer_purpose: return None layer_purpose = layer_purpose[0] return definition(layer.keywords[layer_purpose])
def set_widgets(self): """Set widgets on the Hazard Category tab.""" self.clear_further_steps() # Set widgets self.lstHazardCategories.clear() self.lblDescribeHazardCategory.setText('') self.lblSelectHazardCategory.setText(hazard_category_question) hazard_categories = self.hazard_categories_for_layer() for hazard_category in hazard_categories: if not isinstance(hazard_category, dict): # noinspection PyTypeChecker hazard_category = definition(hazard_category) # noinspection PyTypeChecker item = QListWidgetItem(hazard_category['name'], self.lstHazardCategories) # noinspection PyTypeChecker item.setData(QtCore.Qt.UserRole, hazard_category['key']) self.lstHazardCategories.addItem(item) # Set values based on existing keywords (if already assigned) category_keyword = self.parent.get_existing_keyword('hazard_category') if category_keyword: categories = [] for index in range(self.lstHazardCategories.count()): item = self.lstHazardCategories.item(index) categories.append(item.data(QtCore.Qt.UserRole)) if category_keyword in categories: self.lstHazardCategories.setCurrentRow( categories.index(category_keyword)) self.auto_select_one_item(self.lstHazardCategories)
def set_widgets(self): """Set widgets on the Hazard Category tab.""" self.clear_further_steps() # Set widgets self.lstHazardCategories.clear() self.lblDescribeHazardCategory.setText('') self.lblSelectHazardCategory.setText( hazard_category_question) hazard_categories = self.hazard_categories_for_layer() for hazard_category in hazard_categories: if not isinstance(hazard_category, dict): # noinspection PyTypeChecker hazard_category = definition(hazard_category) # noinspection PyTypeChecker item = QListWidgetItem( hazard_category['name'], self.lstHazardCategories) # noinspection PyTypeChecker item.setData(QtCore.Qt.UserRole, hazard_category['key']) self.lstHazardCategories.addItem(item) # Set values based on existing keywords (if already assigned) category_keyword = self.parent.get_existing_keyword('hazard_category') if category_keyword: categories = [] for index in range(self.lstHazardCategories.count()): item = self.lstHazardCategories.item(index) categories.append(item.data(QtCore.Qt.UserRole)) if category_keyword in categories: self.lstHazardCategories.setCurrentRow( categories.index(category_keyword)) self.auto_select_one_item(self.lstHazardCategories)
def get_inasafe_default_value_qsetting(qsetting, category, inasafe_field_key): """Helper method to get the inasafe default value from qsetting. :param qsetting: QSetting. :type qsetting: QSetting :param category: Category of the default value. It can be global or recent. Global means the global setting for default value. Recent means the last set custom for default value from the user. :type category: str :param inasafe_field_key: Key for the field. :type inasafe_field_key: str :returns: Value of the inasafe_default_value. :rtype: float """ key = 'inasafe/default_value/%s/%s' % (category, inasafe_field_key) default_value = qsetting.value(key) if default_value is None: if category == GLOBAL: # If empty for global setting, use default one. inasafe_field = definition(inasafe_field_key) default_value = inasafe_field.get('default_value', {}) return default_value.get('default_value', zero_default_value) return zero_default_value try: return float(default_value) except ValueError: return zero_default_value
def test_analysis_earthquake_summary(self): """Test we can compute summary after an EQ on population.""" hazard = load_test_raster_layer('gisv4', 'hazard', 'earthquake.asc') exposure = load_test_raster_layer( 'gisv4', 'exposure', 'raster', 'population.asc') aggregation = load_test_vector_layer( 'gisv4', 'aggregation', 'small_grid.geojson') impact_function = ImpactFunction() impact_function.hazard = hazard impact_function.exposure = exposure impact_function.aggregation = aggregation status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) layer = impact_function.analysis_impacted classification = hazard.keywords['classification'] classes = definition(classification)['classes'] for hazard_class in classes: field_name = hazard_count_field['field_name'] % hazard_class['key'] message = '%s is not found in the EQ summary layer.' % field_name self.assertNotEqual(-1, layer.fieldNameIndex(field_name), message) check_inasafe_fields(impact_function.analysis_impacted) check_inasafe_fields(impact_function.aggregation_summary)
def test_analysis_earthquake_summary(self): """Test we can compute summary after an EQ on population.""" hazard = load_test_raster_layer('gisv4', 'hazard', 'earthquake.asc') exposure = load_test_raster_layer('gisv4', 'exposure', 'raster', 'population.asc') aggregation = load_test_vector_layer('gisv4', 'aggregation', 'small_grid.geojson') impact_function = ImpactFunction() impact_function.hazard = hazard impact_function.exposure = exposure impact_function.aggregation = aggregation status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) layer = impact_function.analysis_impacted classification = hazard.keywords['classification'] classes = definition(classification)['classes'] for hazard_class in classes: field_name = hazard_count_field['field_name'] % hazard_class['key'] message = '%s is not found in the EQ summary layer.' % field_name self.assertNotEqual(-1, layer.fieldNameIndex(field_name), message) check_inasafe_fields(impact_function.analysis_impacted) check_inasafe_fields(impact_function.aggregation_summary)
def get_inasafe_default_value_qsetting( qsetting, category, inasafe_field_key): """Helper method to get the inasafe default value from qsetting. :param qsetting: QSetting. :type qsetting: QSetting :param category: Category of the default value. It can be global or recent. Global means the global setting for default value. Recent means the last set custom for default value from the user. :type category: str :param inasafe_field_key: Key for the field. :type inasafe_field_key: str :returns: Value of the inasafe_default_value. :rtype: float """ key = 'inasafe/default_value/%s/%s' % (category, inasafe_field_key) default_value = qsetting.value(key) if default_value is None: if category == GLOBAL: # If empty for global setting, use default one. inasafe_field = definition(inasafe_field_key) default_value = inasafe_field.get('default_value', {}) return default_value.get('default_value', zero_default_value) return zero_default_value try: return float(default_value) except ValueError: return zero_default_value
def set_widgets(self): """Set widgets on the Classification tab.""" self.clear_further_steps() purpose = self.parent.step_kw_purpose.selected_purpose()['name'] subcategory = self.parent.step_kw_subcategory.\ selected_subcategory()['name'] self.lstClassifications.clear() self.lblDescribeClassification.setText('') self.lblSelectClassification.setText( classification_question % (subcategory, purpose)) classifications = self.classifications_for_layer() for classification in classifications: if not isinstance(classification, dict): classification = definition(classification) item = QListWidgetItem( classification['name'], self.lstClassifications) item.setData(QtCore.Qt.UserRole, classification['key']) self.lstClassifications.addItem(item) # Set values based on existing keywords (if already assigned) classification_keyword = self.parent.get_existing_keyword( 'classification') if classification_keyword: classifications = [] for index in xrange(self.lstClassifications.count()): item = self.lstClassifications.item(index) classifications.append(item.data(QtCore.Qt.UserRole)) if classification_keyword in classifications: self.lstClassifications.setCurrentRow( classifications.index(classification_keyword)) self.auto_select_one_item(self.lstClassifications)
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 _populate_reporting_tab(self): """Populate trees about layers.""" self.tree.clear() self.add_layer.setEnabled(False) self.remove_layer.setEnabled(False) self.move_up.setEnabled(False) self.move_down.setEnabled(False) self.tree.setColumnCount(1) self.tree.setRootIsDecorated(False) self.tree.setHeaderHidden(True) analysis_branch = QTreeWidgetItem(self.tree.invisibleRootItem(), [FROM_ANALYSIS['name']]) analysis_branch.setFont(0, bold_font) analysis_branch.setExpanded(True) analysis_branch.setFlags(Qt.ItemIsEnabled) if self._multi_exposure_if: expected = self._multi_exposure_if.output_layers_expected() for group, layers in list(expected.items()): group_branch = QTreeWidgetItem(analysis_branch, [group]) group_branch.setFont(0, bold_font) group_branch.setExpanded(True) group_branch.setFlags(Qt.ItemIsEnabled) for layer in layers: layer = definition(layer) if layer.get('allowed_geometries', None): item = QTreeWidgetItem(group_branch, [layer.get('name')]) item.setData(0, LAYER_ORIGIN_ROLE, FROM_ANALYSIS['key']) item.setData(0, LAYER_PARENT_ANALYSIS_ROLE, group) item.setData(0, LAYER_PURPOSE_KEY_OR_ID_ROLE, layer['key']) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) canvas_branch = QTreeWidgetItem(self.tree.invisibleRootItem(), [FROM_CANVAS['name']]) canvas_branch.setFont(0, bold_font) canvas_branch.setExpanded(True) canvas_branch.setFlags(Qt.ItemIsEnabled) # List layers from the canvas loaded_layers = list(QgsProject.instance().mapLayers().values()) canvas_layers = self.iface.mapCanvas().layers() flag = setting('visibleLayersOnlyFlag', expected_type=bool) for loaded_layer in loaded_layers: if flag and loaded_layer not in canvas_layers: continue title = loaded_layer.name() item = QTreeWidgetItem(canvas_branch, [title]) item.setData(0, LAYER_ORIGIN_ROLE, FROM_CANVAS['key']) item.setData(0, LAYER_PURPOSE_KEY_OR_ID_ROLE, loaded_layer.id()) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) self.tree.resizeColumnToContents(0)
def test_definition(self): """Test we can get definitions for keywords. .. versionadded:: 3.2 """ keyword = 'hazards' keyword_definition = definition(keyword) self.assertTrue('description' in keyword_definition)
def test_definition(self): """Test we can get definitions for keywords. .. versionadded:: 3.2 """ keyword = 'hazards' keyword_definition = definition(keyword) self.assertTrue('description' in keyword_definition)
def selected_layermode(self): """Obtain the layer mode selected by user. :returns: selected layer mode. :rtype: string, None """ item = self.lstLayerModes.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_layermode(self): """Obtain the layer mode selected by user. :returns: selected layer mode. :rtype: string, None """ item = self.lstLayerModes.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def sum_fields(layer, output_field_key, input_fields): """Sum the value of input_fields and put it as output_field. :param layer: The vector layer. :type layer: QgsVectorLayer :param output_field_key: The output field definition key. :type output_field_key: basestring :param input_fields: List of input fields' name. :type input_fields: list """ field_definition = definition(output_field_key) output_field_name = field_definition['field_name'] # If the fields only has one element if len(input_fields) == 1: # Name is different, copy it if input_fields[0] != output_field_name: to_rename = {input_fields[0]: output_field_name} # We copy only, it will be deleted later. # We can't rename the field, we need to copy it as the same # field might be used many times in the FMT tool. copy_fields(layer, to_rename) else: # Name is same, do nothing return else: # Creating expression # Put field name in a double quote. See #4248 input_fields = ['"%s"' % f for f in input_fields] string_expression = ' + '.join(input_fields) sum_expression = QgsExpression(string_expression) context = QgsExpressionContext() context.setFields(layer.pendingFields()) sum_expression.prepare(context) # Get the output field index output_idx = layer.fieldNameIndex(output_field_name) # Output index is not found if output_idx == -1: output_field = create_field_from_definition(field_definition) layer.startEditing() layer.addAttribute(output_field) layer.commitChanges() output_idx = layer.fieldNameIndex(output_field_name) layer.startEditing() # Iterate to all features for feature in layer.getFeatures(): context.setFeature(feature) result = sum_expression.evaluate(context) feature[output_idx] = result layer.updateFeature(feature) layer.commitChanges()
def selected_classification(self): """Obtain the classification selected by user. :returns: Metadata of the selected classification. :rtype: dict, None """ item = self.lstClassifications.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_unit(self): """Obtain the unit selected by user. :returns: Metadata of the selected unit. :rtype: dict, None """ item = self.lstUnits.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_subcategory(self): """Obtain the subcategory selected by user. :returns: Metadata of the selected subcategory. :rtype: dict, None """ item = self.lstSubcategories.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_unit(self): """Obtain the unit selected by user. :returns: Metadata of the selected unit. :rtype: dict, None """ item = self.lstUnits.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_classification(self): """Obtain the classification selected by user. :returns: Metadata of the selected classification. :rtype: dict, None """ item = self.lstClassifications.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_purpose(self): """Obtain the layer purpose selected by user. :returns: Metadata of the selected layer purpose. :rtype: dict, None """ item = self.lstCategories.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def selected_hazard_category(self): """Obtain the hazard category selected by user. :returns: Metadata of the selected hazard category. :rtype: dict, None """ item = self.lstHazardCategories.currentItem() try: return definition(item.data(QtCore.Qt.UserRole)) except (AttributeError, NameError): return None
def layer_title(layer): """Set the layer title according to the standards. :param layer: The layer to style. :type layer: QgsVectorLayer """ exposure_type = layer.keywords['exposure_keywords']['exposure'] exposure_definitions = definition(exposure_type) title = exposure_definitions['layer_legend_title'] layer.setTitle(title) layer.keywords['title'] = title
def layer_title(layer): """Set the layer title according to the standards. :param layer: The layer to style. :type layer: QgsVectorLayer """ exposure_type = layer.keywords['exposure_keywords']['exposure'] exposure_definitions = definition(exposure_type) title = exposure_definitions['layer_legend_title'] layer.setTitle(title) layer.keywords['title'] = title
def sum_fields(layer, output_field_key, input_fields): """Sum the value of input_fields and put it as output_field. :param layer: The vector layer. :type layer: QgsVectorLayer :param output_field_key: The output field definition key. :type output_field_key: basestring :param input_fields: List of input fields' name. :type input_fields: list """ field_definition = definition(output_field_key) output_field_name = field_definition['field_name'] # If the fields only has one element if len(input_fields) == 1: # Name is different, copy it if input_fields[0] != output_field_name: to_rename = {input_fields[0]: output_field_name} # We copy only, it will be deleted later. # We can't rename the field, we need to copy it as the same # field might be used many times in the FMT tool. copy_fields(layer, to_rename) else: # Name is same, do nothing return else: # Creating expression # Put field name in a double quote. See #4248 input_fields = ['"%s"' % f for f in input_fields] string_expression = ' + '.join(input_fields) sum_expression = QgsExpression(string_expression) context = QgsExpressionContext() context.setFields(layer.fields()) sum_expression.prepare(context) # Get the output field index output_idx = layer.fields().lookupField(output_field_name) # Output index is not found layer.startEditing() if output_idx == -1: output_field = create_field_from_definition(field_definition) layer.addAttribute(output_field) output_idx = layer.fields().lookupField(output_field_name) # Iterate to all features for feature in layer.getFeatures(): context.setFeature(feature) result = sum_expression.evaluate(context) feature[output_idx] = result layer.updateFeature(feature) layer.commitChanges()
def add_fields( layer, absolute_values, static_fields, dynamic_structure): """Function to add fields needed in the output layer. :param layer: The vector layer. :type layer: QgsVectorLayer :param absolute_values: The absolute value structure. :type absolute_values: dict :param static_fields: The list of static fields to add. :type static_fields: list :param dynamic_structure: The list of dynamic fields to add to the layer. The list must be structured like this: dynamic_structure = [ [exposure_count_field, unique_exposure] ] where "exposure_count_field" is the dynamic to field to add and "unique_exposure" is the list of unique values to associate with this dynamic field. Because dynamic_structure is a ordered list, you can add many dynamic fields. :type dynamic_structure: list """ for new_dynamic_field in dynamic_structure: field_definition = new_dynamic_field[0] unique_values = new_dynamic_field[1] for column in unique_values: if (column == '' or (hasattr(column, 'isNull') and column.isNull())): column = 'NULL' field = create_field_from_definition(field_definition, column) layer.addAttribute(field) key = field_definition['key'] % column value = field_definition['field_name'] % column layer.keywords['inasafe_fields'][key] = value for static_field in static_fields: field = create_field_from_definition(static_field) layer.addAttribute(field) # noinspection PyTypeChecker layer.keywords['inasafe_fields'][static_field['key']] = ( static_field['field_name']) # For each absolute values for absolute_field in list(absolute_values.keys()): field_definition = definition(absolute_values[absolute_field][1]) field = create_field_from_definition(field_definition) layer.addAttribute(field) key = field_definition['key'] value = field_definition['field_name'] layer.keywords['inasafe_fields'][key] = value
def add_fields( layer, absolute_values, static_fields, dynamic_structure): """Function to add fields needed in the output layer. :param layer: The vector layer. :type layer: QgsVectorLayer :param absolute_values: The absolute value structure. :type absolute_values: dict :param static_fields: The list of static fields to add. :type static_fields: list :param dynamic_structure: The list of dynamic fields to add to the layer. The list must be structured like this: dynamic_structure = [ [exposure_count_field, unique_exposure] ] where "exposure_count_field" is the dynamic to field to add and "unique_exposure" is the list of unique values to associate with this dynamic field. Because dynamic_structure is a ordered list, you can add many dynamic fields. :type dynamic_structure: list """ for new_dynamic_field in dynamic_structure: field_definition = new_dynamic_field[0] unique_values = new_dynamic_field[1] for column in unique_values: if (column == '' or (hasattr(column, 'isNull') and column.isNull())): column = 'NULL' field = create_field_from_definition(field_definition, column) layer.addAttribute(field) key = field_definition['key'] % column value = field_definition['field_name'] % column layer.keywords['inasafe_fields'][key] = value for static_field in static_fields: field = create_field_from_definition(static_field) layer.addAttribute(field) # noinspection PyTypeChecker layer.keywords['inasafe_fields'][static_field['key']] = ( static_field['field_name']) # For each absolute values for absolute_field in list(absolute_values.keys()): field_definition = definition(absolute_values[absolute_field][1]) field = create_field_from_definition(field_definition) layer.addAttribute(field) key = field_definition['key'] value = field_definition['field_name'] layer.keywords['inasafe_fields'][key] = value
def sum_fields(layer, output_field_key, input_fields): """Sum the value of input_fields and put it as output_field. :param layer: The vector layer. :type layer: QgsVectorLayer :param output_field_key: The output field definition key. :type output_field_key: basestring :param input_fields: List of input fields' name. :type input_fields: list """ field_definition = definition(output_field_key) output_field_name = field_definition['field_name'] # If the fields only has one element if len(input_fields) == 1: # Name is different, copy it if input_fields[0] != output_field_name: copy_fields(layer, { input_fields[0]: output_field_name}) # Name is same, do nothing else: return else: # Creating expression # Put field name in a double quote. See #4248 input_fields = ['"%s"' % f for f in input_fields] string_expression = ' + '.join(input_fields) sum_expression = QgsExpression(string_expression) context = QgsExpressionContext() context.setFields(layer.pendingFields()) sum_expression.prepare(context) # Get the output field index output_idx = layer.fieldNameIndex(output_field_name) # Output index is not found if output_idx == -1: output_field = create_field_from_definition(field_definition) layer.startEditing() layer.addAttribute(output_field) layer.commitChanges() output_idx = layer.fieldNameIndex(output_field_name) layer.startEditing() # Iterate to all features for feature in layer.getFeatures(): context.setFeature(feature) result = sum_expression.evaluate(context) feature[output_idx] = result layer.updateFeature(feature) layer.commitChanges()
def _check_value_mapping(layer, exposure_key=None): """Loop over the exposure type field and check if the value map is correct. :param layer: The layer :type layer: QgsVectorLayer :param exposure_key: The exposure key. :type exposure_key: str """ index = layer.fieldNameIndex(exposure_type_field['field_name']) unique_exposure = layer.uniqueValues(index) if layer.keywords['layer_purpose'] == layer_purpose_hazard['key']: if not exposure_key: message = tr('Hazard value mapping missing exposure key.') raise InvalidKeywordsForProcessingAlgorithm(message) value_map = active_thresholds_value_maps(layer.keywords, exposure_key) else: value_map = layer.keywords.get('value_map') if not value_map: # The exposure do not have a value_map, we can skip the layer. return layer if layer.keywords['layer_purpose'] == layer_purpose_hazard['key']: if not exposure_key: message = tr('Hazard classification is missing exposure key.') raise InvalidKeywordsForProcessingAlgorithm(message) classification = active_classification(layer.keywords, exposure_key) else: classification = layer.keywords['classification'] exposure_classification = definition(classification) other = None if exposure_classification['key'] != 'data_driven_classes': other = exposure_classification['classes'][-1]['key'] exposure_mapped = [] for group in value_map.itervalues(): exposure_mapped.extend(group) diff = list(set(unique_exposure) - set(exposure_mapped)) if other in value_map.keys(): value_map[other].extend(diff) else: value_map[other] = diff layer.keywords['value_map'] = value_map layer.keywords['classification'] = classification return layer
def _check_value_mapping(layer, exposure_key=None): """Loop over the exposure type field and check if the value map is correct. :param layer: The layer :type layer: QgsVectorLayer :param exposure_key: The exposure key. :type exposure_key: str """ index = layer.fields().lookupField(exposure_type_field['field_name']) unique_exposure = layer.uniqueValues(index) if layer.keywords['layer_purpose'] == layer_purpose_hazard['key']: if not exposure_key: message = tr('Hazard value mapping missing exposure key.') raise InvalidKeywordsForProcessingAlgorithm(message) value_map = active_thresholds_value_maps(layer.keywords, exposure_key) else: value_map = layer.keywords.get('value_map') if not value_map: # The exposure do not have a value_map, we can skip the layer. return layer if layer.keywords['layer_purpose'] == layer_purpose_hazard['key']: if not exposure_key: message = tr('Hazard classification is missing exposure key.') raise InvalidKeywordsForProcessingAlgorithm(message) classification = active_classification(layer.keywords, exposure_key) else: classification = layer.keywords['classification'] exposure_classification = definition(classification) other = None if exposure_classification['key'] != data_driven_classes['key']: other = exposure_classification['classes'][-1]['key'] exposure_mapped = [] for group in list(value_map.values()): exposure_mapped.extend(group) diff = list(unique_exposure - set(exposure_mapped)) if other in list(value_map.keys()): value_map[other].extend(diff) else: value_map[other] = diff layer.keywords['value_map'] = value_map layer.keywords['classification'] = classification return layer
def add_debug_layers_to_canvas(impact_function): """Helper method to add debug layers to QGIS from impact function. :param impact_function: The impact function used. :type impact_function: ImpactFunction """ name = 'DEBUG %s' % impact_function.name root = QgsProject.instance().layerTreeRoot() group_debug = root.insertGroup(0, name) group_debug.setItemVisibilityChecked(False) group_debug.setExpanded(False) hazard_keywords = impact_function.provenance['hazard_keywords'] exposure_keywords = impact_function.provenance['exposure_keywords'] # Let's style the hazard class in each layers. # noinspection PyBroadException try: classification = active_classification( hazard_keywords, exposure_keywords['exposure']) classification = definition(classification) classes = OrderedDict() for f in reversed(classification['classes']): classes[f['key']] = (f['color'], f['name']) hazard_class = hazard_class_field['key'] except BaseException: # We might not have a classification. But this is the debug group so # let's not raise a new exception. classification = None datastore = impact_function.datastore for layer in datastore.layers(): qgis_layer = datastore.layer(layer) if not isinstance(qgis_layer, QgsMapLayer): continue QgsProject.instance().addMapLayer( qgis_layer, False) layer_node = group_debug.insertLayer(0, qgis_layer) layer_node.setItemVisibilityChecked(False) layer_node.setExpanded(False) # Let's style layers which have a geometry and have # hazard_class if qgis_layer.type() == QgsMapLayer.VectorLayer: if qgis_layer.geometryType() not in [ QgsWkbTypes.NullGeometry, QgsWkbTypes.UnknownGeometry ] and classification: # noqa if qgis_layer.keywords['inasafe_fields'].get(hazard_class): hazard_class_style(qgis_layer, classes, True)
def add_debug_layers_to_canvas(impact_function): """Helper method to add debug layers to QGIS from impact function. :param impact_function: The impact function used. :type impact_function: ImpactFunction """ name = 'DEBUG %s' % impact_function.name root = QgsProject.instance().layerTreeRoot() group_debug = root.insertGroup(0, name) group_debug.setItemVisibilityChecked(False) group_debug.setExpanded(False) hazard_keywords = impact_function.provenance['hazard_keywords'] exposure_keywords = impact_function.provenance['exposure_keywords'] # Let's style the hazard class in each layers. # noinspection PyBroadException try: classification = active_classification(hazard_keywords, exposure_keywords['exposure']) classification = definition(classification) classes = OrderedDict() for f in reversed(classification['classes']): classes[f['key']] = (f['color'], f['name']) hazard_class = hazard_class_field['key'] except BaseException: # We might not have a classification. But this is the debug group so # let's not raise a new exception. classification = None datastore = impact_function.datastore for layer in datastore.layers(): qgis_layer = datastore.layer(layer) if not isinstance(qgis_layer, QgsMapLayer): continue QgsProject.instance().addMapLayer(qgis_layer, False) layer_node = group_debug.insertLayer(0, qgis_layer) layer_node.setItemVisibilityChecked(False) layer_node.setExpanded(False) # Let's style layers which have a geometry and have # hazard_class not_allowed_geom = [ QgsWkbTypes.NullGeometry, QgsWkbTypes.UnknownGeometry ] if qgis_layer.type() == QgsMapLayer.VectorLayer: if qgis_layer.geometryType() not in not_allowed_geom \ and classification: # noqa if qgis_layer.keywords['inasafe_fields'].get(hazard_class): hazard_class_style(qgis_layer, classes, True)
def test_title(self): """Test we can set the layer title correctly.""" layer = load_test_vector_layer('impact', 'buildings_without_style.geojson') layer_title(layer) # The code tested is running the same logic as the test itself. # But at least we have a test. exposure_type = layer.keywords['exposure_keywords']['exposure'] exposure_definitions = definition(exposure_type) title = exposure_definitions['layer_legend_title'] layer.setTitle(title) self.assertEqual(title, layer.title())
def test_title(self): """Test we can set the layer title correctly.""" layer = load_test_vector_layer( 'impact', 'buildings_without_style.geojson') layer_title(layer) # The code tested is running the same logic as the test itself. # But at least we have a test. exposure_type = layer.keywords['exposure_keywords']['exposure'] exposure_definitions = definition(exposure_type) title = exposure_definitions['layer_legend_title'] layer.setTitle(title) self.assertEqual(title, layer.title())
def add_fields( layer, absolute_values, static_fields, dynamic_values, dynamic_field): """Function to add fields needed in the output layer. :param layer: The vector layer. :type layer: QgsVectorLayer :param absolute_values: The absolute value structure. :type absolute_values: dict :param static_fields: The list of static fields to add. :type static_fields: list :param dynamic_values: The list of unique field to create. :type dynamic_values: list :param dynamic_field: The dynamic field to add. :type dynamic_field: safe.definitions.fields :param static_fields """ for column in dynamic_values: if not column or isinstance(column, QPyNullVariant): column = 'NULL' field = create_field_from_definition(dynamic_field, column) layer.addAttribute(field) key = dynamic_field['key'] % column value = dynamic_field['field_name'] % column layer.keywords['inasafe_fields'][key] = value for static_field in static_fields: field = create_field_from_definition(static_field) layer.addAttribute(field) # noinspection PyTypeChecker layer.keywords['inasafe_fields'][static_field['key']] = ( static_field['field_name']) # For each absolute values for absolute_field in absolute_values.iterkeys(): field_definition = definition(absolute_values[absolute_field][1]) field = create_field_from_definition(field_definition) layer.addAttribute(field) key = field_definition['key'] value = field_definition['field_name'] layer.keywords['inasafe_fields'][key] = value
def add_debug_layers_to_canvas(impact_function): """Helper method to add debug layers to QGIS from impact function. :param impact_function: The impact function used. :type impact_function: ImpactFunction """ name = 'DEBUG %s' % impact_function.name root = QgsProject.instance().layerTreeRoot() group_debug = root.insertGroup(0, name) group_debug.setVisible(Qt.Unchecked) group_debug.setExpanded(False) # Let's style the hazard class in each layers. # noinspection PyBroadException try: classification = ( impact_function.hazard.keywords['classification']) classification = definition(classification) classes = OrderedDict() for f in reversed(classification['classes']): classes[f['key']] = (f['color'], f['name']) hazard_class = hazard_class_field['key'] except: # We might not have a classification. But this is the debug group so # let's not raise a new exception. classification = None datastore = impact_function.datastore for layer in datastore.layers(): qgis_layer = datastore.layer(layer) if not isinstance(qgis_layer, QgsMapLayer): continue QgsMapLayerRegistry.instance().addMapLayer( qgis_layer, False) layer_node = group_debug.insertLayer(0, qgis_layer) layer_node.setVisible(Qt.Unchecked) layer_node.setExpanded(False) # Let's style layers which have a geometry and have # hazard_class if qgis_layer.type() == QgsMapLayer.VectorLayer: if qgis_layer.geometryType() != QGis.NoGeometry and classification: if qgis_layer.keywords['inasafe_fields'].get(hazard_class): hazard_class_style(qgis_layer, classes, True)
def add_fields( layer, absolute_values, static_fields, dynamic_values, dynamic_field): """Function to add fields needed in the output layer. :param layer: The vector layer. :type layer: QgsVectorLayer :param absolute_values: The absolute value structure. :type absolute_values: dict :param static_fields: The list of static fields to add. :type static_fields: list :param dynamic_values: The list of unique field to create. :type dynamic_values: list :param dynamic_field: The dynamic field to add. :type dynamic_field: safe.definitions.fields :param static_fields """ for column in dynamic_values: if not column or isinstance(column, QPyNullVariant): column = 'NULL' field = create_field_from_definition(dynamic_field, column) layer.addAttribute(field) key = dynamic_field['key'] % column value = dynamic_field['field_name'] % column layer.keywords['inasafe_fields'][key] = value for static_field in static_fields: field = create_field_from_definition(static_field) layer.addAttribute(field) # noinspection PyTypeChecker layer.keywords['inasafe_fields'][static_field['key']] = ( static_field['field_name']) # For each absolute values for absolute_field in absolute_values.iterkeys(): field_definition = definition(absolute_values[absolute_field][1]) field = create_field_from_definition(field_definition) layer.addAttribute(field) key = field_definition['key'] value = field_definition['field_name'] layer.keywords['inasafe_fields'][key] = value
def retrieve_exposure_classes_lists(exposure_keywords): """Retrieve exposures classes. Only if the exposure has some classifications. :param exposure_keywords: exposure keywords :type exposure_keywords: dict :return: lists of classes used in the classifications. :rtype: list(dict) """ # return None in case exposure doesn't have classifications classification = exposure_keywords.get('classification') if not classification: return None # retrieve classes definitions exposure_classifications = definition(classification) return exposure_classifications['classes']
def retrieve_exposure_classes_lists(exposure_keywords): """Retrieve exposures classes. Only if the exposure has some classifications. :param exposure_keywords: exposure keywords :type exposure_keywords: dict :return: lists of classes used in the classifications. :rtype: list(dict) """ # return None in case exposure doesn't have classifications classification = exposure_keywords.get('classification') if not classification: return None # retrieve classes definitions exposure_classifications = definition(classification) return exposure_classifications['classes']
def retrieve_exposure_classes_lists(exposure_layer): """Retrieve exposures classes. Only if the exposure has some classifications. :param exposure_layer: exposure layer :type exposure_layer: qgis.core.QgsMapLayer :return: lists of classes used in the classifications. :rtype: list(dict) """ # return None in case exposure doesn't have classifications keywords = exposure_layer.keywords classification = keywords.get('classification') if not classification: return None # retrieve classes definitions exposure_classifications = definition(classification) return exposure_classifications['classes']
def retrieve_exposure_classes_lists(exposure_layer): """Retrieve exposures classes. Only if the exposure has some classifications. :param exposure_layer: exposure layer :type exposure_layer: qgis.core.QgsMapLayer :return: lists of classes used in the classifications. :rtype: list(dict) """ # return None in case exposure doesn't have classifications keywords = exposure_layer.keywords classification = keywords.get('classification') if not classification: return None # retrieve classes definitions exposure_classifications = definition(classification) return exposure_classifications['classes']
def get_current_state(self): """Obtain current classification and value map / threshold.""" def clean_state(dictionary): """Clean dictionary from bad value. :param dictionary: Dictionary of value maps or thresholds. :type dictionary: dict :returns: Clean state. :rtype: dict """ clean_dictionary = { k: v for k, v in list(dictionary.items()) if isinstance(v, dict)} return clean_dictionary if self.layer_mode == layer_mode_continuous: output = {'thresholds': clean_state(self.thresholds)} key = 'thresholds' else: output = {'value_maps': clean_state(self.value_maps)} key = 'value_maps' # Clean non existing hazard class key empty_exposure_classifications = [] for the_exposure, the_hazard_classifications in list( output[key].items()): for the_hazard_classification in list(the_hazard_classifications. keys()): invalid_classifications = [] if not definition(the_hazard_classification): invalid_classifications.append( the_hazard_classification) for invalid_classification in invalid_classifications: the_hazard_classifications.pop(invalid_classification) if not the_hazard_classifications: empty_exposure_classifications.append(the_exposure) for empty_exposure_classification in empty_exposure_classifications: output[key].pop(empty_exposure_classification) return output
def get_current_state(self): """Obtain current classification and value map / threshold.""" def clean_state(dictionary): """Clean dictionary from bad value. :param dictionary: Dictionary of value maps or thresholds. :type dictionary: dict :returns: Clean state. :rtype: dict """ clean_dictionary = { k: v for k, v in list(dictionary.items()) if isinstance(v, dict)} return clean_dictionary if self.layer_mode == layer_mode_continuous: output = {'thresholds': clean_state(self.thresholds)} key = 'thresholds' else: output = {'value_maps': clean_state(self.value_maps)} key = 'value_maps' # Clean non existing hazard class key empty_exposure_classifications = [] for the_exposure, the_hazard_classifications in list( output[key].items()): for the_hazard_classification in list(the_hazard_classifications. keys()): invalid_classifications = [] if not definition(the_hazard_classification): invalid_classifications.append( the_hazard_classification) for invalid_classification in invalid_classifications: the_hazard_classifications.pop(invalid_classification) if not the_hazard_classifications: empty_exposure_classifications.append(the_exposure) for empty_exposure_classification in empty_exposure_classifications: output[key].pop(empty_exposure_classification) return output
def from_mmi_to_hazard_class(mmi_level, classification_key): """From a MMI level, it returns the hazard class given a classification. :param mmi_level: The MMI level. :type mmi_level: int :param classification_key: The earthquake classification key. :type classification_key: safe.definitions.hazard_classifications :return: The hazard class key :rtype: basestring """ classes = definition(classification_key)['classes'] for hazard_class in classes: minimum = hazard_class['numeric_default_min'] maximum = hazard_class['numeric_default_max'] if minimum < mmi_level <= maximum: return hazard_class['key'] return None
def fatality_rate(mmi_level, classification_key): """From a MMI level, it gives the fatality rate given a classification. :param mmi_level: The MMI level. :type mmi_level: int :param classification_key: The earthquake classification key. :type classification_key: safe.definitions.hazard_classifications :return: The fatality rate. :rtype: float """ classes = definition(classification_key)['classes'] for hazard_class in classes: minimum = hazard_class['numeric_default_min'] maximum = hazard_class['numeric_default_max'] if minimum < mmi_level <= maximum: return hazard_class['fatality_rate'] return 0.0
def report_on_field(layer): """Helper function to set on which field we are going to report. The return might be empty if we don't report on a field. :param layer: The vector layer. :type layer: QgsVectorLayer :return: The field index on which we should report. :rtype: int """ source_fields = layer.keywords['inasafe_fields'] if source_fields.get(size_field['key']): field_size = source_fields[size_field['key']] field_index = layer.fields().lookupField(field_size) else: field_index = None # Special case for a point layer and indivisible polygon, # we do not want to report on the size. geometry = layer.geometryType() exposure = layer.keywords.get('exposure') if geometry == QgsWkbTypes.PointGeometry: field_index = None if geometry == QgsWkbTypes.PolygonGeometry and exposure == \ exposure_structure['key']: field_index = None # Special case if it's an exposure without classification. It means it's # a continuous exposure. We count the compulsory field. classification = layer.keywords.get('classification') if not classification: exposure_definitions = definition(exposure) # I take the only first field for reporting, I don't know how to manage # with many fields. AFAIK we don't have this case yet. field = exposure_definitions['compulsory_fields'][0] field_name = source_fields[field['key']] field_index = layer.fields().lookupField(field_name) return field_index
def _remove_layer_clicked(self): """Remove layer clicked.""" layer = self.list_layers_in_map_report.selectedItems()[0] origin = layer.data(LAYER_ORIGIN_ROLE) if origin == FROM_ANALYSIS['key']: key = layer.data(LAYER_PURPOSE_KEY_OR_ID_ROLE) parent = layer.data(LAYER_PARENT_ANALYSIS_ROLE) parent_item = self.tree.findItems( parent, Qt.MatchContains | Qt.MatchRecursive, 0)[0] item = QTreeWidgetItem(parent_item, [definition(key)['name']]) item.setData(0, LAYER_PARENT_ANALYSIS_ROLE, parent) else: parent_item = self.tree.findItems( FROM_CANVAS['name'], Qt.MatchContains | Qt.MatchRecursive, 0)[0] item = QTreeWidgetItem(parent_item, [layer.text()]) layer_id = layer.data(LAYER_PURPOSE_KEY_OR_ID_ROLE) item.setData(0, LAYER_PURPOSE_KEY_OR_ID_ROLE, layer_id) item.setData(0, LAYER_ORIGIN_ROLE, origin) index = self.list_layers_in_map_report.indexFromItem(layer) self.list_layers_in_map_report.takeItem(index.row()) self.list_layers_in_map_report.clearSelection()
def report_on_field(layer): """Helper function to set on which field we are going to report. The return might be empty if we don't report on a field. :param layer: The vector layer. :type layer: QgsVectorLayer :return: The field index on which we should report. :rtype: int """ source_fields = layer.keywords['inasafe_fields'] if source_fields.get(size_field['key']): field_size = source_fields[size_field['key']] field_index = layer.fieldNameIndex(field_size) else: field_index = None # Special case for a point layer and indivisible polygon, # we do not want to report on the size. geometry = layer.geometryType() exposure = layer.keywords.get('exposure') if geometry == QGis.Point: field_index = None if geometry == QGis.Polygon and exposure == 'structure': field_index = None # Special case if it's an exposure without classification. It means it's # a continuous exposure. We count the compulsory field. classification = layer.keywords.get('classification') if not classification: exposure_definitions = definition(exposure) # I take the only first field for reporting, I don't know how to manage # with many fields. AFAIK we don't have this case yet. field = exposure_definitions['compulsory_fields'][0] field_name = source_fields[field['key']] field_index = layer.fieldNameIndex(field_name) return field_index
def minimum_needs_unit(field, feature, parent): """Retrieve units of the given minimum needs field name. For instance: * minimum_needs_unit('minimum_needs__clean_water') -> 'l/weekly' """ _ = feature, parent # NOQA field_definition = definition(field, 'field_name') if field_definition: unit_abbreviation = None frequency = None if field_definition.get('need_parameter'): need = field_definition['need_parameter'] if isinstance(need, ResourceParameter): unit_abbreviation = need.unit.abbreviation frequency = need.frequency elif field_definition.get('unit'): need_unit = field_definition.get('unit') unit_abbreviation = need_unit.get('abbreviation') if field_definition.get('frequency') and not frequency: frequency = field_definition.get('frequency') if not unit_abbreviation: unit_abbreviation = exposure_unit['plural_name'] once_frequency_field_keys = [ 'minimum_needs__toilets_count_field' ] if not frequency or ( field_definition['key'] in once_frequency_field_keys): return unit_abbreviation.lower() unit_format = u'{unit_abbreviation}/{frequency}' return unit_format.format( unit_abbreviation=unit_abbreviation, frequency=frequency).lower() return None
def set_widgets(self): """Set widgets on the layer purpose tab.""" self.clear_further_steps() # Set widgets self.lstCategories.clear() self.lblDescribeCategory.setText('') self.lblIconCategory.setPixmap(QPixmap()) self.lblSelectCategory.setText( category_question % self.parent.layer.name()) purposes = self.purposes_for_layer() for purpose in purposes: if not isinstance(purpose, dict): purpose = definition(purpose) item = QListWidgetItem(purpose['name'], self.lstCategories) item.setData(QtCore.Qt.UserRole, purpose['key']) self.lstCategories.addItem(item) # Check if layer keywords are already assigned purpose_keyword = self.parent.get_existing_keyword('layer_purpose') # Overwrite the purpose_keyword if it's KW mode embedded in IFCW mode if self.parent.parent_step: purpose_keyword = self.parent.\ get_parent_mode_constraints()[0]['key'] # Set values based on existing keywords or parent mode if purpose_keyword: purposes = [] for index in xrange(self.lstCategories.count()): item = self.lstCategories.item(index) purposes.append(item.data(QtCore.Qt.UserRole)) if purpose_keyword in purposes: self.lstCategories.setCurrentRow( purposes.index(purpose_keyword)) self.auto_select_one_item(self.lstCategories)
def generate_classified_legend( analysis, exposure, hazard, debug_mode): """Generate an ordered python structure with the classified symbology. :param analysis: The analysis layer. :type analysis: QgsVectorLayer :param exposure: The exposure layer. :type exposure: QgsVectorLayer :param hazard: The hazard layer. :type hazard: QgsVectorLayer :param debug_mode: Boolean if run in debug mode. :type debug_mode: bool :return: The ordered dictionary to use to build the classified style. :rtype: OrderedDict """ # We need to read the analysis layer to get the number of features. analysis_row = analysis.getFeatures().next() # Let's style the hazard class in each layers. hazard_classification = hazard.keywords['classification'] hazard_classification = definition(hazard_classification) # Let's check if there is some thresholds: thresholds = hazard.keywords.get('thresholds') if thresholds: hazard_unit = hazard.keywords.get('continuous_hazard_unit') hazard_unit = definition(hazard_unit)['abbreviation'] else: hazard_unit = None exposure = exposure.keywords['exposure'] exposure_definitions = definition(exposure) exposure_units = exposure_definitions['units'] exposure_unit = exposure_units[0] coefficient = 1 # We check if can use a greater unit, such as kilometre for instance. if len(exposure_units) > 1: # We use only two units for now. delta = coefficient_between_units( exposure_units[1], exposure_units[0]) all_values_are_greater = True # We check if all values are greater than the coefficient for i, hazard_class in enumerate(hazard_classification['classes']): field_name = hazard_count_field['field_name'] % hazard_class['key'] try: value = analysis_row[field_name] except KeyError: value = 0 if 0 < value < delta: # 0 is fine, we can still keep the second unit. all_values_are_greater = False if all_values_are_greater: # If yes, we can use this unit. exposure_unit = exposure_units[1] coefficient = delta classes = OrderedDict() # In debug mode we don't round number. enable_rounding = not debug_mode for i, hazard_class in enumerate(hazard_classification['classes']): # Get the hazard class name. field_name = hazard_count_field['field_name'] % hazard_class['key'] # Get the number of affected feature by this hazard class. try: value = analysis_row[field_name] except KeyError: # The field might not exist if no feature impacted in this hazard # zone. value = 0 value = format_number( value, enable_rounding, exposure_definitions['use_population_rounding'], coefficient) minimum = None maximum = None # Check if we need to add thresholds. if thresholds: if i == 0: minimum = thresholds[hazard_class['key']][0] elif i == len(hazard_classification['classes']) - 1: maximum = thresholds[hazard_class['key']][1] else: minimum = thresholds[hazard_class['key']][0] maximum = thresholds[hazard_class['key']][1] label = _format_label( hazard_class=hazard_class['name'], value=value, exposure_unit=exposure_unit['abbreviation'], minimum=minimum, maximum=maximum, hazard_unit=hazard_unit) classes[hazard_class['key']] = (hazard_class['color'], label) if exposure_definitions['display_not_exposed'] or debug_mode: classes[not_exposed_class['key']] = _add_not_exposed( analysis_row, enable_rounding, exposure_definitions['use_population_rounding'], exposure_unit['abbreviation'], coefficient) return classes