Esempio n. 1
0
def calculate_svi(
    iface, current_layer, project_definition, indicators_operator=None, themes_operator=None, reuse_field=False
):
    """
    add an SVI attribute to the current layer
    """
    # set default
    if indicators_operator is None:
        indicators_operator = DEFAULT_COMBINATION
    if themes_operator is None:
        themes_operator = DEFAULT_COMBINATION

    themes = project_definition["children"][1]["children"]

    if reuse_field and "svi_field" in project_definition:
        svi_attr_name = project_definition["svi_field"]
        if DEBUG:
            print "Reusing %s" % svi_attr_name
    else:
        svi_attr_name = "SVI"
        svi_field = QgsField(svi_attr_name, QVariant.Double)
        svi_field.setTypeName(DOUBLE_FIELD_TYPE_NAME)
        attr_names = ProcessLayer(current_layer).add_attributes([svi_field])
        svi_attr_name = attr_names[svi_attr_name]

    # get the id of the new attribute
    svi_attr_id = ProcessLayer(current_layer).find_attribute_id(svi_attr_name)

    discarded_feats_ids = []
    try:
        with LayerEditingManager(current_layer, "Add SVI", DEBUG):
            for feat in current_layer.getFeatures():
                # If a feature contains any NULL value, discard_feat will
                # be set to True and the corresponding SVI will be set to
                # NULL
                discard_feat = False
                feat_id = feat.id()

                # init svi_value to the correct value depending on
                # themes_operator
                if themes_operator in SUM_BASED_COMBINATIONS:
                    svi_value = 0
                elif themes_operator in MUL_BASED_COMBINATIONS:
                    svi_value = 1

                # iterate all themes of SVI
                for theme in themes:
                    indicators = theme["children"]

                    # init theme_result to the correct value depending on
                    # indicators_operator
                    if indicators_operator in SUM_BASED_COMBINATIONS:
                        theme_result = 0
                    elif indicators_operator in MUL_BASED_COMBINATIONS:
                        theme_result = 1

                    # iterate all indicators of a theme
                    for indicator in indicators:
                        if feat[indicator["field"]] == QPyNullVariant(float):
                            discard_feat = True
                            discarded_feats_ids.append(feat_id)
                            break
                        # For "Average (equal weights)" it's equivalent to use
                        # equal weights, or to sum the indicators
                        # (all weights 1)
                        # and divide by the number of indicators (we use
                        # the latter solution)
                        if indicators_operator in (
                            "Sum (simple)",
                            "Average (equal weights)",
                            "Multiplication (simple)",
                        ):
                            indicator_weighted = feat[indicator["field"]]
                        else:
                            indicator_weighted = feat[indicator["field"]] * indicator["weight"]

                        if indicators_operator in SUM_BASED_COMBINATIONS:
                            theme_result += indicator_weighted
                        elif indicators_operator in MUL_BASED_COMBINATIONS:
                            theme_result *= indicator_weighted
                        else:
                            error_message = "invalid indicators_operator: %s" % indicators_operator
                            raise RuntimeError(error_message)
                    if discard_feat:
                        break
                    if indicators_operator == "Average (equal weights)":
                        theme_result /= len(indicators)

                    # combine the indicators of each theme
                    # For "Average (equal weights)" it's equivalent to use
                    # equal weights, or to sum the themes (all weights 1)
                    # and divide by the number of themes (we use
                    # the latter solution)
                    if themes_operator in ("Sum (simple)", "Average (equal weights)", "Multiplication (simple)"):
                        theme_weighted = theme_result
                    else:
                        theme_weighted = theme_result * theme["weight"]

                    if themes_operator in SUM_BASED_COMBINATIONS:
                        svi_value += theme_weighted
                    elif themes_operator in MUL_BASED_COMBINATIONS:
                        svi_value *= theme_weighted
                if discard_feat:
                    svi_value = QPyNullVariant(float)
                else:
                    if themes_operator == "Average (equal weights)":
                        svi_value /= len(themes)

                current_layer.changeAttributeValue(feat_id, svi_attr_id, svi_value)
        msg = (
            "The SVI has been calculated for fields containing "
            "non-NULL values and it was added to the layer as "
            "a new attribute called %s"
        ) % svi_attr_name
        iface.messageBar().pushMessage(tr("Info"), tr(msg), level=QgsMessageBar.INFO)
        if discarded_feats_ids:
            widget = toggle_select_features_widget(
                tr("Warning"),
                tr("Invalid indicators were found in some features while " "calculating SVI"),
                tr("Select invalid features"),
                current_layer,
                discarded_feats_ids,
                current_layer.selectedFeaturesIds(),
            )
            iface.messageBar().pushWidget(widget, QgsMessageBar.WARNING)

        project_definition["indicators_operator"] = indicators_operator
        project_definition["themes_operator"] = themes_operator
        project_definition["svi_field"] = svi_attr_name
        return svi_attr_id, discarded_feats_ids

    except TypeError as e:
        current_layer.dataProvider().deleteAttributes([svi_attr_id])
        msg = "Could not calculate SVI due to data problems: %s" % e
        iface.messageBar().pushMessage(tr("Error"), tr(msg), level=QgsMessageBar.CRITICAL)
Esempio n. 2
0
def calculate_iri(
    iface, current_layer, project_definition, svi_attr_id, aal_field_name, discarded_feats_ids, iri_operator=None
):
    """
    Copy the AAL and calculate an IRI attribute to the current layer
    """

    # set default
    if iri_operator is None:
        iri_operator = DEFAULT_COMBINATION

    aal_weight = project_definition["children"][0]["weight"]
    svi_weight = project_definition["children"][1]["weight"]

    iri_attr_name = "IRI"
    iri_field = QgsField(iri_attr_name, QVariant.Double)
    iri_field.setTypeName(DOUBLE_FIELD_TYPE_NAME)

    attr_names = ProcessLayer(current_layer).add_attributes([iri_field])

    # get the id of the new attributes
    iri_attr_id = ProcessLayer(current_layer).find_attribute_id(attr_names[iri_attr_name])

    discarded_aal_feats_ids = []

    try:
        with LayerEditingManager(current_layer, "Add IRI", DEBUG):
            for feat in current_layer.getFeatures():
                feat_id = feat.id()
                svi_value = feat.attributes()[svi_attr_id]
                aal_value = feat[aal_field_name]
                if aal_value == QPyNullVariant(float) or feat_id in discarded_feats_ids:
                    iri_value = QPyNullVariant(float)
                    discarded_aal_feats_ids.append(feat_id)
                elif iri_operator == "Sum (simple)":
                    iri_value = svi_value + aal_value
                elif iri_operator == "Multiplication (simple)":
                    iri_value = svi_value * aal_value
                elif iri_operator == "Sum (weighted)":
                    iri_value = svi_value * svi_weight + aal_value * aal_weight
                elif iri_operator == "Multiplication (weighted)":
                    iri_value = svi_value * svi_weight * aal_value * aal_weight
                elif iri_operator == "Average (equal weights)":
                    # For "Average (equal weights)" it's equivalent to use
                    # equal weights, or to sum the indices (all weights 1)
                    # and divide by the number of indices (we use
                    # the latter solution)
                    iri_value = (svi_value + aal_value) / 2.0
                # store IRI
                current_layer.changeAttributeValue(feat_id, iri_attr_id, iri_value)
        project_definition["iri_operator"] = iri_operator
        # set the field name for the copied AAL layer
        project_definition["aal_field"] = aal_field_name
        project_definition["iri_field"] = attr_names[iri_attr_name]
        msg = (
            "The IRI has been calculated for fields containing "
            "non-NULL values and it was added to the layer as "
            "a new attribute called %s"
        ) % attr_names[iri_attr_name]
        iface.messageBar().pushMessage(tr("Info"), tr(msg), level=QgsMessageBar.INFO)
        widget = toggle_select_features_widget(
            tr("Warning"),
            tr("Invalid values were found in some features while calculating " "IRI"),
            tr("Select invalid features"),
            current_layer,
            discarded_aal_feats_ids,
            current_layer.selectedFeaturesIds(),
        )
        iface.messageBar().pushWidget(widget, QgsMessageBar.WARNING)
        return iri_attr_id

    except TypeError as e:
        current_layer.dataProvider().deleteAttributes([iri_attr_id])
        msg = "Could not calculate IRI due to data problems: %s" % e

        iface.messageBar().pushMessage(tr("Error"), tr(msg), level=QgsMessageBar.CRITICAL)