Example #1
0
    def layer_changed(self, layer):
        """Enable or disable keywords editor icon when active layer changes.

        :param layer: The layer that is now active.
        :type layer: QgsMapLayer
        """
        if not layer:
            enable_keyword_wizard = False
        elif not hasattr(layer, 'providerType'):
            enable_keyword_wizard = False
        elif layer.providerType() == 'wms':
            enable_keyword_wizard = False
        elif is_raster_layer(layer) and layer.bandCount() > 1:
            enable_keyword_wizard = False
        else:
            enable_keyword_wizard = True

        try:
            if layer:
                if is_raster_layer(layer):
                    enable_field_mapping_tool = False
                else:
                    keywords = KeywordIO().read_keywords(layer)
                    layer_purpose = keywords.get('layer_purpose')

                    if not layer_purpose:
                        enable_field_mapping_tool = False

                    if layer_purpose == layer_purpose_exposure['key']:
                        layer_subcategory = keywords.get('exposure')
                    elif layer_purpose == layer_purpose_hazard['key']:
                        layer_subcategory = keywords.get('hazard')
                    else:
                        layer_subcategory = None
                    field_groups = get_field_groups(
                        layer_purpose, layer_subcategory)
                    if len(field_groups) == 0:
                        # No field group, disable field mapping tool.
                        enable_field_mapping_tool = False
                    else:
                        enable_field_mapping_tool = True
            else:
                enable_field_mapping_tool = False
        except (KeywordNotFoundError, NoKeywordsFoundError, MetadataReadError):
            # No keywords, disable field mapping tool.
            enable_field_mapping_tool = False

        self.action_keywords_wizard.setEnabled(enable_keyword_wizard)
        self.action_field_mapping.setEnabled(enable_field_mapping_tool)
Example #2
0
    def layer_changed(self, layer):
        """Enable or disable keywords editor icon when active layer changes.

        :param layer: The layer that is now active.
        :type layer: QgsMapLayer
        """
        if not layer:
            enable_keyword_wizard = False
        elif not hasattr(layer, 'providerType'):
            enable_keyword_wizard = False
        elif layer.providerType() == 'wms':
            enable_keyword_wizard = False
        elif is_raster_layer(layer) and layer.bandCount() > 1:
            enable_keyword_wizard = False
        else:
            enable_keyword_wizard = True

        try:
            if layer:
                if is_raster_layer(layer):
                    enable_field_mapping_tool = False
                else:
                    keywords = KeywordIO().read_keywords(layer)
                    layer_purpose = keywords.get('layer_purpose')

                    if not layer_purpose:
                        enable_field_mapping_tool = False

                    if layer_purpose == layer_purpose_exposure['key']:
                        layer_subcategory = keywords.get('exposure')
                    elif layer_purpose == layer_purpose_hazard['key']:
                        layer_subcategory = keywords.get('hazard')
                    else:
                        layer_subcategory = None
                    field_groups = get_field_groups(layer_purpose,
                                                    layer_subcategory)
                    if len(field_groups) == 0:
                        # No field group, disable field mapping tool.
                        enable_field_mapping_tool = False
                    else:
                        enable_field_mapping_tool = True
            else:
                enable_field_mapping_tool = False
        except (KeywordNotFoundError, NoKeywordsFoundError, MetadataReadError):
            # No keywords, disable field mapping tool.
            enable_field_mapping_tool = False

        self.action_keywords_wizard.setEnabled(enable_keyword_wizard)
        self.action_field_mapping.setEnabled(enable_field_mapping_tool)
Example #3
0
    def on_lstFields_itemSelectionChanged(self):
        """Update field description label and unlock the Next button.

        .. note:: This is an automatic Qt slot
           executed when the field selection changes.
        """
        self.clear_further_steps()
        field = self.selected_field()
        # Exit if no selection
        if not field:
            return
        # Exit if the selected field comes from a previous wizard run (vector)
        if is_raster_layer(self.parent.layer):
            return
        fields = self.parent.layer.dataProvider().fields()
        field_index = fields.indexFromName(field)
        # Exit if the selected field comes from a previous wizard run
        if field_index < 0:
            return
        field_type = fields.field(field).typeName()
        field_index = fields.indexFromName(self.selected_field())
        unique_values = self.parent.layer.uniqueValues(field_index)[0:48]
        unique_values_str = [
            i is not None and unicode(i) or 'NULL'
            for i in unique_values]
        if unique_values != self.parent.layer.uniqueValues(field_index):
            unique_values_str += ['...']
        desc = '<br/>%s: %s<br/><br/>' % (self.tr('Field type'), field_type)
        desc += self.tr('Unique values: %s') % ', '.join(unique_values_str)
        self.lblDescribeField.setText(desc)
        # Enable the next buttonlayer_purpose_aggregation
        self.parent.pbnNext.setEnabled(True)
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        is_raster = is_raster_layer(self.parent.layer)
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()
        has_unit = subcategory.get('units') or subcategory.get(
            'continuous_hazard_units')
        selected_layer_mode = self.selected_layermode()

        # continuous
        if selected_layer_mode == layer_mode_continuous and has_unit:
            new_step = self.parent.step_kw_unit
        # no unit and vector
        elif not is_raster:
            new_step = self.parent.step_kw_field
        # no unit and raster
        elif is_raster:
            new_step = self.parent.step_kw_multi_classifications
        else:
            raise InvalidWizardStep

        return new_step
Example #5
0
    def on_lstFields_itemSelectionChanged(self):
        """Update field description label and unlock the Next button.

        .. note:: This is an automatic Qt slot
           executed when the field selection changes.
        """
        field = self.selected_field()
        # Exit if no selection
        if not field:
            return
        # Exit if the selected field comes from a previous wizard run (vector)
        if is_raster_layer(self.parent.layer):
            return
        fields = self.parent.layer.dataProvider().fields()
        field_index = fields.indexFromName(field)
        # Exit if the selected field comes from a previous wizard run
        if field_index < 0:
            return
        field_type = fields.field(field).typeName()
        field_index = fields.indexFromName(self.selected_field())
        unique_values = self.parent.layer.uniqueValues(field_index)[0:48]
        unique_values_str = [
            i is not None and unicode(i) or 'NULL' for i in unique_values
        ]
        if unique_values != self.parent.layer.uniqueValues(field_index):
            unique_values_str += ['...']
        desc = '<br/>%s: %s<br/><br/>' % (self.tr('Field type'), field_type)
        desc += self.tr('Unique values: %s') % ', '.join(unique_values_str)
        self.lblDescribeField.setText(desc)
        # Enable the next buttonlayer_purpose_aggregation
        self.parent.pbnNext.setEnabled(True)
    def classifications_for_layer(self):
        """Return a list of valid classifications for a layer.

        :returns: A list where each value represents a valid classification.
        :rtype: list
        """
        layer_geometry_id = self.parent.get_layer_geometry_id()
        layer_mode_id = self.parent.step_kw_layermode.\
            selected_layermode()['key']
        subcategory_id = self.parent.step_kw_subcategory.\
            selected_subcategory()['key']
        if self.parent.step_kw_purpose.\
                selected_purpose() == layer_purpose_hazard:
            hazard_category_id = self.parent.step_kw_hazard_category.\
                selected_hazard_category()['key']
            if is_raster_layer(self.parent.layer):
                return self.impact_function_manager.\
                    raster_hazards_classifications_for_layer(
                        subcategory_id,
                        layer_geometry_id,
                        layer_mode_id,
                        hazard_category_id)
            else:
                return self.impact_function_manager\
                    .vector_hazards_classifications_for_layer(
                        subcategory_id,
                        layer_geometry_id,
                        layer_mode_id,
                        hazard_category_id)
        else:
            # There are no classifications for exposures defined yet, apart
            # from postprocessor_classification, processed paralelly
            return []
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to.
        :rtype: WizardStep instance or None
        """
        if self.layer_purpose != layer_purpose_aggregation:
            subcategory = self.parent.step_kw_subcategory.\
                selected_subcategory()
        else:
            subcategory = {'key': None}

        if is_raster_layer(self.parent.layer):
            return self.parent.step_kw_source

        # Check if it can go to inasafe field step
        inasafe_fields = get_non_compulsory_fields(
            self.layer_purpose['key'], subcategory['key'])

        if not skip_inasafe_field(self.parent.layer, inasafe_fields):
            return self.parent.step_kw_inasafe_fields

        # Check if it can go to inasafe default field step
        default_inasafe_fields = get_fields(
            self.layer_purpose['key'],
            subcategory['key'],
            replace_null=True,
            in_group=False
        )
        if default_inasafe_fields:
            return self.parent.step_kw_default_inasafe_fields

        # Any other case
        return self.parent.step_kw_source
    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)
        geom = 'raster' if is_raster_layer(self.parent.layer) else 'vector'
        key = '%s_%s_classification' % (
            geom, self.parent.step_kw_purpose.selected_purpose()['key'])
        classification_keyword = self.parent.get_existing_keyword(key)
        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 classifications_for_layer(self):
        """Return a list of valid classifications for a layer.

        :returns: A list where each value represents a valid classification.
        :rtype: list
        """
        layer_geometry_id = self.parent.get_layer_geometry_id()
        layer_mode_id = self.parent.step_kw_layermode.\
            selected_layermode()['key']
        subcategory_id = self.parent.step_kw_subcategory.\
            selected_subcategory()['key']
        if self.parent.step_kw_purpose.\
                selected_purpose() == layer_purpose_hazard:
            hazard_category_id = self.parent.step_kw_hazard_category.\
                selected_hazard_category()['key']
            if is_raster_layer(self.parent.layer):
                return self.impact_function_manager.\
                    raster_hazards_classifications_for_layer(
                        subcategory_id,
                        layer_geometry_id,
                        layer_mode_id,
                        hazard_category_id)
            else:
                return self.impact_function_manager\
                    .vector_hazards_classifications_for_layer(
                        subcategory_id,
                        layer_geometry_id,
                        layer_mode_id,
                        hazard_category_id)
        else:
            # There are no classifications for exposures defined yet, apart
            # from postprocessor_classification, processed paralelly
            return []
Example #10
0
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to.
        :rtype: WizardStep instance or None
        """
        if self.layer_purpose != layer_purpose_aggregation:
            subcategory = self.parent.step_kw_subcategory.\
                selected_subcategory()
        else:
            subcategory = {'key': None}

        if is_raster_layer(self.parent.layer):
            return self.parent.step_kw_source

        # Check if it can go to inasafe field step
        inasafe_fields = get_non_compulsory_fields(
            self.layer_purpose['key'], subcategory['key'])

        if not skip_inasafe_field(self.parent.layer, inasafe_fields):
            return self.parent.step_kw_inasafe_fields

        # Check if it can go to inasafe default field step
        default_inasafe_fields = get_fields(
            self.layer_purpose['key'],
            subcategory['key'],
            replace_null=True,
            in_group=False
        )
        if default_inasafe_fields:
            return self.parent.step_kw_default_inasafe_fields

        # Any other case
        return self.parent.step_kw_source
    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)
        geom = 'raster' if is_raster_layer(self.parent.layer) else 'vector'
        key = '%s_%s_classification' % (
            geom, self.parent.step_kw_purpose.selected_purpose()['key'])
        classification_keyword = self.parent.get_existing_keyword(key)
        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)
Example #12
0
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        is_raster = is_raster_layer(self.parent.layer)
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()
        has_unit = subcategory.get('units') or subcategory.get(
            'continuous_hazard_units')
        selected_layer_mode = self.selected_layermode()

        # continuous
        if selected_layer_mode == layer_mode_continuous and has_unit:
            new_step = self.parent.step_kw_unit
        # no unit and vector
        elif not is_raster:
            new_step = self.parent.step_kw_field
        # no unit and raster
        elif is_raster:
            new_step = self.parent.step_kw_multi_classifications
        else:
            raise InvalidWizardStep

        return new_step
    def set_widgets(self):
        """Set widgets on the LayerMode tab."""
        self.clear_further_steps()
        # Set widgets
        purpose = self.parent.step_kw_purpose.selected_purpose()
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()
        layer_mode_question = (
            layer_mode_raster_question
            if is_raster_layer(self.parent.layer)
            else layer_mode_vector_question)

        self.lblDescribeLayerMode.setText('')
        self.lstLayerModes.clear()
        layer_modes = get_layer_modes(subcategory['key'])
        if is_raster_layer(self.parent.layer):
            layer_mode_question = layer_mode_raster_question
        else:
            if len(layer_modes) == 2:
                layer_mode_question = layer_mode_vector_question
            elif len(layer_modes) == 1:
                if layer_modes[0]['key'] == 'classified':
                    layer_mode_question = layer_mode_vector_classified_confirm
                elif layer_modes[0]['key'] == 'continuous':
                    layer_mode_question = layer_mode_vector_continuous_confirm
                else:
                    layer_mode_question = layer_mode_vector_question
        self.lblSelectLayerMode.setText(
            layer_mode_question % (subcategory['name'], purpose['name']))
        for layer_mode in layer_modes:
            item = QListWidgetItem(layer_mode['name'], self.lstLayerModes)
            item.setData(QtCore.Qt.UserRole, layer_mode['key'])
            self.lstLayerModes.addItem(item)

        # Set value to existing keyword or default value
        layer_mode_keys = [m['key'] for m in layer_modes]
        layer_mode_keyword = self.parent.get_existing_keyword('layer_mode')
        if layer_mode_keyword in layer_mode_keys:
            index = layer_mode_keys.index(layer_mode_keyword)
        elif layer_mode_continuous['key'] in layer_mode_keys:
            # Set default value
            index = layer_mode_keys.index(layer_mode_continuous['key'])
        else:
            index = -1
        self.lstLayerModes.setCurrentRow(index)

        self.auto_select_one_item(self.lstLayerModes)
Example #14
0
    def set_widgets(self):
        """Set widgets on the LayerMode tab."""
        self.clear_further_steps()
        # Set widgets
        purpose = self.parent.step_kw_purpose.selected_purpose()
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()
        layer_mode_question = (
            layer_mode_raster_question
            if is_raster_layer(self.parent.layer)
            else layer_mode_vector_question)

        self.lblDescribeLayerMode.setText('')
        self.lstLayerModes.clear()
        layer_modes = get_layer_modes(subcategory['key'])
        if is_raster_layer(self.parent.layer):
            layer_mode_question = layer_mode_raster_question
        else:
            if len(layer_modes) == 2:
                layer_mode_question = layer_mode_vector_question
            elif len(layer_modes) == 1:
                if layer_modes[0]['key'] == 'classified':
                    layer_mode_question = layer_mode_vector_classified_confirm
                elif layer_modes[0]['key'] == 'continuous':
                    layer_mode_question = layer_mode_vector_continuous_confirm
                else:
                    layer_mode_question = layer_mode_vector_question
        self.lblSelectLayerMode.setText(
            layer_mode_question % (subcategory['name'], purpose['name']))
        for layer_mode in layer_modes:
            item = QListWidgetItem(layer_mode['name'], self.lstLayerModes)
            item.setData(QtCore.Qt.UserRole, layer_mode['key'])
            self.lstLayerModes.addItem(item)

        # Set value to existing keyword or default value
        layer_mode_keys = [m['key'] for m in layer_modes]
        layer_mode_keyword = self.parent.get_existing_keyword('layer_mode')
        if layer_mode_keyword in layer_mode_keys:
            index = layer_mode_keys.index(layer_mode_keyword)
        elif layer_mode_continuous['key'] in layer_mode_keys:
            # Set default value
            index = layer_mode_keys.index(layer_mode_continuous['key'])
        else:
            index = -1
        self.lstLayerModes.setCurrentRow(index)

        self.auto_select_one_item(self.lstLayerModes)
Example #15
0
def check_layer(layer, has_geometry=True):
    """Helper to check layer validity.

    This function wil; raise InvalidLayerError if the layer is invalid.

    :param layer: The layer to check.
    :type layer: QgsMapLayer

    :param has_geometry: If the layer must have a geometry. True by default.
        If it's a raster layer, we will no check this parameter. If we do not
        want to check the geometry type, we can set it to None.
    :type has_geometry: bool,None

    :raise: InvalidLayerError

    :return: Return True if the layer is valid.
    :rtype: bool
    """
    if is_vector_layer(layer) or is_raster_layer(layer):
        if not layer.isValid():
            raise InvalidLayerError('The layer is invalid : %s' %
                                    layer.publicSource())

        if is_vector_layer(layer):

            sub_layers = layer.dataProvider().subLayers()
            if len(sub_layers) > 1:
                names = ';'.join(sub_layers)
                source = layer.source()
                raise InvalidLayerError(
                    tr('The layer should not have many sublayers : {source} : '
                       '{names}').format(source=source, names=names))

            # We only check the geometry if we have at least one feature.

            if layer.geometryType() == QgsWkbTypes.UnknownGeometry and (
                    layer.featureCount() != 0):
                raise InvalidLayerError(
                    tr('The layer has not a valid geometry type.'))

            if layer.wkbType() == QgsWkbTypes.Unknown and (
                    layer.featureCount() != 0):
                raise InvalidLayerError(
                    tr('The layer has not a valid geometry type.'))

            if isinstance(has_geometry, bool) and layer.featureCount() != 0:
                if layer.isSpatial() != has_geometry:
                    raise InvalidLayerError(
                        tr('The layer has not a correct geometry type.'))

    else:
        raise InvalidLayerError(
            tr('The layer is neither a raster nor a vector : {type}').format(
                type=type(layer)))

    return True
Example #16
0
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        if is_raster_layer(self.parent.layer):
            new_step = self.parent.step_kw_band_selector
        else:
            new_step = self.parent.step_kw_layermode
        return new_step
Example #17
0
    def get_previous_step(self):
        """Find the proper step when user clicks the Previous button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        if is_raster_layer(self.parent.layer):
            new_step = self.parent.step_kw_classification
        else:
            new_step = self.parent.step_kw_field
        return new_step
Example #18
0
    def get_previous_step(self):
        """Find the proper step when user clicks the Previous button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        if is_raster_layer(self.parent.layer):
            new_step = self.parent.step_kw_classification
        else:
            new_step = self.parent.step_kw_field
        return new_step
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        if is_raster_layer(self.parent.layer):
            new_step = self.parent.step_kw_band_selector
        else:
            new_step = self.parent.step_kw_layermode
        return new_step
Example #20
0
def check_layer(layer, has_geometry=True):
    """Helper to check layer validity.

    This function wil; raise InvalidLayerError if the layer is invalid.

    :param layer: The layer to check.
    :type layer: QgsMapLayer

    :param has_geometry: If the layer must have a geometry. True by default.
        If it's a raster layer, we will no check this parameter. If we do not
        want to check the geometry type, we can set it to None.
    :type has_geometry: bool

    :raise: InvalidLayerError

    :return: Return True if the layer is valid.
    :rtype: bool
    """
    if is_vector_layer(layer) or is_raster_layer(layer):
        if not layer.isValid():
            raise InvalidLayerError(
                'The layer is invalid : %s' % layer.publicSource())

        if is_vector_layer(layer):

            sub_layers = layer.dataProvider().subLayers()
            if len(sub_layers) > 1:
                names = ';'.join(sub_layers)
                source = layer.source()
                raise InvalidLayerError(
                    tr('The layer should not have many sublayers : {source} : '
                       '{names}').format(source=source, names=names))

            if layer.geometryType() == QGis.UnknownGeometry:
                raise InvalidLayerError(
                    tr('The layer has not a valid geometry type.'))

            if layer.wkbType() == QgsWKBTypes.Unknown:
                raise InvalidLayerError(
                    tr('The layer has not a valid geometry type.'))

            if isinstance(has_geometry, bool):
                if layer.hasGeometryType() != has_geometry:
                    raise InvalidLayerError(
                        tr('The layer has not a correct geometry type.'))

    else:
        raise InvalidLayerError(
            tr('The layer is neither a raster nor a vector : {type}').format(
                type=type(layer)))

    return True
Example #21
0
def check_earthquake_contour_preprocessor(impact_function):
    """Checker for the contour preprocessor.

    :param impact_function: Impact function to check.
    :type impact_function: ImpactFunction

    :return: If the preprocessor can run.
    :rtype: bool
    """
    hazard_key = impact_function.hazard.keywords.get('hazard')
    is_earthquake = hazard_key == hazard_earthquake['key']

    if is_earthquake and is_raster_layer(impact_function.hazard):
        return True
    else:
        return False
Example #22
0
def check_earthquake_contour_preprocessor(impact_function):
    """Checker for the contour preprocessor.

    :param impact_function: Impact function to check.
    :type impact_function: ImpactFunction

    :return: If the preprocessor can run.
    :rtype: bool
    """
    hazard_key = impact_function.hazard.keywords.get('hazard')
    is_earthquake = hazard_key == hazard_earthquake['key']

    if is_earthquake and is_raster_layer(impact_function.hazard):
        return True
    else:
        return False
Example #23
0
def add_impact_layers_to_canvas(impact_function, iface):
    """Helper method to add impact layer to QGIS from impact function.

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

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface
    """
    layers = impact_function.outputs
    name = impact_function.name

    # noinspection PyArgumentList
    root = QgsProject.instance().layerTreeRoot()
    group_analysis = root.insertGroup(0, name)
    group_analysis.setVisible(Qt.Checked)
    for layer in layers:
        # noinspection PyArgumentList
        QgsMapLayerRegistry.instance().addMapLayer(layer, False)
        layer_node = group_analysis.addLayer(layer)

        # set layer title if any
        try:
            title = layer.keywords['title']
            if qgis_version() >= 21800:
                layer.setName(title)
            else:
                layer.setLayerName(title)
        except KeyError:
            pass

        visible_layers = [impact_function.impact.id()]
        print_atlas = setting('print_atlas_report', False, bool)
        if print_atlas:
            visible_layers.append(impact_function.aggregation_summary.id())
        # Let's enable only the more detailed layer. See #2925
        if layer.id() in visible_layers:
            layer_node.setVisible(Qt.Checked)
        elif is_raster_layer(layer):
            layer_node.setVisible(Qt.Checked)
        else:
            layer_node.setVisible(Qt.Unchecked)

        # we need to set analysis_impacted as an active layer because we need
        # to get all qgis variables that we need from this layer for
        # infographic.
        iface.setActiveLayer(impact_function.analysis_impacted)
Example #24
0
def add_impact_layers_to_canvas(impact_function, iface):
    """Helper method to add impact layer to QGIS from impact function.

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

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface
    """
    layers = impact_function.outputs
    name = impact_function.name

    # noinspection PyArgumentList
    root = QgsProject.instance().layerTreeRoot()
    group_analysis = root.insertGroup(0, name)
    group_analysis.setVisible(Qt.Checked)
    for layer in layers:
        # noinspection PyArgumentList
        QgsMapLayerRegistry.instance().addMapLayer(layer, False)
        layer_node = group_analysis.addLayer(layer)

        # set layer title if any
        try:
            title = layer.keywords['title']
            if qgis_version() >= 21800:
                layer.setName(title)
            else:
                layer.setLayerName(title)
        except KeyError:
            pass

        visible_layers = [impact_function.impact.id()]
        print_atlas = setting('print_atlas_report', False, bool)
        if print_atlas:
            visible_layers.append(impact_function.aggregation_summary.id())
        # Let's enable only the more detailed layer. See #2925
        if layer.id() in visible_layers:
            layer_node.setVisible(Qt.Checked)
        elif is_raster_layer(layer):
            layer_node.setVisible(Qt.Checked)
        else:
            layer_node.setVisible(Qt.Unchecked)

        # we need to set analysis_impacted as an active layer because we need
        # to get all qgis variables that we need from this layer for
        # infographic.
        iface.setActiveLayer(impact_function.analysis_impacted)
Example #25
0
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        if is_raster_layer(self.parent.layer):
            if self.parent.step_kw_purpose.\
                    selected_purpose() == layer_purpose_exposure:
                # Only go to resample for continuous raster exposures
                new_step = self.parent.step_kw_resample
            else:
                new_step = self.parent.step_kw_extrakeywords
        else:
            # Currently not used, as we don't have continuous vectors
            new_step = self.parent.step_kw_field
        return new_step
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        if is_raster_layer(self.parent.layer):
            if self.parent.step_kw_purpose.\
                    selected_purpose() == layer_purpose_exposure:
                # Only go to resample for continuous raster exposures
                new_step = self.parent.step_kw_resample
            else:
                new_step = self.parent.step_kw_extrakeywords
        else:
            # Currently not used, as we don't have continuous vectors
            new_step = self.parent.step_kw_field
        return new_step
Example #27
0
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to.
        :rtype: WizardStep instance or None
        """
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()
        is_raster = is_raster_layer(self.parent.layer)
        has_classifications = get_classifications(subcategory['key'])

        # Vector
        if not is_raster:
            return self.parent.step_kw_field
        # Raster and has classifications
        elif has_classifications:
            return self.parent.step_kw_multi_classifications
        # else go to source
        return self.parent.step_kw_source
Example #28
0
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to.
        :rtype: WizardStep instance or None
        """
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()
        is_raster = is_raster_layer(self.parent.layer)
        has_classifications = get_classifications(subcategory['key'])

        # Vector
        if not is_raster:
            return self.parent.step_kw_field
        # Raster and has classifications
        elif has_classifications:
            return self.parent.step_kw_multi_classifications
        # else go to source
        return self.parent.step_kw_source
Example #29
0
def geometry_type(layer):
    """Retrieve the geometry type: point, line, polygon or raster for a layer.

    :param layer: The layer.
    :type layer: QgsMapLayer

    :return: The definition key.
    :rtype: basestring
    """
    if is_raster_layer(layer):
        return layer_geometry_raster['key']
    elif is_point_layer(layer):
        return layer_geometry_point['key']
    elif is_line_layer(layer):
        return layer_geometry_line['key']
    elif is_polygon_layer(layer):
        return layer_geometry_polygon['key']
    else:
        return None
Example #30
0
def geometry_type(layer):
    """Retrieve the geometry type: point, line, polygon or raster for a layer.

    :param layer: The layer.
    :type layer: QgsMapLayer

    :return: The definition key.
    :rtype: basestring
    """
    if is_raster_layer(layer):
        return layer_geometry_raster['key']
    elif is_point_layer(layer):
        return layer_geometry_point['key']
    elif is_line_layer(layer):
        return layer_geometry_line['key']
    elif is_polygon_layer(layer):
        return layer_geometry_polygon['key']
    else:
        return None
Example #31
0
    def selected_allowresampling(self):
        """Obtain the allow_resampling state selected by user.

        .. note:: Returns none if not set or not relevant

        :returns: Value of the allow_resampling or None for not-set.
        :rtype: boolean or None
        """
        if not is_raster_layer(self.parent.layer):
            return None

        if self.parent.step_kw_purpose.\
                selected_purpose() != layer_purpose_exposure:
            return None

        # Only return false if checked, otherwise None for not-set.
        if self.chkAllowResample.isChecked():
            return False
        else:
            return None
Example #32
0
    def layer_changed(self, layer):
        """Enable or disable keywords editor icon when active layer changes.

        :param layer: The layer that is now active.
        :type layer: QgsMapLayer
        """
        if not layer:
            self._disable_keyword_tools()
            return
        if not hasattr(layer, 'providerType'):
            self._disable_keyword_tools()
            return
        if layer.providerType() == 'wms':
            self._disable_keyword_tools()
            return
        if is_raster_layer(layer) and layer.bandCount() > 1:
            self._disable_keyword_tools()
            return

        self.action_keywords_wizard.setEnabled(True)
Example #33
0
    def selected_allowresampling(self):
        """Obtain the allow_resampling state selected by user.

        .. note:: Returns none if not set or not relevant

        :returns: Value of the allow_resampling or None for not-set.
        :rtype: boolean or None
        """
        if not is_raster_layer(self.parent.layer):
            return None

        if self.parent.step_kw_purpose.\
                selected_purpose() != layer_purpose_exposure:
            return None

        # Only return false if checked, otherwise None for not-set.
        if self.chkAllowResample.isChecked():
            return False
        else:
            return None
Example #34
0
    def layer_changed(self, layer):
        """Enable or disable keywords editor icon when active layer changes.

        :param layer: The layer that is now active.
        :type layer: QgsMapLayer
        """
        if not layer:
            self._disable_keyword_tools()
            return
        if not hasattr(layer, 'providerType'):
            self._disable_keyword_tools()
            return
        if layer.providerType() == 'wms':
            self._disable_keyword_tools()
            return
        if is_raster_layer(layer) and layer.bandCount() > 1:
            self._disable_keyword_tools()
            return

        self.action_keywords_wizard.setEnabled(True)
Example #35
0
    def get_layer_geometry_key(self, layer=None):
        """Obtain layer mode of a given layer.

        If no layer specified, the current layer is used

        :param layer : layer to examine
        :type layer: QgsMapLayer or None

        :returns: The layer mode.
        :rtype: str
        """
        if not layer:
            layer = self.layer
        if is_raster_layer(layer):
            return layer_geometry_raster['key']
        elif is_point_layer(layer):
            return layer_geometry_point['key']
        elif is_polygon_layer(layer):
            return layer_geometry_polygon['key']
        else:
            return layer_geometry_line['key']
Example #36
0
    def get_layer_geometry_id(self, layer=None):
        """Obtain layer mode of a given layer.

        If no layer specified, the current layer is used

        :param layer : layer to examine
        :type layer: QgsMapLayer or None

        :returns: The layer mode.
        :rtype: str
        """
        if not layer:
            layer = self.layer
        if is_raster_layer(layer):
            return 'raster'
        elif is_point_layer(layer):
            return 'point'
        elif is_polygon_layer(layer):
            return 'polygon'
        else:
            return 'line'
Example #37
0
def add_impact_layers_to_canvas(impact_function, iface):
    """Helper method to add impact layer to QGIS from impact function.

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

    :param iface: QGIS QGisAppInterface instance.
    :type iface: QGisAppInterface
    """
    layers = impact_function.outputs
    name = impact_function.name

    # noinspection PyArgumentList
    root = QgsProject.instance().layerTreeRoot()
    group_analysis = root.insertGroup(0, name)
    group_analysis.setVisible(Qt.Checked)
    for layer in layers:
        # noinspection PyArgumentList
        QgsMapLayerRegistry.instance().addMapLayer(layer, False)
        layer_node = group_analysis.addLayer(layer)

        # set layer title if any
        try:
            title = layer.keywords['title']
            if qgis_version() >= 21800:
                layer.setName(title)
            else:
                layer.setLayerName(title)
        except KeyError:
            pass

        # Let's enable only the more detailed layer. See #2925
        if layer.id() == impact_function.impact.id():
            layer_node.setVisible(Qt.Checked)
            iface.setActiveLayer(layer)
        elif is_raster_layer(layer):
            layer_node.setVisible(Qt.Checked)
        else:
            layer_node.setVisible(Qt.Unchecked)
Example #38
0
    def set_wizard_step_description(self):
        """Set the text for description."""
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()
        field = self.parent.step_kw_field.selected_fields()
        is_raster = is_raster_layer(self.parent.layer)

        if is_raster:
            if self.layer_mode == layer_mode_continuous:
                text_label = multiple_continuous_hazard_classifications_raster
            else:
                text_label = multiple_classified_hazard_classifications_raster
            # noinspection PyAugmentAssignment
            text_label = text_label % (
                subcategory['name'], self.layer_purpose['name'])
        else:
            if self.layer_mode == layer_mode_continuous:
                text_label = multiple_continuous_hazard_classifications_vector
            else:
                text_label = multiple_classified_hazard_classifications_vector
            # noinspection PyAugmentAssignment
            text_label = text_label % (
                subcategory['name'], self.layer_purpose['name'], field)

        self.multi_classifications_label.setText(text_label)
Example #39
0
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        if self.parent.step_kw_layermode.\
                selected_layermode() == layer_mode_classified:
            if is_point_layer(self.parent.layer) \
                    and self.parent.step_kw_purpose.\
                    selected_purpose() == layer_purpose_hazard:
                # Skip FIELD and CLASSIFICATION for point volcanos
                new_step = self.parent.step_kw_extrakeywords
            elif self.parent.step_kw_classification.\
                    classifications_for_layer():
                new_step = self.parent.step_kw_classification
            elif is_raster_layer(self.parent.layer):
                new_step = self.parent.step_kw_extrakeywords
            else:
                new_step = self.parent.step_kw_field
        else:
            # CONTINUOUS DATA, ALL GEOMETRIES
            new_step = self.parent.step_kw_unit
        return new_step
Example #40
0
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        if self.parent.step_kw_layermode.\
                selected_layermode() == layer_mode_classified:
            if is_point_layer(self.parent.layer) \
                    and self.parent.step_kw_purpose.\
                    selected_purpose() == layer_purpose_hazard:
                # Skip FIELD and CLASSIFICATION for point volcanos
                new_step = self.parent.step_kw_extrakeywords
            elif self.parent.step_kw_classification.\
                    classifications_for_layer():
                new_step = self.parent.step_kw_classification
            elif is_raster_layer(self.parent.layer):
                new_step = self.parent.step_kw_extrakeywords
            else:
                new_step = self.parent.step_kw_field
        else:
            # CONTINUOUS DATA, ALL GEOMETRIES
            new_step = self.parent.step_kw_unit
        return new_step
    def set_wizard_step_description(self):
        """Set the text for description."""
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()
        field = self.parent.step_kw_field.selected_fields()
        is_raster = is_raster_layer(self.parent.layer)

        if is_raster:
            if self.layer_mode == layer_mode_continuous:
                text_label = multiple_continuous_hazard_classifications_raster
            else:
                text_label = multiple_classified_hazard_classifications_raster
            # noinspection PyAugmentAssignment
            text_label = text_label % (
                subcategory['name'], self.layer_purpose['name'])
        else:
            if self.layer_mode == layer_mode_continuous:
                text_label = multiple_continuous_hazard_classifications_vector
            else:
                text_label = multiple_classified_hazard_classifications_vector
            # noinspection PyAugmentAssignment
            text_label = text_label % (
                subcategory['name'], self.layer_purpose['name'], field)

        self.multi_classifications_label.setText(text_label)
Example #42
0
    def get_keywords(self):
        """Obtain the state of the dialog as a keywords dict.

        :returns: Keywords reflecting the state of the dialog.
        :rtype: dict
        """
        keywords = {}
        keywords['layer_geometry'] = self.get_layer_geometry_id()
        if self.step_kw_purpose.selected_purpose():
            keywords['layer_purpose'] = self.step_kw_purpose.\
                selected_purpose()['key']
            if keywords['layer_purpose'] == 'aggregation':
                keywords.update(
                    self.step_kw_aggregation.get_aggregation_attributes())
        if self.step_kw_subcategory.selected_subcategory():
            key = self.step_kw_purpose.selected_purpose()['key']
            keywords[key] = self.step_kw_subcategory.\
                selected_subcategory()['key']
        if self.step_kw_hazard_category.selected_hazard_category():
            keywords['hazard_category'] \
                = self.step_kw_hazard_category.\
                selected_hazard_category()['key']
        if self.step_kw_layermode.selected_layermode():
            keywords['layer_mode'] = self.step_kw_layermode.\
                selected_layermode()['key']
        if self.step_kw_unit.selected_unit():
            if self.step_kw_purpose.selected_purpose() == layer_purpose_hazard:
                key = continuous_hazard_unit['key']
            else:
                key = exposure_unit['key']
            keywords[key] = self.step_kw_unit.selected_unit()['key']
        if self.step_kw_resample.selected_allowresampling() is not None:
            keywords['allow_resampling'] = (
                self.step_kw_resample.selected_allowresampling() and
                'true' or 'false')
        if self.step_kw_field.lstFields.currentItem():
            field_keyword = self.field_keyword_for_the_layer()
            keywords[field_keyword] = self.step_kw_field.\
                lstFields.currentItem().text()
        if self.step_kw_classification.selected_classification():
            geom = 'raster' if is_raster_layer(self.layer) else 'vector'
            key = '%s_%s_classification' % (
                geom, self.step_kw_purpose.selected_purpose()['key'])
            keywords[key] = self.step_kw_classification.\
                selected_classification()['key']
        value_map = self.step_kw_classify.selected_mapping()
        if value_map:
            if self.step_kw_classification.selected_classification():
                # hazard mapping
                keyword = 'value_map'
            else:
                # exposure mapping
                keyword = 'value_mapping'
            keywords[keyword] = json.dumps(value_map)

        name_field = self.step_kw_name_field.selected_field()
        if name_field:
            keywords['name_field'] = name_field

        population_field = self.step_kw_population_field.selected_field()
        if population_field:
            keywords['population_field'] = population_field

        extra_keywords = self.step_kw_extrakeywords.selected_extra_keywords()
        for key in extra_keywords:
            keywords[key] = extra_keywords[key]
        if self.step_kw_source.leSource.text():
            keywords['source'] = get_unicode(
                self.step_kw_source.leSource.text())
        if self.step_kw_source.leSource_url.text():
            keywords['url'] = get_unicode(
                self.step_kw_source.leSource_url.text())
        if self.step_kw_source.leSource_scale.text():
            keywords['scale'] = get_unicode(
                self.step_kw_source.leSource_scale.text())
        if self.step_kw_source.ckbSource_date.isChecked():
            keywords['date'] = self.step_kw_source.dtSource_date.dateTime()
        if self.step_kw_source.leSource_license.text():
            keywords['license'] = get_unicode(
                self.step_kw_source.leSource_license.text())
        if self.step_kw_title.leTitle.text():
            keywords['title'] = get_unicode(self.step_kw_title.leTitle.text())

        return keywords
Example #43
0
    def setup_left_panel(self):
        """Setup the UI for left panel.

        Generate all exposure, combobox, and edit button.
        """
        hazard = self.parent.step_kw_subcategory.selected_subcategory()
        left_panel_heading = QLabel(tr('Classifications'))
        left_panel_heading.setFont(big_font)
        self.left_layout.addWidget(left_panel_heading)

        inner_left_layout = QGridLayout()

        row = 0
        for exposure in exposure_all:
            special_case = False
            # Filter out unsupported exposure for the hazard
            if exposure in hazard['disabled_exposures']:
                # Remove from the storage if the exposure is disabled
                if self.layer_mode == layer_mode_continuous:
                    if exposure['key'] in self.thresholds:
                        self.thresholds.pop(exposure['key'])
                else:
                    if exposure['key'] in self.value_maps:
                        self.value_maps.pop(exposure['key'])
                continue
            # Trick for EQ raster for population #3853
            if exposure == exposure_population and hazard == hazard_earthquake:
                if is_raster_layer(self.parent.layer):
                    if self.layer_mode == layer_mode_continuous:
                        self.use_default_thresholds = True
                        special_case = True
                        # Set classification for EQ Raster for Population
                        self.thresholds[exposure_population['key']] = {
                            earthquake_mmi_scale['key']: {
                                'classes': default_classification_thresholds(
                                    earthquake_mmi_scale),
                                'active': True
                            }
                        }

            # Add label
            # Hazard on Exposure Classifications
            label = tr(
                '{hazard_name} on {exposure_name} Classifications').format(
                hazard_name=hazard['name'],
                exposure_name=exposure['name']
            )
            exposure_label = QLabel(label)

            # Add combo box
            exposure_combo_box = QComboBox()
            hazard_classifications = hazard.get('classifications')
            exposure_combo_box.addItem(tr('No classifications'))
            exposure_combo_box.setItemData(
                0, None, Qt.UserRole)

            current_index = 0
            i = 0
            # Iterate through all available hazard classifications
            for hazard_classification in hazard_classifications:
                # Skip if the classification is not for the exposure
                if 'exposures' in hazard_classification:
                    if exposure not in hazard_classification['exposures']:
                        continue
                exposure_combo_box.addItem(hazard_classification['name'])
                exposure_combo_box.setItemData(
                    i + 1, hazard_classification, Qt.UserRole)
                if self.layer_mode == layer_mode_continuous:
                    current_hazard_classifications = self.thresholds.get(
                        exposure['key'])
                else:
                    current_hazard_classifications = self.value_maps.get(
                        exposure['key'])
                if current_hazard_classifications:
                    current_hazard_classification = \
                        current_hazard_classifications.get(
                            hazard_classification['key'])
                    if current_hazard_classification:
                        is_active = current_hazard_classification.get('active')
                        if is_active:
                            current_index = i + 1
                i += 1
            # Set current classification
            exposure_combo_box.setCurrentIndex(current_index)

            # Add edit button
            exposure_edit_button = QPushButton(tr('Edit'))

            # For special case. Raster EQ on Population.
            if special_case:
                mmi_index = exposure_combo_box.findText(
                    earthquake_mmi_scale['name'])
                exposure_combo_box.setCurrentIndex(mmi_index)
                exposure_combo_box.setEnabled(False)
                exposure_edit_button.setEnabled(False)
                tool_tip_message = tr(
                    'InaSAFE use default classification for Raster Earthquake '
                    'hazard on population.')
                exposure_label.setToolTip(tool_tip_message)
                exposure_combo_box.setToolTip(tool_tip_message)
                exposure_edit_button.setToolTip(tool_tip_message)

            else:
                if current_index == 0:
                    # Disable if there is no classification chosen.
                    exposure_edit_button.setEnabled(False)
                exposure_edit_button.clicked.connect(
                    partial(self.edit_button_clicked,
                        edit_button=exposure_edit_button,
                        exposure_combo_box=exposure_combo_box,
                        exposure=exposure))
                exposure_combo_box.currentIndexChanged.connect(
                    partial(
                        self.classifications_combo_box_changed,
                        exposure=exposure,
                        exposure_combo_box=exposure_combo_box,
                        edit_button=exposure_edit_button))

            # Arrange in layout
            inner_left_layout.addWidget(exposure_label, row, 0)
            inner_left_layout.addWidget(exposure_combo_box, row, 1)
            inner_left_layout.addWidget(exposure_edit_button, row, 2)

            # Adding to step's attribute
            self.exposures.append(exposure)
            self.exposure_combo_boxes.append(exposure_combo_box)
            self.exposure_edit_buttons.append(exposure_edit_button)
            self.exposure_labels.append(label)
            if special_case:
                self.special_case_index = len(self.exposures) - 1

            row += 1

        self.left_layout.addLayout(inner_left_layout)
        # To push the inner_left_layout up
        self.left_layout.addStretch(1)
Example #44
0
def layer_description_html(layer, keywords=None):
    """Form a html description of a given layer based on the layer
       parameters and keywords if provided

    :param layer: The layer to get the description
    :type layer: QgsMapLayer

    :param keywords: The layer keywords
    :type keywords: None, dict

    :returns: The html description in tabular format,
        ready to use in a label or tool tip.
    :rtype: str
    """

    if keywords and 'keyword_version' in keywords:
        keyword_version = str(keywords['keyword_version'])
    else:
        keyword_version = None

    if (keywords and keyword_version
            and is_keyword_version_supported(keyword_version)):
        # The layer has valid keywords
        purpose = keywords.get('layer_purpose')
        if purpose == layer_purpose_hazard['key']:
            subcategory = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (
                tr('Hazard'), keywords.get(purpose))
            unit = keywords.get('continuous_hazard_unit')
        elif purpose == layer_purpose_exposure['key']:
            subcategory = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (
                tr('Exposure'), keywords.get(purpose))
            unit = keywords.get('exposure_unit')
        else:
            subcategory = ''
            unit = None
        if keywords.get('layer_mode') == layer_mode_classified['key']:
            unit = tr('classified data')
        if unit:
            unit = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (tr('Unit'),
                                                                 unit)

        description = """
            <table border="0" width="100%%">
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            %s
            %s
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            </table>
        """ % (tr('Title'), keywords.get('title'), tr('Purpose'),
               keywords.get('layer_purpose'), subcategory, unit, tr('Source'),
               keywords.get('source'))
    elif keywords:
        # The layer has keywords, but the version is wrong
        layer_version = keyword_version or tr('No Version')
        description = tr(
            'Your layer\'s keyword\'s version ({layer_version}) does not '
            'match with your InaSAFE version ({inasafe_version}). If you wish '
            'to use it as an exposure, hazard, or aggregation layer in an '
            'analysis, please update the keywords. Click Next if you want to '
            'assign keywords now.').format(layer_version=layer_version,
                                           inasafe_version=get_version())
    else:
        # The layer is keywordless
        if is_point_layer(layer):
            geom_type = layer_geometry_point['key']
        elif is_polygon_layer(layer):
            geom_type = layer_geometry_polygon['key']
        else:
            geom_type = layer_geometry_line['key']

        # hide password in the layer source
        source = layer.publicSource()
        description = """
            %s<br/><br/>
            <b>%s</b>: %s<br/>
            <b>%s</b>: %s<br/><br/>
            %s
        """ % (tr('This layer has no valid keywords assigned'), tr('SOURCE'),
               source, tr('TYPE'), is_raster_layer(layer) and 'raster'
               or 'vector (%s)' % geom_type,
               tr('In the next step you will be able' +
                  ' to assign keywords to this layer.'))
    return description
Example #45
0
    def get_keywords(self):
        """Obtain the state of the dialog as a keywords dict.

        :returns: Keywords reflecting the state of the dialog.
        :rtype: dict
        """
        keywords = {}
        keywords['layer_geometry'] = self.get_layer_geometry_id()
        if self.step_kw_purpose.selected_purpose():
            keywords['layer_purpose'] = self.step_kw_purpose.\
                selected_purpose()['key']
            if keywords['layer_purpose'] == 'aggregation':
                keywords.update(
                    self.step_kw_aggregation.get_aggregation_attributes())
        if self.step_kw_subcategory.selected_subcategory():
            key = self.step_kw_purpose.selected_purpose()['key']
            keywords[key] = self.step_kw_subcategory.\
                selected_subcategory()['key']
        if self.step_kw_hazard_category.selected_hazard_category():
            keywords['hazard_category'] \
                = self.step_kw_hazard_category.\
                selected_hazard_category()['key']
        if self.step_kw_layermode.selected_layermode():
            keywords['layer_mode'] = self.step_kw_layermode.\
                selected_layermode()['key']
        if self.step_kw_unit.selected_unit():
            if self.step_kw_purpose.selected_purpose() == layer_purpose_hazard:
                key = continuous_hazard_unit['key']
            else:
                key = exposure_unit['key']
            keywords[key] = self.step_kw_unit.selected_unit()['key']
        if self.step_kw_resample.selected_allowresampling() is not None:
            keywords['allow_resampling'] = (
                self.step_kw_resample.selected_allowresampling() and 'true'
                or 'false')
        if self.step_kw_field.lstFields.currentItem():
            field_keyword = self.field_keyword_for_the_layer()
            keywords[field_keyword] = self.step_kw_field.\
                lstFields.currentItem().text()
        if self.step_kw_classification.selected_classification():
            geom = 'raster' if is_raster_layer(self.layer) else 'vector'
            key = '%s_%s_classification' % (
                geom, self.step_kw_purpose.selected_purpose()['key'])
            keywords[key] = self.step_kw_classification.\
                selected_classification()['key']
        value_map = self.step_kw_classify.selected_mapping()
        if value_map:
            if self.step_kw_classification.selected_classification():
                # hazard mapping
                keyword = 'value_map'
            else:
                # exposure mapping
                keyword = 'value_mapping'
            keywords[keyword] = json.dumps(value_map)

        name_field = self.step_kw_name_field.selected_field()
        if name_field:
            keywords['name_field'] = name_field

        population_field = self.step_kw_population_field.selected_field()
        if population_field:
            keywords['population_field'] = population_field

        extra_keywords = self.step_kw_extrakeywords.selected_extra_keywords()
        for key in extra_keywords:
            keywords[key] = extra_keywords[key]
        if self.step_kw_source.leSource.text():
            keywords['source'] = get_unicode(
                self.step_kw_source.leSource.text())
        if self.step_kw_source.leSource_url.text():
            keywords['url'] = get_unicode(
                self.step_kw_source.leSource_url.text())
        if self.step_kw_source.leSource_scale.text():
            keywords['scale'] = get_unicode(
                self.step_kw_source.leSource_scale.text())
        if self.step_kw_source.ckbSource_date.isChecked():
            keywords['date'] = self.step_kw_source.dtSource_date.dateTime()
        if self.step_kw_source.leSource_license.text():
            keywords['license'] = get_unicode(
                self.step_kw_source.leSource_license.text())
        if self.step_kw_title.leTitle.text():
            keywords['title'] = get_unicode(self.step_kw_title.leTitle.text())

        return keywords
Example #46
0
    def unsuitable_layer_description_html(
            self, layer, layer_purpose, keywords=None):
        """Form a html description of a given non-matching layer based on
           the currently selected impact function requirements vs layer\'s
           parameters and keywords if provided, as

        :param layer: The layer to be validated
        :type layer: QgsVectorLayer | QgsRasterLayer

        :param layer_purpose: The layer_purpose the layer is validated for
        :type layer_purpose: string

        :param keywords: The layer keywords
        :type keywords: None, dict

        :returns: The html description in tabular format,
            ready to use in a label or tool tip.
        :rtype: str
        """

        def emphasize(str1, str2):
            """ Compare two strings and emphasize both if differ """
            if str1 != str2:
                str1 = '<i>%s</i>' % str1
                str2 = '<i>%s</i>' % str2
            return (str1, str2)

        # Get allowed subcategory and layer_geometry from IF constraints
        h, e, hc, ec = self.parent.selected_impact_function_constraints()
        imfunc = self.parent.step_fc_function.selected_function()
        lay_req = imfunc['layer_requirements'][layer_purpose]

        if layer_purpose == layer_purpose_hazard['key']:
            layer_purpose_key_name = layer_purpose_hazard['name']
            req_subcategory = h['key']
            req_geometry = hc['key']
        elif layer_purpose == layer_purpose_exposure['key']:
            layer_purpose_key_name = layer_purpose_exposure['name']
            req_subcategory = e['key']
            req_geometry = ec['key']
        else:
            layer_purpose_key_name = layer_purpose_aggregation['name']
            req_subcategory = ''
            # For aggregation layers, only accept polygons
            req_geometry = layer_geometry_polygon['key']
        req_layer_mode = lay_req['layer_mode']['key']

        lay_geometry = self.parent.get_layer_geometry_id(layer)
        lay_purpose = '&nbsp;&nbsp;-'
        lay_subcategory = '&nbsp;&nbsp;-'
        lay_layer_mode = '&nbsp;&nbsp;-'

        if keywords:
            if 'layer_purpose' in keywords:
                lay_purpose = keywords['layer_purpose']
            if layer_purpose in keywords:
                lay_subcategory = keywords[layer_purpose]
            if 'layer_mode' in keywords:
                lay_layer_mode = keywords['layer_mode']

        lay_geometry, req_geometry = emphasize(lay_geometry, req_geometry)
        lay_purpose, layer_purpose = emphasize(lay_purpose, layer_purpose)
        lay_subcategory, req_subcategory = emphasize(
            lay_subcategory, req_subcategory)
        lay_layer_mode, req_layer_mode = emphasize(
            lay_layer_mode, req_layer_mode)

        # Classification
        classification_row = ''
        if (lay_req['layer_mode'] == layer_mode_classified and
                layer_purpose == layer_purpose_hazard['key']):
            # Determine the keyword key for the classification
            classification_obj = (
                raster_hazard_classification
                if is_raster_layer(layer)
                else vector_hazard_classification)
            classification_key = classification_obj['key']
            classification_key_name = classification_obj['name']
            classification_keys = classification_key + 's'

            if classification_keys in lay_req:
                allowed_classifications = [
                    c['key'] for c in lay_req[classification_keys]]
                req_classifications = ', '.join(allowed_classifications)

                lay_classification = '&nbsp;&nbsp;-'
                if classification_key in keywords:
                    lay_classification = keywords[classification_key]

                if lay_classification not in allowed_classifications:
                    # We already know we want to emphasize them and the test
                    # inside the function will always pass.
                    lay_classification, req_classifications = emphasize(
                        lay_classification, req_classifications)
                classification_row = (
                    (
                        '<tr><td><b>%s</b></td>' +
                        '<td>%s</td><td>%s</td></tr>')
                    % (
                        classification_key_name,
                        lay_classification,
                        req_classifications))

        # Unit
        units_row = ''
        if lay_req['layer_mode'] == layer_mode_continuous:
            # Determine the keyword key for the unit
            unit_obj = (
                continuous_hazard_unit
                if layer_purpose == layer_purpose_hazard['key']
                else exposure_unit)
            unit_key = unit_obj['key']
            unit_key_name = unit_obj['name']
            unit_keys = unit_key + 's'

            if unit_keys in lay_req:
                allowed_units = [c['key'] for c in lay_req[unit_keys]]
                req_units = ', '.join(allowed_units)

                lay_unit = '&nbsp;&nbsp;-'
                if unit_key in keywords:
                    lay_unit = keywords[unit_key]

                if lay_unit not in allowed_units:
                    # We already know we want to emphasize them and the test
                    # inside the function will always pass.
                    lay_unit, req_units = emphasize(lay_unit, req_units)
                units_row = (
                    (
                        '<tr><td><b>%s</b></td>' +
                        '<td>%s</td><td>%s</td></tr>')
                    % (unit_key_name, lay_unit, req_units))

        html = '''
            <table border="0" width="100%%" cellpadding="2">
                <tr><td width="33%%"></td>
                    <td width="33%%"><b>%s</b></td>
                    <td width="33%%"><b>%s</b></td>
                </tr>
                <tr><td><b>%s</b></td><td>%s</td><td>%s</td></tr>
                <tr><td><b>%s</b></td><td>%s</td><td>%s</td></tr>
                <tr><td><b>%s</b></td><td>%s</td><td>%s</td></tr>
                <tr><td><b>%s</b></td><td>%s</td><td>%s</td></tr>
                %s
                %s
            </table>
        ''' % (self.tr('Layer'), self.tr('Required'),
               safe.definitions.layer_geometry['name'],
               lay_geometry, req_geometry,
               safe.definitions.layer_purpose['name'],
               lay_purpose, layer_purpose,
               layer_purpose_key_name, lay_subcategory, req_subcategory,
               safe.definitions.layer_mode['name'],
               lay_layer_mode, req_layer_mode,
               classification_row,
               units_row)
        return html
    def setup_value_mapping_panels(self, classification):
        """Setup value mapping panel in the right panel.

        :param classification: Classification definition.
        :type classification: dict
        """
        # Set text in the label
        layer_purpose = self.parent.step_kw_purpose.selected_purpose()
        layer_subcategory = self.parent.step_kw_subcategory. \
            selected_subcategory()

        if is_raster_layer(self.parent.layer):
            description_text = classify_raster_question % (
                layer_subcategory['name'],
                layer_purpose['name'],
                classification['name'])

            dataset = gdal.Open(self.parent.layer.source(), GA_ReadOnly)
            active_band = self.parent.step_kw_band_selector.selected_band()
            unique_values = numpy.unique(numpy.array(
                dataset.GetRasterBand(active_band).ReadAsArray()))
            field_type = 0
            # Convert datatype to a json serializable type
            if numpy.issubdtype(unique_values.dtype, float):
                unique_values = [float(i) for i in unique_values]
            else:
                unique_values = [int(i) for i in unique_values]
        else:
            field = self.parent.step_kw_field.selected_fields()
            field_index = self.parent.layer.dataProvider().fields(). \
                indexFromName(field)
            field_type = self.parent.layer.dataProvider(). \
                fields()[field_index].type()
            description_text = classify_vector_question % (
                layer_subcategory['name'],
                layer_purpose['name'],
                classification['name'],
                field.upper())
            unique_values = self.parent.layer.uniqueValues(field_index)

        # Set description
        description_label = QLabel(description_text)
        description_label.setWordWrap(True)
        self.right_layout.addWidget(description_label)

        self.list_unique_values = QListWidget()
        self.list_unique_values.setDragDropMode(QAbstractItemView.DragDrop)
        self.list_unique_values.setDefaultDropAction(Qt.MoveAction)

        self.tree_mapping_widget = QTreeWidget()
        self.tree_mapping_widget.setDragDropMode(QAbstractItemView.DragDrop)
        self.tree_mapping_widget.setDefaultDropAction(Qt.MoveAction)
        self.tree_mapping_widget.header().hide()

        self.tree_mapping_widget.itemChanged.connect(
            self.update_dragged_item_flags)

        value_mapping_layout = QHBoxLayout()
        value_mapping_layout.addWidget(self.list_unique_values)
        value_mapping_layout.addWidget(self.tree_mapping_widget)

        self.right_layout.addLayout(value_mapping_layout)

        default_classes = classification['classes']

        # Assign unique values to classes (according to default)
        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        for unique_value in unique_values:
            if unique_value is None or isinstance(
                    unique_value, QPyNullVariant):
                # Don't classify features with NULL value
                continue
            # Capitalization of the value and removing '_' (raw OSM data).
            value_as_string = unicode(unique_value).upper().replace('_', ' ')
            assigned = False
            for default_class in default_classes:
                if 'string_defaults' in default_class:
                    condition_1 = (
                        field_type > 9 and
                        value_as_string in [
                            c.upper() for c in
                            default_class['string_defaults']])
                else:
                    condition_1 = False
                condition_2 = (
                    field_type < 10 and
                    'numeric_default_min' in default_class and
                    'numeric_default_max' in default_class and (
                        default_class['numeric_default_min'] <= unique_value <
                        default_class['numeric_default_max']))
                if condition_1 or condition_2:
                    assigned_values[default_class['key']] += [unique_value]
                    assigned = True
            if not assigned:
                # add to unassigned values list otherwise
                unassigned_values += [unique_value]
        self.populate_classified_values(
            unassigned_values,
            assigned_values,
            default_classes,
            self.list_unique_values,
            self.tree_mapping_widget
        )

        # Current value map for exposure and classification
        available_classifications = self.value_maps.get(
            self.active_exposure['key'])
        if not available_classifications:
            return
        # Get active one
        current_classification = available_classifications.get(
            classification['key'])
        if not current_classification:
            return
        current_value_map = current_classification.get('classes')
        if not current_value_map:
            return

        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        for unique_value in unique_values:
            if unique_value is None or isinstance(
                    unique_value, QPyNullVariant):
                # Don't classify features with NULL value
                continue
            # check in value map
            assigned = False
            for key, value_list in current_value_map.items():
                if unique_value in value_list and key in assigned_values:
                    assigned_values[key] += [unique_value]
                    assigned = True
            if not assigned:
                unassigned_values += [unique_value]
        self.populate_classified_values(
            unassigned_values,
            assigned_values,
            default_classes,
            self.list_unique_values,
            self.tree_mapping_widget
        )
Example #48
0
    def set_widgets(self):
        """Set widgets on the Threshold tab."""
        clear_layout(self.gridLayoutThreshold)

        # Set text in the label
        layer_purpose = self.parent.step_kw_purpose.selected_purpose()
        layer_subcategory = self.parent.step_kw_subcategory.\
            selected_subcategory()
        classification = self.parent.step_kw_classification. \
            selected_classification()

        if is_raster_layer(self.parent.layer):
            statistics = self.parent.layer.dataProvider().bandStatistics(
                1, QgsRasterBandStats.All, self.parent.layer.extent(), 0)
            text = continuous_raster_question % (
                layer_purpose['name'],
                layer_subcategory['name'],
                classification['name'],
                statistics.minimumValue,
                statistics.maximumValue)
        else:
            field_name = self.parent.step_kw_field.selected_fields()
            field_index = self.parent.layer.fields().lookupField(field_name)
            min_value_layer = self.parent.layer.minimumValue(field_index)
            max_value_layer = self.parent.layer.maximumValue(field_index)
            text = continuous_vector_question % (
                layer_purpose['name'],
                layer_subcategory['name'],
                field_name,
                classification['name'],
                min_value_layer,
                max_value_layer)
        self.lblThreshold.setText(text)

        thresholds = self.parent.get_existing_keyword('thresholds')
        selected_unit = self.parent.step_kw_unit.selected_unit()['key']

        self.classes = OrderedDict()
        classes = classification.get('classes')
        # Sort by value, put the lowest first
        classes = sorted(classes, key=lambda k: k['value'])

        for i, the_class in enumerate(classes):
            class_layout = QHBoxLayout()

            # Class label
            class_label = QLabel(the_class['name'])

            # Min label
            min_label = QLabel(tr('Min >'))

            # Min value as double spin
            min_value_input = QDoubleSpinBox()
            # TODO(IS) We can set the min and max depends on the unit, later
            min_value_input.setMinimum(0)
            min_value_input.setMaximum(999999)
            if thresholds.get(the_class['key']):
                min_value_input.setValue(thresholds[the_class['key']][0])
            else:
                default_min = the_class['numeric_default_min']
                if isinstance(default_min, dict):
                    default_min = the_class[
                        'numeric_default_min'][selected_unit]
                min_value_input.setValue(default_min)
            min_value_input.setSingleStep(0.1)

            # Max label
            max_label = QLabel(tr('Max <='))

            # Max value as double spin
            max_value_input = QDoubleSpinBox()
            # TODO(IS) We can set the min and max depends on the unit, later
            max_value_input.setMinimum(0)
            max_value_input.setMaximum(999999)
            if thresholds.get(the_class['key']):
                max_value_input.setValue(thresholds[the_class['key']][1])
            else:
                default_max = the_class['numeric_default_max']
                if isinstance(default_max, dict):
                    default_max = the_class[
                        'numeric_default_max'][selected_unit]
                max_value_input.setValue(default_max)
            max_value_input.setSingleStep(0.1)

            # Add to class_layout
            class_layout.addWidget(min_label)
            class_layout.addWidget(min_value_input)
            # class_layout.addStretch(1)
            class_layout.addWidget(max_label)
            class_layout.addWidget(max_value_input)

            # Add to grid_layout
            self.gridLayoutThreshold.addWidget(class_label, i, 0)
            self.gridLayoutThreshold.addLayout(class_layout, i, 1)

            self.classes[the_class['key']] = [min_value_input, max_value_input]

        self.gridLayoutThreshold.setSpacing(0)

        def min_max_changed(index, the_string):
            """Slot when min or max value change.

            :param index: The index of the double spin.
            :type index: int

            :param the_string: The flag to indicate the min or max value.
            :type the_string: str
            """
            if the_string == 'Max value':
                current_max_value = list(self.classes.values())[index][1]
                target_min_value = list(self.classes.values())[index + 1][0]
                if current_max_value.value() != target_min_value.value():
                    target_min_value.setValue(current_max_value.value())
            elif the_string == 'Min value':
                current_min_value = list(self.classes.values())[index][0]
                target_max_value = list(self.classes.values())[index - 1][1]
                if current_min_value.value() != target_max_value.value():
                    target_max_value.setValue(current_min_value.value())

        # Set behaviour
        for k, v in list(self.classes.items()):
            index = list(self.classes.keys()).index(k)
            if index < len(self.classes) - 1:
                # Max value changed
                v[1].valueChanged.connect(partial(
                    min_max_changed, index=index, the_string='Max value'))
            if index > 0:
                # Min value
                v[0].valueChanged.connect(partial(
                    min_max_changed, index=index, the_string='Min value'))
Example #49
0
    def set_widgets(self):
        """Set widgets on the Classify tab."""
        purpose = self.parent.step_kw_purpose.selected_purpose()
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()

        classification = self.parent.step_kw_classification.\
            selected_classification()
        classification_name = classification['name']

        if is_raster_layer(self.parent.layer):
            self.lblClassify.setText(classify_raster_question % (
                subcategory['name'], purpose['name'], classification_name))
            dataset = gdal.Open(self.parent.layer.source(), GA_ReadOnly)
            active_band = self.parent.step_kw_band_selector.selected_band()
            unique_values = numpy.unique(numpy.array(
                dataset.GetRasterBand(active_band).ReadAsArray()))
            field_type = 0
            # Convert datatype to a json serializable type
            if numpy.issubdtype(unique_values.dtype, float):
                unique_values = [float(i) for i in unique_values]
            else:
                unique_values = [int(i) for i in unique_values]
        else:
            field = self.parent.step_kw_field.selected_fields()
            field_index = self.parent.layer.dataProvider().fields().\
                indexFromName(field)
            field_type = self.parent.layer.dataProvider().\
                fields()[field_index].type()
            self.lblClassify.setText(classify_vector_question % (
                    subcategory['name'], purpose['name'],
                    classification_name, field.upper()))
            unique_values = self.parent.layer.uniqueValues(field_index)

        clean_unique_values = []
        for unique_value in unique_values:
            if unique_value is None or isinstance(
                    unique_value, QPyNullVariant):
                # Don't classify features with NULL value
                continue
            clean_unique_values.append(unique_value)

        # get default classes
        default_classes = classification['classes']
        if classification['key'] == 'data_driven_classes':
            for unique_value in clean_unique_values:
                name = unicode(unique_value).upper().replace('_', ' ')
                default_class = {'key': unique_value,
                                 'name': name,
                                 # 'description': tr('Settlement'),
                                 'string_defaults': [name]}

                default_classes.append(default_class)

        # Assign unique values to classes (according to default)
        unassigned_values = list()
        assigned_values = dict()

        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        for unique_value in clean_unique_values:
            # Capitalization of the value and removing '_' (raw OSM data).
            value_as_string = unicode(unique_value).upper().replace('_', ' ')
            assigned = False
            for default_class in default_classes:
                if 'string_defaults' in default_class:
                    condition_1 = (
                        field_type > 9 and
                        value_as_string in [
                            c.upper() for c in
                            default_class['string_defaults']])
                else:
                    condition_1 = False
                condition_2 = (
                    field_type < 10 and
                    'numeric_default_min' in default_class and
                    'numeric_default_max' in default_class and (
                        default_class['numeric_default_min'] <= unique_value <=
                        default_class['numeric_default_max']))
                if condition_1 or condition_2:
                    assigned_values[default_class['key']] += [unique_value]
                    assigned = True

            if not assigned:
                # add to unassigned values list otherwise
                unassigned_values += [unique_value]

        self.populate_classified_values(
            unassigned_values, assigned_values, default_classes)

        # Overwrite assigned values according to existing keyword (if present).
        # Note the default_classes and unique_values are already loaded!

        value_map = self.parent.get_existing_keyword('value_map')
        value_map_classification_name = self.parent.get_existing_keyword(
            'classification')
        # Do not continue if there is no value_map in existing keywords
        if (value_map is None or
                value_map_classification_name != classification['key']):
            return

        # Do not continue if user selected different field
        field_keyword = self.parent.field_keyword_for_the_layer()
        field = self.parent.get_existing_keyword('inasafe_fields').get(
            field_keyword)
        if (not is_raster_layer(self.parent.layer) and
                field != self.parent.step_kw_field.selected_fields()):
            return

        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        if isinstance(value_map, str):
            try:
                value_map = json.loads(value_map)
            except ValueError:
                return

        for unique_value in clean_unique_values:
            # check in value map
            assigned = False
            for key, value_list in value_map.iteritems():
                if unique_value in value_list and key in assigned_values:
                    assigned_values[key] += [unique_value]
                    assigned = True
            if not assigned:
                unassigned_values += [unique_value]
        self.populate_classified_values(
           unassigned_values, assigned_values, default_classes)
Example #50
0
    def set_widgets(self):
        """Set widgets on the Classify tab."""
        purpose = self.parent.step_kw_purpose.selected_purpose()
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()

        classification = self.parent.step_kw_classification.\
            selected_classification()
        classification_name = classification['name']

        if is_raster_layer(self.parent.layer):
            self.lblClassify.setText(
                classify_raster_question %
                (subcategory['name'], purpose['name'], classification_name))
            dataset = gdal.Open(self.parent.layer.source(), GA_ReadOnly)
            active_band = self.parent.step_kw_band_selector.selected_band()
            unique_values = numpy.unique(
                numpy.array(dataset.GetRasterBand(active_band).ReadAsArray()))
            field_type = 0
            # Convert datatype to a json serializable type
            if numpy.issubdtype(unique_values.dtype, float):
                unique_values = [float(i) for i in unique_values]
            else:
                unique_values = [int(i) for i in unique_values]
        else:
            field = self.parent.step_kw_field.selected_fields()
            field_index = self.parent.layer.fields().indexFromName(field)
            field_type = self.parent.layer.fields()[field_index].type()
            self.lblClassify.setText(classify_vector_question %
                                     (subcategory['name'], purpose['name'],
                                      classification_name, field.upper()))
            unique_values = self.parent.layer.uniqueValues(field_index)

        clean_unique_values = []
        for unique_value in unique_values:
            if (unique_value is None or
                (hasattr(unique_value, 'isNull') and unique_value.isNull())):
                # Don't classify features with NULL value
                continue
            clean_unique_values.append(unique_value)

        # get default classes
        default_classes = deepcopy(classification['classes'])
        if classification['key'] == data_driven_classes['key']:
            for unique_value in clean_unique_values:
                name = str(unique_value).upper().replace('_', ' ')
                default_class = {
                    'key': unique_value,
                    'name': name,
                    # 'description': tr('Settlement'),
                    'string_defaults': [name]
                }

                default_classes.append(default_class)

        # Assign unique values to classes (according to default)
        unassigned_values = list()
        assigned_values = dict()

        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        for unique_value in clean_unique_values:
            # Capitalization of the value and removing '_' (raw OSM data).
            value_as_string = str(unique_value).upper().replace('_', ' ')
            assigned = False
            for default_class in default_classes:
                if 'string_defaults' in default_class:
                    # To make it case insensitive
                    upper_string_defaults = [
                        c.upper() for c in default_class['string_defaults']
                    ]
                    in_string_default = (value_as_string
                                         in upper_string_defaults)
                    condition_1 = field_type > 9 and in_string_default
                else:
                    condition_1 = False
                condition_2 = (
                    field_type < 10 and 'numeric_default_min' in default_class
                    and 'numeric_default_max' in default_class
                    and (default_class['numeric_default_min'] <= unique_value
                         <= default_class['numeric_default_max']))
                if condition_1 or condition_2:
                    assigned_values[default_class['key']] += [unique_value]
                    assigned = True

            if not assigned:
                # add to unassigned values list otherwise
                unassigned_values += [unique_value]

        self.populate_classified_values(unassigned_values, assigned_values,
                                        default_classes)

        # Overwrite assigned values according to existing keyword (if present).
        # Note the default_classes and unique_values are already loaded!

        value_map = self.parent.get_existing_keyword('value_map')
        value_map_classification_name = self.parent.get_existing_keyword(
            'classification')
        # Do not continue if there is no value_map in existing keywords
        if (value_map is None
                or value_map_classification_name != classification['key']):
            return

        # Do not continue if user selected different field
        field_keyword = self.parent.field_keyword_for_the_layer()
        field = self.parent.get_existing_keyword('inasafe_fields').get(
            field_keyword)
        if (not is_raster_layer(self.parent.layer)
                and field != self.parent.step_kw_field.selected_fields()):
            return

        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        if isinstance(value_map, str):
            try:
                value_map = json.loads(value_map)
            except ValueError:
                return

        for unique_value in clean_unique_values:
            # check in value map
            assigned = False
            for key, value_list in list(value_map.items()):
                if unique_value in value_list and key in assigned_values:
                    assigned_values[key] += [unique_value]
                    assigned = True
            if not assigned:
                unassigned_values += [unique_value]
        self.populate_classified_values(unassigned_values, assigned_values,
                                        default_classes)
Example #51
0
    def setup_value_mapping_panels(self, classification):
        """Setup value mapping panel in the right panel.

        :param classification: Classification definition.
        :type classification: dict
        """
        # Set text in the label
        layer_purpose = self.parent.step_kw_purpose.selected_purpose()
        layer_subcategory = self.parent.step_kw_subcategory. \
            selected_subcategory()

        if is_raster_layer(self.parent.layer):
            description_text = classify_raster_question % (
                layer_subcategory['name'],
                layer_purpose['name'],
                classification['name'])

            dataset = gdal.Open(self.parent.layer.source(), GA_ReadOnly)
            active_band = self.parent.step_kw_band_selector.selected_band()
            unique_values = numpy.unique(numpy.array(
                dataset.GetRasterBand(active_band).ReadAsArray()))
            field_type = 0
            # Convert datatype to a json serializable type
            if numpy.issubdtype(unique_values.dtype, float):
                unique_values = [float(i) for i in unique_values]
            else:
                unique_values = [int(i) for i in unique_values]
        else:
            field = self.parent.step_kw_field.selected_fields()
            field_index = self.parent.layer.dataProvider().fields(). \
                indexFromName(field)
            field_type = self.parent.layer.dataProvider(). \
                fields()[field_index].type()
            description_text = classify_vector_question % (
                layer_subcategory['name'],
                layer_purpose['name'],
                classification['name'],
                field.upper())
            unique_values = self.parent.layer.uniqueValues(field_index)

        # Set description
        description_label = QLabel(description_text)
        description_label.setWordWrap(True)
        self.right_layout.addWidget(description_label)

        self.list_unique_values = QListWidget()
        self.list_unique_values.setDragDropMode(QAbstractItemView.DragDrop)
        self.list_unique_values.setDefaultDropAction(Qt.MoveAction)

        self.tree_mapping_widget = QTreeWidget()
        self.tree_mapping_widget.setDragDropMode(QAbstractItemView.DragDrop)
        self.tree_mapping_widget.setDefaultDropAction(Qt.MoveAction)
        self.tree_mapping_widget.header().hide()

        self.tree_mapping_widget.itemChanged.connect(
            self.update_dragged_item_flags)

        value_mapping_layout = QHBoxLayout()
        value_mapping_layout.addWidget(self.list_unique_values)
        value_mapping_layout.addWidget(self.tree_mapping_widget)

        self.right_layout.addLayout(value_mapping_layout)

        default_classes = classification['classes']

        # Assign unique values to classes (according to default)
        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        for unique_value in unique_values:
            if unique_value is None or isinstance(
                    unique_value, QPyNullVariant):
                # Don't classify features with NULL value
                continue
            # Capitalization of the value and removing '_' (raw OSM data).
            value_as_string = unicode(unique_value).upper().replace('_', ' ')
            assigned = False
            for default_class in default_classes:
                if 'string_defaults' in default_class:
                    condition_1 = (
                        field_type > 9 and
                        value_as_string in [
                            c.upper() for c in
                            default_class['string_defaults']])
                else:
                    condition_1 = False
                condition_2 = (
                    field_type < 10 and
                    'numeric_default_min' in default_class and
                    'numeric_default_max' in default_class and (
                        default_class['numeric_default_min'] <= unique_value <
                        default_class['numeric_default_max']))
                if condition_1 or condition_2:
                    assigned_values[default_class['key']] += [unique_value]
                    assigned = True
            if not assigned:
                # add to unassigned values list otherwise
                unassigned_values += [unique_value]
        self.populate_classified_values(
            unassigned_values,
            assigned_values,
            default_classes,
            self.list_unique_values,
            self.tree_mapping_widget
        )

        # Current value map for exposure and classification
        available_classifications = self.value_maps.get(
            self.active_exposure['key'])
        if not available_classifications:
            return
        # Get active one
        current_classification = available_classifications.get(
            classification['key'])
        if not current_classification:
            return
        current_value_map = current_classification.get('classes')
        if not current_value_map:
            return

        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        for unique_value in unique_values:
            if unique_value is None or isinstance(
                    unique_value, QPyNullVariant):
                # Don't classify features with NULL value
                continue
            # check in value map
            assigned = False
            for key, value_list in current_value_map.items():
                if unique_value in value_list and key in assigned_values:
                    assigned_values[key] += [unique_value]
                    assigned = True
            if not assigned:
                unassigned_values += [unique_value]
        self.populate_classified_values(
            unassigned_values,
            assigned_values,
            default_classes,
            self.list_unique_values,
            self.tree_mapping_widget
        )
Example #52
0
def layer_description_html(layer, keywords=None):
    """Form a html description of a given layer based on the layer
       parameters and keywords if provided

    :param layer: The layer to get the description
    :type layer: QgsMapLayer

    :param keywords: The layer keywords
    :type keywords: None, dict

    :returns: The html description in tabular format,
        ready to use in a label or tool tip.
    :rtype: str
    """

    if keywords and 'keyword_version' in keywords:
        keyword_version = str(keywords['keyword_version'])
    else:
        keyword_version = None

    if (keywords and
            keyword_version and
            is_keyword_version_supported(keyword_version)):
        # The layer has valid keywords
        purpose = keywords.get('layer_purpose')
        if purpose == layer_purpose_hazard['key']:
            subcategory = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (
                tr('Hazard'), keywords.get(purpose))
            unit = keywords.get('continuous_hazard_unit')
        elif purpose == layer_purpose_exposure['key']:
            subcategory = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (
                tr('Exposure'), keywords.get(purpose))
            unit = keywords.get('exposure_unit')
        else:
            subcategory = ''
            unit = None
        if keywords.get('layer_mode') == layer_mode_classified['key']:
            unit = tr('classified data')
        if unit:
            unit = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (
                tr('Unit'), unit)

        desc = """
            <table border="0" width="100%%">
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            %s
            %s
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            </table>
        """ % (tr('Title'), keywords.get('title'),
               tr('Purpose'), keywords.get('layer_purpose'),
               subcategory,
               unit,
               tr('Source'), keywords.get('source'))
    elif keywords:
        # The layer has keywords, but the version is wrong
        layer_version = keyword_version or tr('No Version')
        desc = tr(
            'Your layer\'s keyword\'s version ({layer_version}) does not '
            'match with your InaSAFE version ({inasafe_version}). If you wish '
            'to use it as an exposure, hazard, or aggregation layer in an '
            'analysis, please update the keywords. Click Next if you want to '
            'assign keywords now.').format(
            layer_version=layer_version, inasafe_version=get_version())
    else:
        # The layer is keywordless
        if is_point_layer(layer):
            geom_type = 'point'
        elif is_polygon_layer(layer):
            geom_type = 'polygon'
        else:
            geom_type = 'line'

        # hide password in the layer source
        source = layer.publicSource()
        desc = """
            %s<br/><br/>
            <b>%s</b>: %s<br/>
            <b>%s</b>: %s<br/><br/>
            %s
        """ % (tr('This layer has no valid keywords assigned'),
               tr('SOURCE'), source,
               tr('TYPE'), is_raster_layer(layer) and 'raster' or
               'vector (%s)' % geom_type,
               tr('In the next step you will be able' +
                  ' to assign keywords to this layer.'))
    return desc
Example #53
0
    def is_layer_compatible(self, layer, layer_purpose=None, keywords=None):
        """Validate if a given layer is compatible for selected IF
           as a given layer_purpose

        :param layer: The layer to be validated
        :type layer: QgsVectorLayer | QgsRasterLayer

        :param layer_purpose: The layer_purpose the layer is validated for
        :type layer_purpose: None, string

        :param keywords: The layer keywords
        :type keywords: None, dict

        :returns: True if layer is appropriate for the selected role
        :rtype: boolean
        """

        # If not explicitly stated, find the desired purpose
        # from the parent step
        if not layer_purpose:
            layer_purpose = self.get_parent_mode_constraints()[0]['key']

        # If not explicitly stated, read the layer's keywords
        if not keywords:
            try:
                keywords = self.keyword_io.read_keywords(layer)
                if ('layer_purpose' not in keywords and
                        'impact_summary' not in keywords):
                    keywords = None
            except (HashNotFoundError,
                    OperationalError,
                    NoKeywordsFoundError,
                    KeywordNotFoundError,
                    InvalidParameterError,
                    UnsupportedProviderError):
                keywords = None

        # Get allowed subcategory and layer_geometry from IF constraints
        h, e, hc, ec = self.selected_impact_function_constraints()
        if layer_purpose == 'hazard':
            subcategory = h['key']
            layer_geometry = hc['key']
        elif layer_purpose == 'exposure':
            subcategory = e['key']
            layer_geometry = ec['key']
        else:
            # For aggregation layers, use a simplified test and return
            if (keywords and 'layer_purpose' in keywords and
                    keywords['layer_purpose'] == layer_purpose):
                return True
            if not keywords and is_polygon_layer(layer):
                return True
            return False

        # Compare layer properties with explicitly set constraints
        # Reject if layer geometry doesn't match
        if layer_geometry != self.get_layer_geometry_id(layer):
            return False

        # If no keywords, there's nothing more we can check.
        # The same if the keywords version doesn't match
        if not keywords or 'keyword_version' not in keywords:
            return True
        keyword_version = str(keywords['keyword_version'])
        if not is_keyword_version_supported(keyword_version):
            return True

        # Compare layer keywords with explicitly set constraints
        # Reject if layer purpose missing or doesn't match
        if ('layer_purpose' not in keywords or
                keywords['layer_purpose'] != layer_purpose):
            return False

        # Reject if layer subcategory doesn't match
        if (layer_purpose in keywords and
                keywords[layer_purpose] != subcategory):
            return False

        # Compare layer keywords with the chosen function's constraints

        imfunc = self.step_fc_function.selected_function()
        lay_req = imfunc['layer_requirements'][layer_purpose]

        # Reject if layer mode doesn't match
        if ('layer_mode' in keywords and
                lay_req['layer_mode']['key'] != keywords['layer_mode']):
            return False

        # Reject if classification doesn't match
        classification_key = '%s_%s_classification' % (
            'raster' if is_raster_layer(layer) else 'vector',
            layer_purpose)
        classification_keys = classification_key + 's'
        if (lay_req['layer_mode'] == layer_mode_classified and
                classification_key in keywords and
                classification_keys in lay_req):
            allowed_classifications = [
                c['key'] for c in lay_req[classification_keys]]
            if keywords[classification_key] not in allowed_classifications:
                return False

        # Reject if unit doesn't match
        unit_key = ('continuous_hazard_unit'
                    if layer_purpose == layer_purpose_hazard['key']
                    else 'exposure_unit')
        unit_keys = unit_key + 's'
        if (lay_req['layer_mode'] == layer_mode_continuous and
                unit_key in keywords and
                unit_keys in lay_req):
            allowed_units = [
                c['key'] for c in lay_req[unit_keys]]
            if keywords[unit_key] not in allowed_units:
                return False

        # Finally return True
        return True
Example #54
0
    def set_widgets(self):
        """Set widgets on the Threshold tab."""
        clear_layout(self.gridLayoutThreshold)

        # Set text in the label
        layer_purpose = self.parent.step_kw_purpose.selected_purpose()
        layer_subcategory = self.parent.step_kw_subcategory.\
            selected_subcategory()
        classification = self.parent.step_kw_classification. \
            selected_classification()

        if is_raster_layer(self.parent.layer):
            statistics = self.parent.layer.dataProvider().bandStatistics(
                1, QgsRasterBandStats.All, self.parent.layer.extent(), 0)
            text = continuous_raster_question % (
                layer_purpose['name'],
                layer_subcategory['name'],
                classification['name'],
                statistics.minimumValue,
                statistics.maximumValue)
        else:
            field_name = self.parent.step_kw_field.selected_fields()
            field_index = self.parent.layer.fields().lookupField(field_name)
            min_value_layer = self.parent.layer.minimumValue(field_index)
            max_value_layer = self.parent.layer.maximumValue(field_index)
            text = continuous_vector_question % (
                layer_purpose['name'],
                layer_subcategory['name'],
                field_name,
                classification['name'],
                min_value_layer,
                max_value_layer)
        self.lblThreshold.setText(text)

        thresholds = self.parent.get_existing_keyword('thresholds')
        selected_unit = self.parent.step_kw_unit.selected_unit()['key']

        self.classes = OrderedDict()
        classes = classification.get('classes')
        # Sort by value, put the lowest first
        classes = sorted(classes, key=lambda k: k['value'])

        for i, the_class in enumerate(classes):
            class_layout = QHBoxLayout()

            # Class label
            class_label = QLabel(the_class['name'])

            # Min label
            min_label = QLabel(tr('Min >'))

            # Min value as double spin
            min_value_input = QDoubleSpinBox()
            # TODO(IS) We can set the min and max depends on the unit, later
            min_value_input.setMinimum(0)
            min_value_input.setMaximum(999999)
            if thresholds.get(the_class['key']):
                min_value_input.setValue(thresholds[the_class['key']][0])
            else:
                default_min = the_class['numeric_default_min']
                if isinstance(default_min, dict):
                    default_min = the_class[
                        'numeric_default_min'][selected_unit]
                min_value_input.setValue(default_min)
            min_value_input.setSingleStep(0.1)

            # Max label
            max_label = QLabel(tr('Max <='))

            # Max value as double spin
            max_value_input = QDoubleSpinBox()
            # TODO(IS) We can set the min and max depends on the unit, later
            max_value_input.setMinimum(0)
            max_value_input.setMaximum(999999)
            if thresholds.get(the_class['key']):
                max_value_input.setValue(thresholds[the_class['key']][1])
            else:
                default_max = the_class['numeric_default_max']
                if isinstance(default_max, dict):
                    default_max = the_class[
                        'numeric_default_max'][selected_unit]
                max_value_input.setValue(default_max)
            max_value_input.setSingleStep(0.1)

            # Add to class_layout
            class_layout.addWidget(min_label)
            class_layout.addWidget(min_value_input)
            # class_layout.addStretch(1)
            class_layout.addWidget(max_label)
            class_layout.addWidget(max_value_input)

            # Add to grid_layout
            self.gridLayoutThreshold.addWidget(class_label, i, 0)
            self.gridLayoutThreshold.addLayout(class_layout, i, 1)

            self.classes[the_class['key']] = [min_value_input, max_value_input]

        self.gridLayoutThreshold.setSpacing(0)

        def min_max_changed(index, the_string):
            """Slot when min or max value change.

            :param index: The index of the double spin.
            :type index: int

            :param the_string: The flag to indicate the min or max value.
            :type the_string: str
            """
            if the_string == 'Max value':
                current_max_value = list(self.classes.values())[index][1]
                target_min_value = list(self.classes.values())[index + 1][0]
                if current_max_value.value() != target_min_value.value():
                    target_min_value.setValue(current_max_value.value())
            elif the_string == 'Min value':
                current_min_value = list(self.classes.values())[index][0]
                target_max_value = list(self.classes.values())[index - 1][1]
                if current_min_value.value() != target_max_value.value():
                    target_max_value.setValue(current_min_value.value())

        # Set behaviour
        for k, v in list(self.classes.items()):
            index = list(self.classes.keys()).index(k)
            if index < len(self.classes) - 1:
                # Max value changed
                v[1].valueChanged.connect(partial(
                    min_max_changed, index=index, the_string='Max value'))
            if index > 0:
                # Min value
                v[0].valueChanged.connect(partial(
                    min_max_changed, index=index, the_string='Min value'))
Example #55
0
def calculate_zonal_stats(raster_layer, polygon_layer):
    """Calculate zonal statics given two layers.

    :param raster_layer: A QGIS raster layer.
    :type raster_layer: QgsRasterLayer, QgsMapLayer

    :param polygon_layer: A QGIS vector layer containing polygons.
    :type polygon_layer: QgsVectorLayer, QgsMapLayer

    :returns: A data structure containing sum, mean, min, max,
        count of raster values for each polygonal area.
    :rtype: dict

    :raises: InvalidParameterError, InvalidGeometryError

    Note:
        * InvalidParameterError if incorrect inputs are received.
        * InvalidGeometryError if none geometry is found during calculations.
        * Any other exceptions are propagated.

    Example of output data structure:

        { 1: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2},
          2: {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2},
          3 {'sum': 10, 'count': 20, 'min': 1, 'max': 4, 'mean': 2}}

    The key in the outer dict is the feature id

    .. note:: This is a python port of the zonal stats implementation in QGIS
        . See https://github.com/qgis/Quantum-GIS/blob/master/src/analysis/
        vector/qgszonalstatistics.cpp

    .. note:: Currently not projection checks are made to ensure that both
        layers are in the same CRS - we assume they are.

    """
    if not is_polygon_layer(polygon_layer):
        raise InvalidParameterError(tr(
            'Zonal stats needs a polygon layer in order to compute '
            'statistics.'))
    if not is_raster_layer(raster_layer):
        raise InvalidParameterError(tr(
            'Zonal stats needs a raster layer in order to compute statistics.'
        ))
    LOGGER.debug('Calculating zonal stats for:')
    LOGGER.debug('Raster: %s' % raster_layer.source())
    LOGGER.debug('Vector: %s' % polygon_layer.source())
    results = {}
    raster_source = raster_layer.source()
    feature_id = gdal.Open(str(raster_source), gdal.GA_ReadOnly)
    geo_transform = feature_id.GetGeoTransform()
    columns = feature_id.RasterXSize
    rows = feature_id.RasterYSize
    # Get first band.
    band = feature_id.GetRasterBand(1)
    no_data = band.GetNoDataValue()
    # print 'No data %s' % no_data
    cell_size_x = geo_transform[1]
    if cell_size_x < 0:
        cell_size_x = -cell_size_x
    cell_size_y = geo_transform[5]
    if cell_size_y < 0:
        cell_size_y = -cell_size_y
    raster_box = QgsRectangle(
        geo_transform[0],
        geo_transform[3] - (cell_size_y * rows),
        geo_transform[0] + (cell_size_x * columns),
        geo_transform[3])

    # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
    raster_geometry = QgsGeometry.fromRect(raster_box)

    # Get vector layer
    provider = polygon_layer.dataProvider()
    if provider is None:
        message = tr(
            'Could not obtain data provider from layer "%s"') % (
                polygon_layer.source())
        raise Exception(message)

    request = QgsFeatureRequest()
    crs = osr.SpatialReference()
    crs.ImportFromProj4(str(polygon_layer.crs().toProj4()))

    count = 0
    for myFeature in provider.getFeatures(request):
        geometry = myFeature.geometry()
        if geometry is None:
            message = tr(
                'Feature %d has no geometry or geometry is invalid') % (
                    myFeature.id())
            raise InvalidGeometryError(message)

        count += 1
        feature_box = geometry.boundingBox().intersect(raster_box)
        print 'NEW AGGR: %s' % myFeature.id()

        # print 'Raster Box: %s' % raster_box.asWktCoordinates()
        # print 'Feature Box: %s' % feature_box.asWktCoordinates()

        offset_x, offset_y, cells_x, cells_y = intersection_box(
            raster_box, feature_box, cell_size_x, cell_size_y)

        # If the poly does not intersect the raster just continue
        if None in [offset_x, offset_y, cells_x, cells_y]:
            continue

        # avoid access to cells outside of the raster (may occur because of
        # rounding)
        if (offset_x + cells_x) > columns:
            offset_x = columns - offset_x

        if (offset_y + cells_y) > rows:
            cells_y = rows - offset_y

        intersected_geometry = raster_geometry.intersection(geometry)
        geometry_sum, count = numpy_stats(
            band,
            intersected_geometry,
            geo_transform,
            no_data,
            crs)

        if count <= 1:
            # The cell resolution is probably larger than the polygon area.
            # We switch to precise pixel - polygon intersection in this case
            geometry_sum, count = precise_stats(
                band,
                geometry,
                offset_x,
                offset_y,
                cells_x,
                cells_y,
                cell_size_x,
                cell_size_y,
                raster_box,
                no_data)
            # print geometry_sum, count

        if count == 0:
            mean = 0
        else:
            mean = geometry_sum / count

        results[myFeature.id()] = {
            'sum': geometry_sum,
            'count': count,
            'mean': mean}

    # noinspection PyUnusedLocal
    feature_id = None  # Close
    return results
Example #56
0
    def set_widgets(self):
        """Set widgets on the Classify tab."""
        purpose = self.parent.step_kw_purpose.selected_purpose()
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()
        # There may be two cases this tab is displayed: either
        # a classification or postprocessor_classification is available

        sel_cl = self.parent.step_kw_classification.selected_classification()
        if sel_cl:
            default_classes = sel_cl['classes']
            mapping_keyword = 'value_map'
            classification_name = sel_cl['name']
        else:
            default_classes = self.postprocessor_classification_for_layer()
            mapping_keyword = 'value_mapping'
            classification_name = ''
        if is_raster_layer(self.parent.layer):
            self.lblClassify.setText(
                classify_raster_question %
                (subcategory['name'], purpose['name'], classification_name))
            ds = gdal.Open(self.parent.layer.source(), GA_ReadOnly)
            unique_values = numpy.unique(
                numpy.array(ds.GetRasterBand(1).ReadAsArray()))
            field_type = 0
            # Convert datatype to a json serializable type
            if numpy.issubdtype(unique_values.dtype, float):
                unique_values = [float(i) for i in unique_values]
            else:
                unique_values = [int(i) for i in unique_values]
        else:
            field = self.parent.step_kw_field.selected_field()
            field_index = self.parent.layer.dataProvider().fields().\
                indexFromName(field)
            field_type = self.parent.layer.dataProvider().\
                fields()[field_index].type()
            if classification_name:
                self.lblClassify.setText(classify_vector_question %
                                         (subcategory['name'], purpose['name'],
                                          classification_name, field.upper()))
            else:
                self.lblClassify.setText(
                    classify_vector_for_postprocessor_question %
                    (subcategory['name'], purpose['name'], field.upper()))
            unique_values = self.parent.layer.uniqueValues(field_index)

        # Assign unique values to classes (according to default)
        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        for unique_value in unique_values:
            if unique_value is None or isinstance(unique_value,
                                                  QPyNullVariant):
                # Don't classify features with NULL value
                continue
            # Capitalization of the value and removing '_' (raw OSM data).
            value_as_string = unicode(unique_value).upper().replace('_', ' ')
            assigned = False
            for default_class in default_classes:
                condition_1 = (field_type > 9 and value_as_string in [
                    c.upper() for c in default_class['string_defaults']
                ])
                condition_2 = (
                    field_type < 10 and 'numeric_default_min' in default_class
                    and 'numeric_default_max' in default_class
                    and (default_class['numeric_default_min'] <= unique_value
                         <= default_class['numeric_default_max']))
                if condition_1 or condition_2:
                    assigned_values[default_class['key']] += [unique_value]
                    assigned = True
            if not assigned:
                # add to unassigned values list otherwise
                unassigned_values += [unique_value]
        self.populate_classified_values(unassigned_values, assigned_values,
                                        default_classes)

        # Overwrite assigned values according to existing keyword (if present).
        # Note the default_classes and unique_values are already loaded!

        value_map = self.parent.get_existing_keyword(mapping_keyword)
        # Do not continue if there is no value_map in existing keywords
        if value_map is None:
            return

        # Do not continue if user selected different field
        field_keyword = self.parent.field_keyword_for_the_layer()
        field = self.parent.get_existing_keyword(field_keyword)
        if (not is_raster_layer(self.parent.layer)
                and field != self.parent.step_kw_field.selected_field()):
            return

        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        if isinstance(value_map, str):
            try:
                value_map = json.loads(value_map)
            except ValueError:
                return
        for unique_value in unique_values:
            if unique_value is None or isinstance(unique_value,
                                                  QPyNullVariant):
                # Don't classify features with NULL value
                continue
            # check in value map
            assigned = False
            for key, value_list in value_map.iteritems():
                if unique_value in value_list and key in assigned_values:
                    assigned_values[key] += [unique_value]
                    assigned = True
            if not assigned:
                unassigned_values += [unique_value]
        self.populate_classified_values(unassigned_values, assigned_values,
                                        default_classes)
Example #57
0
    def set_widgets(self):
        """Set widgets on the Classify tab."""
        purpose = self.parent.step_kw_purpose.selected_purpose()
        subcategory = self.parent.step_kw_subcategory.selected_subcategory()
        # There may be two cases this tab is displayed: either
        # a classification or postprocessor_classification is available

        sel_cl = self.parent.step_kw_classification.selected_classification()
        if sel_cl:
            default_classes = sel_cl['classes']
            mapping_keyword = 'value_map'
            classification_name = sel_cl['name']
        else:
            default_classes = self.postprocessor_classification_for_layer()
            mapping_keyword = 'value_mapping'
            classification_name = ''
        if is_raster_layer(self.parent.layer):
            self.lblClassify.setText(classify_raster_question % (
                subcategory['name'], purpose['name'], classification_name))
            ds = gdal.Open(self.parent.layer.source(), GA_ReadOnly)
            unique_values = numpy.unique(numpy.array(
                ds.GetRasterBand(1).ReadAsArray()))
            field_type = 0
            # Convert datatype to a json serializable type
            if numpy.issubdtype(unique_values.dtype, float):
                unique_values = [float(i) for i in unique_values]
            else:
                unique_values = [int(i) for i in unique_values]
        else:
            field = self.parent.step_kw_field.selected_field()
            field_index = self.parent.layer.dataProvider().fields().\
                indexFromName(field)
            field_type = self.parent.layer.dataProvider().\
                fields()[field_index].type()
            if classification_name:
                self.lblClassify.setText(classify_vector_question % (
                    subcategory['name'], purpose['name'],
                    classification_name, field.upper()))
            else:
                self.lblClassify.setText(
                    classify_vector_for_postprocessor_question % (
                        subcategory['name'], purpose['name'], field.upper()))
            unique_values = self.parent.layer.uniqueValues(field_index)

        # Assign unique values to classes (according to default)
        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        for unique_value in unique_values:
            if unique_value is None or isinstance(
                    unique_value, QPyNullVariant):
                # Don't classify features with NULL value
                continue
            # Capitalization of the value and removing '_' (raw OSM data).
            value_as_string = unicode(unique_value).upper().replace('_', ' ')
            assigned = False
            for default_class in default_classes:
                condition_1 = (
                    field_type > 9 and
                    value_as_string in [
                        c.upper() for c in default_class['string_defaults']])
                condition_2 = (
                    field_type < 10 and
                    'numeric_default_min' in default_class and
                    'numeric_default_max' in default_class and (
                        default_class['numeric_default_min'] <= unique_value <=
                        default_class['numeric_default_max']))
                if condition_1 or condition_2:
                    assigned_values[default_class['key']] += [unique_value]
                    assigned = True
            if not assigned:
                # add to unassigned values list otherwise
                unassigned_values += [unique_value]
        self.populate_classified_values(
            unassigned_values, assigned_values, default_classes)

        # Overwrite assigned values according to existing keyword (if present).
        # Note the default_classes and unique_values are already loaded!

        value_map = self.parent.get_existing_keyword(mapping_keyword)
        # Do not continue if there is no value_map in existing keywords
        if value_map is None:
            return

        # Do not continue if user selected different field
        field_keyword = self.parent.field_keyword_for_the_layer()
        field = self.parent.get_existing_keyword(field_keyword)
        if (not is_raster_layer(self.parent.layer) and
                field != self.parent.step_kw_field.selected_field()):
            return

        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        if isinstance(value_map, str):
            try:
                value_map = json.loads(value_map)
            except ValueError:
                return
        for unique_value in unique_values:
            if unique_value is None or isinstance(
                    unique_value, QPyNullVariant):
                # Don't classify features with NULL value
                continue
            # check in value map
            assigned = False
            for key, value_list in value_map.iteritems():
                if unique_value in value_list and key in assigned_values:
                    assigned_values[key] += [unique_value]
                    assigned = True
            if not assigned:
                unassigned_values += [unique_value]
        self.populate_classified_values(
            unassigned_values, assigned_values, default_classes)
Example #58
0
    def setup_thresholds_panel(self, classification):
        """Setup threshold panel in the right panel.

        :param classification: Classification definition.
        :type classification: dict
        """
        # Set text in the label
        layer_purpose = self.parent.step_kw_purpose.selected_purpose()
        layer_subcategory = self.parent.step_kw_subcategory.\
            selected_subcategory()

        if is_raster_layer(self.parent.layer):
            statistics = self.parent.layer.dataProvider().bandStatistics(
                1, QgsRasterBandStats.All, self.parent.layer.extent(), 0)
            description_text = continuous_raster_question % (
                layer_purpose['name'],
                layer_subcategory['name'],
                classification['name'],
                statistics.minimumValue,
                statistics.maximumValue)
        else:
            field_name = self.parent.step_kw_field.selected_fields()
            field_index = self.parent.layer.fieldNameIndex(field_name)
            min_value_layer = self.parent.layer.minimumValue(field_index)
            max_value_layer = self.parent.layer.maximumValue(field_index)
            description_text = continuous_vector_question % (
                layer_purpose['name'],
                layer_subcategory['name'],
                field_name,
                classification['name'],
                min_value_layer,
                max_value_layer)

        # Set description
        description_label = QLabel(description_text)
        description_label.setWordWrap(True)
        self.right_layout.addWidget(description_label)

        if self.thresholds:
            thresholds = self.thresholds
        else:
            thresholds = self.parent.get_existing_keyword('thresholds')
        selected_unit = self.parent.step_kw_unit.selected_unit()['key']

        self.threshold_classes = OrderedDict()
        classes = classification.get('classes')
        # Sort by value, put the lowest first
        classes = sorted(classes, key=lambda the_key: the_key['value'])

        grid_layout_thresholds = QGridLayout()

        for i, the_class in enumerate(classes):
            class_layout = QHBoxLayout()

            # Class label
            class_label = QLabel(the_class['name'])

            # Min label
            min_label = QLabel(tr('Min >'))

            # Min value as double spin
            min_value_input = QDoubleSpinBox()
            # TODO(IS) We can set the min and max depends on the unit, later
            min_value_input.setMinimum(0)
            min_value_input.setMaximum(999999)

            if thresholds.get(self.active_exposure['key']):
                exposure_thresholds = thresholds.get(
                    self.active_exposure['key'])
                if exposure_thresholds.get(classification['key']):
                    exposure_thresholds_classifications = exposure_thresholds\
                        .get(classification['key'])
                    min_value_input.setValue(
                        exposure_thresholds_classifications['classes'][
                            the_class['key']][0])
                else:
                    default_min = the_class['numeric_default_min']
                    if isinstance(default_min, dict):
                        default_min = the_class[
                            'numeric_default_min'][selected_unit]
                    min_value_input.setValue(default_min)
            else:
                default_min = the_class['numeric_default_min']
                if isinstance(default_min, dict):
                    default_min = the_class[
                        'numeric_default_min'][selected_unit]
                min_value_input.setValue(default_min)
            min_value_input.setSingleStep(0.1)

            # Max label
            max_label = QLabel(tr('Max <='))

            # Max value as double spin
            max_value_input = QDoubleSpinBox()
            # TODO(IS) We can set the min and max depends on the unit, later
            max_value_input.setMinimum(0)
            max_value_input.setMaximum(999999)
            if thresholds.get(self.active_exposure['key']):
                exposure_thresholds = thresholds.get(
                    self.active_exposure['key'])
                if exposure_thresholds.get(classification['key']):
                    exposure_thresholds_classifications = exposure_thresholds \
                        .get(classification['key'])
                    max_value_input.setValue(
                        exposure_thresholds_classifications['classes'][
                            the_class['key']][1])
                else:
                    default_max = the_class['numeric_default_max']
                    if isinstance(default_max, dict):
                        default_max = the_class[
                            'numeric_default_max'][selected_unit]
                    max_value_input.setValue(default_max)
            else:
                default_max = the_class['numeric_default_max']
                if isinstance(default_max, dict):
                    default_max = the_class[
                        'numeric_default_max'][selected_unit]
                max_value_input.setValue(default_max)
            max_value_input.setSingleStep(0.1)

            # Add to class_layout
            class_layout.addWidget(min_label)
            class_layout.addWidget(min_value_input)
            class_layout.addWidget(max_label)
            class_layout.addWidget(max_value_input)

            class_layout.setStretch(0, 1)
            class_layout.setStretch(1, 2)
            class_layout.setStretch(2, 1)
            class_layout.setStretch(3, 2)

            # Add to grid_layout
            grid_layout_thresholds.addWidget(class_label, i, 0)
            grid_layout_thresholds.addLayout(class_layout, i, 1)

            self.threshold_classes[the_class['key']] = [
                min_value_input, max_value_input]

        grid_layout_thresholds.setColumnStretch(0, 1)
        grid_layout_thresholds.setColumnStretch(0, 2)

        def min_max_changed(double_spin_index, mode):
            """Slot when min or max value change.

            :param double_spin_index: The index of the double spin.
            :type double_spin_index: int

            :param mode: The flag to indicate the min or max value.
            :type mode: int
            """
            if mode == MAX_VALUE_MODE:
                current_max_value = self.threshold_classes.values()[
                    double_spin_index][1]
                target_min_value = self.threshold_classes.values()[
                    double_spin_index + 1][0]
                if current_max_value.value() != target_min_value.value():
                    target_min_value.setValue(current_max_value.value())
            elif mode == MIN_VALUE_MODE:
                current_min_value = self.threshold_classes.values()[
                    double_spin_index][0]
                target_max_value = self.threshold_classes.values()[
                    double_spin_index - 1][1]
                if current_min_value.value() != target_max_value.value():
                    target_max_value.setValue(current_min_value.value())

        # Set behaviour
        for k, v in self.threshold_classes.items():
            index = self.threshold_classes.keys().index(k)
            if index < len(self.threshold_classes) - 1:
                # Max value changed
                v[1].valueChanged.connect(partial(
                    min_max_changed,
                    double_spin_index=index,
                    mode=MAX_VALUE_MODE))
            if index > 0:
                # Min value
                v[0].valueChanged.connect(partial(
                    min_max_changed,
                    double_spin_index=index,
                    mode=MIN_VALUE_MODE))

        grid_layout_thresholds.setSpacing(0)

        self.right_layout.addLayout(grid_layout_thresholds)