def _get_tvalue(self, id, epoch, symbol, get_first):
     req = QgsFeatureRequest()
     exp = self._time_query_string(epoch, self.timeColumn, symbol)
     exp += self._id_query_string(id)
     req.setFilterExpression(exp)
     warn(exp)
     s = self.timeLayer.subsetString()
     self.timeLayer.setSubsetString("")
     featIt = self.timeLayer.layer.dataProvider().getFeatures(req)
     self.timeLayer.setSubsetString(s)
     feats = list(featIt)
     if get_first:
         subList = feats[:min(20, len(feats))]
     else:
         subList = feats[-min(20, len(feats)):]
     feats = sorted(subList,
                    key=lambda feat: self.getStartEpochFromFeature(feat, self.timeLayer))
     if not feats:
         return None
     if get_first:
         feat = feats[0]
     else:
         feat = feats[-1]
     curr_epoch = self.getStartEpochFromFeature(feat, self.timeLayer)
     return curr_epoch
Example #2
0
    def processAlgorithm(self, parameters, context, feedback):
        if parameters[self.SPOKES] == parameters[self.HUBS]:
            raise QgsProcessingException(
                self.tr('Same layer given for both hubs and spokes'))

        hub_source = self.parameterAsSource(parameters, self.HUBS, context)
        spoke_source = self.parameterAsSource(parameters, self.SPOKES, context)
        field_hub = self.parameterAsString(parameters, self.HUB_FIELD, context)
        field_hub_index = hub_source.fields().lookupField(field_hub)
        field_spoke = self.parameterAsString(parameters, self.SPOKE_FIELD, context)
        field_spoke_index = hub_source.fields().lookupField(field_spoke)

        fields = vector.combineFields(hub_source.fields(), spoke_source.fields())

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.LineString, hub_source.sourceCrs())

        hubs = hub_source.getFeatures()
        total = 100.0 / hub_source.featureCount() if hub_source.featureCount() else 0

        matching_field_types = hub_source.fields().at(field_hub_index).type() == spoke_source.fields().at(field_spoke_index).type()

        for current, hub_point in enumerate(hubs):
            if feedback.isCanceled():
                break

            if not hub_point.hasGeometry():
                continue

            p = hub_point.geometry().boundingBox().center()
            hub_x = p.x()
            hub_y = p.y()
            hub_id = str(hub_point[field_hub])
            hub_attributes = hub_point.attributes()

            request = QgsFeatureRequest().setDestinationCrs(hub_source.sourceCrs())
            if matching_field_types:
                request.setFilterExpression(QgsExpression.createFieldEqualityExpression(field_spoke, hub_attributes[field_hub_index]))

            spokes = spoke_source.getFeatures()
            for spoke_point in spokes:
                if feedback.isCanceled():
                    break

                spoke_id = str(spoke_point[field_spoke])
                if hub_id == spoke_id:
                    p = spoke_point.geometry().boundingBox().center()
                    spoke_x = p.x()
                    spoke_y = p.y()

                    f = QgsFeature()
                    f.setAttributes(hub_attributes + spoke_point.attributes())
                    f.setGeometry(QgsGeometry.fromPolyline(
                        [QgsPointXY(hub_x, hub_y), QgsPointXY(spoke_x, spoke_y)]))
                    sink.addFeature(f, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
def intersecting_blocks(line, destination, grid):
    """Function to fetch intersectings polygons from the grid."""
    dest_id_field = grid.fieldNameIndex('destination_id')
    request = QgsFeatureRequest()
    request.setFilterRect(line.boundingBox())
    request.setFilterExpression('"destination_id" is None')
    for feature in grid.getFeatures(request):
        if feature.geometry().intersects(line):
            grid.changeAttributeValue(feature.id(), dest_id_field, destination)
Example #4
0
 def addHighlight(self, requestOrExpr, lineColor=None, fillColor=None, buff=None, minWidth=None):
     request = None
     if isinstance(requestOrExpr, QgsFeatureRequest):
         request = requestOrExpr
         self.highlight = request.filterExpression()
     else:
         request = QgsFeatureRequest()
         request.setFilterExpression(requestOrExpr)
         self.highlight = requestOrExpr
     for layerKey in self._layers:
         self._layers[layerKey].addHighlight(request, lineColor, fillColor, buff, minWidth)
 def get_Gvalue(self, id, epoch):
     req = QgsFeatureRequest()
     exp = self._time_query_string(epoch, self.timeColumn, '=')
     exp += self._id_query_string(id)
     req.setFilterExpression(exp)
     warn("Geom query Expression {}".format(exp))
     s = self.timeLayer.subsetString()
     self.timeLayer.setSubsetString("")
     featIt = self.timeLayer.layer.dataProvider().getFeatures(req)
     self.timeLayer.setSubsetString(s)
     for feat in featIt:
         return self.getGeometryFromFeature(feat)
     return None
Example #6
0
    def testSubsetStringFids(self):
        """ tests that feature ids are stable even if a subset string is set """

        tmpfile = os.path.join(self.basetestpath, 'subsetStringFids.sqlite')
        ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
        lyr.CreateField(ogr.FieldDefn('type', ogr.OFTInteger))
        lyr.CreateField(ogr.FieldDefn('value', ogr.OFTInteger))
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(0)
        f.SetField(0, 1)
        f.SetField(1, 11)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(1)
        f.SetField(0, 1)
        f.SetField(1, 12)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(2)
        f.SetField(0, 1)
        f.SetField(1, 13)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(3)
        f.SetField(0, 2)
        f.SetField(1, 14)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(4)
        f.SetField(0, 2)
        f.SetField(1, 15)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(5)
        f.SetField(0, 2)
        f.SetField(1, 16)
        lyr.CreateFeature(f)
        f = None
        ds = None

        vl = QgsVectorLayer(tmpfile + "|subset=type=2", 'test', 'ogr')
        self.assertTrue(vl.isValid())

        req = QgsFeatureRequest()
        req.setFilterExpression("value=16")
        it = vl.getFeatures(req)
        f = QgsFeature()
        self.assertTrue(it.nextFeature(f))
        self.assertTrue(f.id() == 5)
    def get_ressources(self, params: Dict[str,str], project: QgsProject) -> CadastreResources:
        """ Find layer and feature corresponding to given parameters
        """

        def get_param(name: str, allowed_values: Sequence[str]=None) -> str:
            v = params.get(name)
            if not v:
                raise CadastreError(400,"Missing parameter '%s'" % name)
            v = v
            if allowed_values and not v in allowed_values:
                raise CadastreError(400,"Invalid or missing value for '%s'" % name)
            return v

        # Get layer and expression
        player    = get_param('LAYER')
        pparcelle = get_param('PARCELLE')
        ptype     = get_param('TYPE',('parcelle', 'proprietaire', 'fiche'))

        # Get feature
        if not PARCELLE_FORMAT_RE.match(pparcelle):
            raise CadastreError(400, "Invalid PARCELLE format: %s" % pparcelle)

        # Find layer
        layer = None
        lr = project.mapLayersByName(player)
        if len(lr) > 0:
            layer = lr[0]
        else:
            raise CadastreError(404,"Layer '%s' not found" % player)

        req = QgsFeatureRequest()
        req.setFilterExpression(' "geo_parcelle" = \'%s\' ' % pparcelle)

        it = layer.getFeatures(req)
        feat = QgsFeature()
        if not it.nextFeature(feat):
            raise CadastreError(404,"Feature not found for parcelle '%s' in layer '%s'" % (pparcelle,player))

        # Get layer connection parameters
        connectionParams = cadastre_common.getConnectionParameterFromDbLayer(layer)
        connector = cadastre_common.getConnectorFromUri( connectionParams )

        return CadastreResources(geo_parcelle = pparcelle,
                                 feature = feat,
                                 type = ptype,
                                 layer = layer,
                                 layername = player,
                                 connector = connector,
                                 connectionParams = connectionParams)
Example #8
0
    def currentClassificationChanged(self):
        """Handler for changing the classification. Includes calculation of the desired results."""
        try:
            # Reading current layer and classification out of the comboboxes
            currentLayer = self.vLayers[self.dlg.comboBox.currentIndex()]
            currentClassification = self.dlg.attributeSelect.currentText()

            # clear table widet and initializing it again
            self.dlg.tableWidget.clear()
            self.initTable()

        
            # saving possible classifications in a set -> Set contains only unique classifications
            allClassifications = set()
            for feature in currentLayer.getFeatures():
                allClassifications.add(feature[currentClassification])

            # setting row count
            self.dlg.tableWidget.setRowCount(len(allClassifications))

            # iterator for rows
            rowCount = 0

            # initialising filter expression
            for classification in allClassifications:
                request = QgsFeatureRequest()
                request.setFilterExpression(str(currentClassification) + ' = ' + str(classification))

                # helper values for storing results
                area_total = 0
                area_collection = []

                for feature in currentLayer.getFeatures(request):
                    print str(currentClassification) + ' = ' + str(classification) + " --- " + str(feature.geometry().area())
                    area_total += feature.geometry().area()
                    area_collection.append(feature.geometry().area())


                # write out the results
                self.dlg.tableWidget.setItem(rowCount, 0, QTableWidgetItem(str(classification)))
                self.dlg.tableWidget.setItem(rowCount, 1, QTableWidgetItem(str(round(area_total / 10000, 3))))
                self.dlg.tableWidget.setItem(rowCount, 2, QTableWidgetItem(str(round(min(area_collection) / 10000, 3))))
                self.dlg.tableWidget.setItem(rowCount, 3, QTableWidgetItem(str(round(max(area_collection) / 10000, 3))))
                self.dlg.tableWidget.setItem(rowCount, 4, QTableWidgetItem(str(round(sum(area_collection) / len(area_collection) / 10000,3))))
                self.dlg.tableWidget.setItem(rowCount, 5, QTableWidgetItem(str(len(area_collection))))
                rowCount += 1
        except:
            print 'currentClassificationChanged'
Example #9
0
    def draw (self, resetStyle = False):
        xField = self.xProperty.currentText()
        yField = self.yProperty.currentText()
        
        #X-Axis limits
        self.xMinTime.setVisible (xField == 'Time')
        self.xMaxTime.setVisible (xField == 'Time')
        self.xMinFloat.setVisible(xField != 'Time')
        self.xMaxFloat.setVisible(xField != 'Time')
        self.xMin = self.xMinFloat if xField != 'Time' else self.xMinTime
        self.xMax = self.xMaxFloat if xField != 'Time' else self.xMaxTime
        #Y-Axis limits
        self.yMinTime.setVisible (yField == 'Time')
        self.yMaxTime.setVisible (yField == 'Time')
        self.yMinFloat.setVisible(yField != 'Time')
        self.yMaxFloat.setVisible(yField != 'Time')
        self.yMin = self.yMinFloat if yField != 'Time' else self.yMinTime
        self.yMax = self.yMaxFloat if yField != 'Time' else self.yMaxTime 
        
        ySorted = self.ySorted.isChecked()
        
        self.plotWidget.clean (xField = xField,
                               yField = yField,
                               resetStyle = resetStyle)

        request = QgsFeatureRequest ()
        request.setFlags(QgsFeatureRequest.NoGeometry)
                
        for foi in self.foiList:
            request.setFilterExpression("foi = '%s'" % foi)
            if ySorted:
                dataSerie = [(f.attribute(yField),f.attribute(xField)) for f in self.layer.getFeatures(request)]
            else:
                dataSerie = [(f.attribute(xField),f.attribute(yField)) for f in self.layer.getFeatures(request)]
            dataSerie.sort()
            
            if len (dataSerie):
                if ySorted:
                    y,x = map(list, zip(*dataSerie))
                else:
                    x,y = map(list, zip(*dataSerie))
                self.plotWidget.plot(x,y, f.attribute('name'))
                self.plotWidget.applyTimeFormat (self.timeFormat.text())
                self.plotWidget.draw ()
        
        styles = self.StylesTable (self.plotWidget.ax.get_lines())
        self.stylesTable.setModel (styles)
        styles.dataChanged.connect(self.plotWidget.draw)
Example #10
0
    def toggle_electorate_deprecation(self, electorate):
        """
        Toggles the deprecation flag for an electorate
        :param electorate: electorate id
        """
        request = QgsFeatureRequest()
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([self.deprecated_field_index])
        request.setFilterExpression(QgsExpression.createFieldEqualityExpression(self.source_field, electorate))
        f = next(self.source_layer.getFeatures(request))

        is_deprecated = f[self.deprecated_field_index]
        if is_deprecated == NULL:
            is_deprecated = False

        new_status = 0 if is_deprecated else 1
        self.source_layer.dataProvider().changeAttributeValues({f.id(): {self.deprecated_field_index: new_status}})
Example #11
0
 def addHighlight(self,
                  requestOrExpr,
                  lineColor=None,
                  fillColor=None,
                  buff=None,
                  minWidth=None):
     request = None
     if isinstance(requestOrExpr, QgsFeatureRequest):
         request = requestOrExpr
         self.highlight = request.filterExpression()
     else:
         request = QgsFeatureRequest()
         request.setFilterExpression(requestOrExpr)
         self.highlight = requestOrExpr
     for layerKey in self._layers:
         self._layers[layerKey].addHighlight(request, lineColor, fillColor,
                                             buff, minWidth)
Example #12
0
    def runGetFeatureTests(self, source):
        FeatureSourceTestCase.runGetFeatureTests(self, source)

        # combination of an uncompilable expression and limit
        feature = next(self.vl.getFeatures('pk=4'))
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        scope.setVariable('parent', feature)
        context.appendScope(scope)

        request = QgsFeatureRequest()
        request.setExpressionContext(context)
        request.setFilterExpression('"pk" = attribute(@parent, \'pk\')')
        request.setLimit(1)

        values = [f['pk'] for f in self.vl.getFeatures(request)]
        self.assertEqual(values, [4])
Example #13
0
    def flag_stats_nz_updating(self, electorate_id):
        """
        Flags an electorate's Statistics NZ api calculations as being currently updated
        :param electorate_id: electorate to update
        """

        # get feature ID
        request = QgsFeatureRequest()
        request.setFilterExpression(QgsExpression.createFieldEqualityExpression(self.source_field, electorate_id))
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([])
        request.setLimit(1)
        f = next(self.source_layer.getFeatures(request))

        self.source_layer.dataProvider().changeAttributeValues({f.id(): {self.stats_nz_pop_field_index: -1,
                                                                         self.stats_nz_var_20_field_index: NULL,
                                                                         self.stats_nz_var_23_field_index: NULL}})
Example #14
0
    def runGetFeatureTests(self, source):
        FeatureSourceTestCase.runGetFeatureTests(self, source)

        # combination of an uncompilable expression and limit
        feature = next(self.vl.getFeatures('pk=4'))
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        scope.setVariable('parent', feature)
        context.appendScope(scope)

        request = QgsFeatureRequest()
        request.setExpressionContext(context)
        request.setFilterExpression('"pk" = attribute(@parent, \'pk\')')
        request.setLimit(1)

        values = [f['pk'] for f in self.vl.getFeatures(request)]
        self.assertEqual(values, [4])
Example #15
0
    def add_stratigraphy(self,
                         layer,
                         filter_expression,
                         column_mapping,
                         title,
                         style_file=None,
                         config=None,
                         station_name=""):
        """Add stratigraphy data

        Parameters
        ----------
        layer: QgsVectorLayer
          The layer where stratigraphic data are stored
        filter_expression: str
          A QGIS expression to filter the vector layer
        column_mapping: dict
          Dictionary of column names
        title: str
          Title of the graph
        style_file: str
          Name of the style file to use
        config: PlotConfig
        station_name: str
        """
        symbology = config.get_symbology()[0] if config else None
        item = StratigraphyItem(
            self.DEFAULT_COLUMN_WIDTH,
            self._scene.height(),
            style_file=style_file if not symbology else None,
            symbology=symbology,
            column_mapping=column_mapping)
        item.style_updated.connect(self.styles_updated)
        legend_item = LegendItem(self.DEFAULT_COLUMN_WIDTH, title)

        item.set_layer(layer)
        item.tooltipRequested.connect(
            lambda txt: self.on_plot_tooltip(station_name, txt))

        req = QgsFeatureRequest()
        req.setFilterExpression(filter_expression)
        item.set_data(list(layer.getFeatures(req)))

        self._add_cell(item, legend_item)
        return item.min_depth(), item.max_depth()
 def addHighlight(self, requestOrExpr, lineColor=None, fillColor=None, buff=None, minWidth=None):
     request = None
     if isinstance(requestOrExpr, QgsFeatureRequest):
         request = requestOrExpr
         self.highlight = request.filterExpression()
     else:
         request = QgsFeatureRequest()
         request.setFilterExpression(requestOrExpr)
         self.highlight = requestOrExpr
     for feature in self.polygonsLayer.getFeatures(request):
         hl = layers.addHighlight(self._iface.mapCanvas(), feature, self.polygonsLayer, lineColor, fillColor, buff, minWidth)
         self._highlights.append(hl)
     for feature in self.linesLayer.getFeatures(request):
         hl = layers.addHighlight(self._iface.mapCanvas(), feature, self.linesLayer, lineColor, fillColor, buff, minWidth)
         self._highlights.append(hl)
     for feature in self.pointsLayer.getFeatures(request):
         hl = layers.addHighlight(self._iface.mapCanvas(), feature, self.pointsLayer, lineColor, fillColor, buff, minWidth)
         self._highlights.append(hl)
Example #17
0
    def __build_data(self):

        req = QgsFeatureRequest()
        if self.__filter_expression is not None:
            req.setFilterExpression(self.__filter_expression)

        # Get unit of the first feature if needed
        if self.__uom is not None and self.__uom.startswith("@"):
            request_unit = QgsFeatureRequest(req)
            request_unit.setLimit(1)
            for f in self.__layer.getFeatures(request_unit):
                self.__uom = f[self.__uom[1:]]
                break

        req.setSubsetOfAttributes([self.__x_fieldname, self.__y_fieldname],
                                  self.__layer.fields())
        # Do not forget to add an index on this field to speed up ordering
        req.addOrderBy(self.__x_fieldname)

        def is_null(v):
            return isinstance(v, QVariant) and v.isNull()

        if self.__nodata_value is not None:
            # replace null values by a 'Nodata' value
            xy_values = [
                (f[self.__x_fieldname], f[self.__y_fieldname] if
                 not is_null(f[self.__y_fieldname]) else self.__nodata_value)
                for f in self.__layer.getFeatures(req)
            ]
        else:
            # do not include null values
            xy_values = [(f[self.__x_fieldname], f[self.__y_fieldname])
                         for f in self.__layer.getFeatures(req)
                         if not is_null(f[self.__y_fieldname])]

        self.__x_values = [coord[0] for coord in xy_values]
        self.__y_values = [coord[1] for coord in xy_values]

        self.__x_min, self.__x_max = (min(self.__x_values), max(
            self.__x_values)) if self.__x_values else (None, None)
        self.__y_min, self.__y_max = (min(self.__y_values), max(
            self.__y_values)) if self.__y_values else (None, None)

        self.data_modified.emit()
Example #18
0
    def update_stats_nz_values(self, electorate_id, results: dict):
        """
        Updates an electorate's stored Statistics NZ api calculations
        :param electorate_id: electorate to update
        :param results: results dictionary from stats API
        """

        # get feature ID
        request = QgsFeatureRequest()
        request.setFilterExpression(QgsExpression.createFieldEqualityExpression(self.source_field, electorate_id))
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([])
        request.setLimit(1)
        f = next(self.source_layer.getFeatures(request))

        self.source_layer.dataProvider().changeAttributeValues(
            {f.id(): {self.stats_nz_pop_field_index: results['currentPopulation'],
                      self.stats_nz_var_20_field_index: results['varianceYear1'],
                      self.stats_nz_var_23_field_index: results['varianceYear2']}})
Example #19
0
    def validate_sql(self):
        """Checks if the rule can be executed without errors

        :return: (True, None) if rule has valid SQL, (False, ValidationError) if it is not valid
        :rtype: tuple (bool, ValidationError)
        """

        try:
            req = QgsFeatureRequest()
            req.setFilterExpression(self.get_qgis_expression())
            expression = req.filterExpression()
            if expression is None:
                return False, QgsExpression(self.rule).parserErrorString()
            if not expression.isValid():
                return False, expression.parserErrorString()
        except Exception as ex:
            logger.debug('Validate SQL failed: %s' % ex)
            return False, ex
        return True, None
    def removeEqualitiesFromCandidateLayer(self):
        print("Start collapse equality chains")
        print("Starting with {count} features".format(
            count=str(self.working_layer.featureCount())))

        dupe = duplicateLayer(self.working_layer, "Duplicate")
        join_prefix = JOIN_PREFIX

        res = processing.run(
            "qgis:joinattributesbylocation",
            {
                'INPUT': self.working_layer,
                'JOIN': dupe,
                'PREDICATE': ['2'],  # 2 := Equals
                'JOIN_FIELDS': '',
                'METHOD': '0',
                'DISCARD_NONMATCHING': False,
                'PREFIX': join_prefix,
                'OUTPUT': r'memory:equalities'
            },
            context=PROCESSING_CONTEXT)

        equalities_layer = res['OUTPUT']

        # equality is reflexive, so this filter is wlog
        filter_icl = QgsFeatureRequest()
        filter_icl.setFilterExpression(self.lessThanIDFilterString())

        self.working_layer.startEditing()

        # for the equality predicate, we remove the losers from all future consideration
        for feat in equalities_layer.getFeatures(filter_icl):
            if self.compareFeatures(feat):  # left side loses
                self.removeFromCandidateLayer(
                    feat[self.getLayerIdentifier(False)])
            else:
                self.removeFromCandidateLayer(
                    feat[self.getLayerIdentifier(True)])  # right side loses

        self.working_layer.commitChanges()
        print("Ending with {count} features".format(
            count=str(self.working_layer.featureCount())))
Example #21
0
    def paint(self, painter, option, widget):  # pylint: disable=missing-docstring, unused-argument, too-many-locals
        if self.image is not None:
            painter.drawImage(0, 0, self.image)
            return

        image_size = self.canvas.mapSettings().outputSize()
        self.image = QImage(image_size.width(), image_size.height(),
                            QImage.Format_ARGB32)
        self.image.fill(0)
        image_painter = QPainter(self.image)
        render_context = QgsRenderContext.fromQPainter(image_painter)

        image_painter.setRenderHint(QPainter.Antialiasing, True)

        rect = self.canvas.mapSettings().visibleExtent()
        request = QgsFeatureRequest()
        request.setFilterRect(rect)
        request.setFilterExpression(
            QgsExpression.createFieldEqualityExpression('type', self.task))

        for f in self.electorate_layer.getFeatures(request):
            #    pole, dist = f.geometry().clipped(rect).poleOfInaccessibility(rect.width() / 30)
            pixel = self.toCanvasCoordinates(
                f.geometry().clipped(rect).centroid().asPoint())

            calc = QgsAggregateCalculator(self.meshblock_layer)
            calc.setFilter('staged_electorate={}'.format(f['electorate_id']))
            estimated_pop, ok = calc.calculate(QgsAggregateCalculator.Sum,
                                               'offline_pop_{}'.format(
                                                   self.task.lower()))  # pylint: disable=unused-variable

            text_string = [
                '{}'.format(f['name']), '{}'.format(int(estimated_pop))
            ]
            QgsTextRenderer().drawText(QPointF(pixel.x(), pixel.y()), 0,
                                       QgsTextRenderer.AlignCenter,
                                       text_string, render_context,
                                       self.text_format)

        image_painter.end()

        painter.drawImage(0, 0, self.image)
Example #22
0
    def get_constraint_geometry(self):
        """Returns the geometry from the constraint layer and rule

        :return: the constraint geometry and the number of matched records
        :rtype: tuple( MultiPolygon, integer)
        """

        constraint_layer = get_qgis_layer(self.constraint.constraint_layer)
        editing_layer = get_qgis_layer(self.constraint.editing_layer)

        # Get the geometries from constraint layer and rule
        qgis_feature_request = QgsFeatureRequest()
        qgis_feature_request.setFilterExpression(self.rule)

        features = get_qgis_features(constraint_layer, qgis_feature_request, exclude_fields='__all__')

        if not features:
            return '', 0

        geometry = QgsMultiPolygon()

        for feature in features:
            geom = feature.geometry()
            if geom.isMultipart():
                geom = [g for g in geom.constGet()]
            else:
                geom = [geom.constGet()]

            i = 0
            for g in geom:
                geometry.insertGeometry(g.clone(), 0)
                i += 1

        # Now, transform into a GEOS geometry
        if constraint_layer.crs() != editing_layer.crs():
            ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem(constraint_layer.crs()), QgsCoordinateReferenceSystem(editing_layer.crs()), QgsCoordinateTransformContext())
            geometry.transform(ct)

        constraint_geometry = MultiPolygon.from_ewkt('SRID=%s;' % editing_layer.crs().postgisSrid() + geometry.asWkt())

        return constraint_geometry, constraint_geometry.num_geom
Example #23
0
    def searchFieldInLayer(self, layer, searchStr, comparisonMode,
                           selectedField):
        '''Do a string search on a specific column in the table.'''
        if self.killed:
            return

        request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([selectedField], layer.fields())
        if comparisonMode == 0:  # Searching for an exact match
            request.setFilterExpression('"{}" LIKE \'{}\''.format(
                selectedField, searchStr))
        elif comparisonMode == 1:  # contains string
            request.setFilterExpression('"{}" ILIKE \'%{}%\''.format(
                selectedField, searchStr))
        else:  # begins with string
            request.setFilterExpression('"{}" ILIKE \'{}%\''.format(
                selectedField, searchStr))

        for feature in layer.getFeatures(request):
            # Check to see if it has been aborted
            if self.killed is True:
                return
            f = feature.attribute(selectedField)
            self.foundmatch.emit(layer, feature, selectedField, str(f))
            self.found += 1
            if self.found >= self.maxResults:
                self.killed = True
                return
Example #24
0
    def updateUiManyToManyPolymorphic(self):
        layer = self.relation().referencingLayer()
        request = self.relation().getRelatedFeaturesRequest(self.feature())
        layerFeature = dict()
        for linkFeature in layer.getFeatures(request):
            for relation in self._polymorphicRelation.generateRelations():
                referencedFeatureRequest = relation.getReferencedFeatureRequest(
                    linkFeature)
                filterExpression = referencedFeatureRequest.filterExpression()
                nmRequest = QgsFeatureRequest()
                nmRequest.setFilterExpression(filterExpression.expression())

                finalLayer = relation.referencedLayer()
                for finalFeature in finalLayer.getFeatures(nmRequest):
                    features = finalFeature, linkFeature
                    if finalLayer in layerFeature:
                        layerFeature[finalLayer].append(features)
                    else:
                        layerFeature[finalLayer] = [features]

        for layer in layerFeature:
            treeWidgetItemLayer = QTreeWidgetItem(self.mFeaturesTreeWidget,
                                                  [layer.name()])
            treeWidgetItemLayer.setData(0, TreeWidgetItemRole.Type,
                                        TreeWidgetItemType.Layer)
            treeWidgetItemLayer.setData(0, TreeWidgetItemRole.Layer, layer)
            treeWidgetItemLayer.setIcon(0, QgsIconUtils.iconForLayer(layer))
            for feature, linkFeature in layerFeature[layer]:
                treeWidgetItem = QTreeWidgetItem(treeWidgetItemLayer, [
                    QgsVectorLayerUtils.getFeatureDisplayString(
                        layer, feature)
                ])
                treeWidgetItem.setData(0, TreeWidgetItemRole.Type,
                                       TreeWidgetItemType.Feature)
                treeWidgetItem.setData(0, TreeWidgetItemRole.Layer, layer)
                treeWidgetItem.setData(0, TreeWidgetItemRole.Feature, feature)
                treeWidgetItem.setData(0, TreeWidgetItemRole.LinkFeature,
                                       linkFeature)
            treeWidgetItemLayer.setExpanded(True)
 def get_target_meshblock_ids_from_numbers(
         self, meshblock_numbers: List[int]) -> Dict[int, int]:
     """
     Returns a dictionary of target meshblock feature IDs corresponding to the
     specified meshblock numbers
     :param meshblock_numbers: list of meshblock numbers to lookup
     """
     assert self.scenario is not None
     request = QgsFeatureRequest()
     request.setSubsetOfAttributes([self.target_meshblock_number_idx])
     request.setFilterExpression(
         QgsExpression.createFieldEqualityExpression(
             'scenario_id', self.scenario))
     meshblock_filter = 'meshblock_number IN ({})'.format(','.join(
         [str(mb) for mb in meshblock_numbers]))
     request.combineFilterExpression(meshblock_filter)
     # create dictionary of meshblock number to id
     mb_number_to_target_id = {}
     for f in self.meshblock_scenario_layer.getFeatures(request):
         mb_number_to_target_id[f[
             self.target_meshblock_number_idx]] = f.id()
     return mb_number_to_target_id
Example #26
0
    def test_relationonetomany_api(self):
        """ Test relationonetomany filter """

        cities = Layer.objects.get(project_id=self.project310.instance.pk,
                                   origname='cities10000eu')
        qgis_project = get_qgs_project(cities.project.qgis_file.path)
        qgis_layer = qgis_project.mapLayer(cities.qgs_layer_id)

        total_count = qgis_layer.featureCount()

        resp = json.loads(
            self._testApiCall('core-vector-api', [
                'data', 'qdjango', self.project310.instance.pk,
                cities.qgs_layer_id
            ], {
                FILTER_RELATIONONETOMANY_PARAM: ''
            }).content)

        self.assertEqual(resp['vector']['count'], total_count)

        # check filter by relations

        resp = json.loads(
            self._testApiCall(
                'core-vector-api', [
                    'data', 'qdjango', self.project310.instance.pk,
                    cities.qgs_layer_id
                ], {
                    FILTER_RELATIONONETOMANY_PARAM:
                    'cities1000_ISO2_CODE_countries__ISOCODE|18'
                }).content)

        qgs_request = QgsFeatureRequest()
        qgs_request.setFilterExpression('"ISO2_CODE" = \'IT\'')
        qgis_layer.selectByExpression(
            qgs_request.filterExpression().expression())

        features = qgis_layer.getFeatures(qgs_request)
        self.assertEqual(resp['vector']['count'], len([f for f in features]))
    def redraw(self, handler):
        """
        Forces a redraw of the cached image
        """
        self.image = None

        if not self.original_populations:
            # first run, get initial estimates
            request = QgsFeatureRequest()
            request.setFilterExpression(QgsExpression.createFieldEqualityExpression('type', self.task))
            request.setFlags(QgsFeatureRequest.NoGeometry)
            for f in self.electorate_layer.getFeatures(request):
                estimated_pop = f.attribute(handler.stats_nz_pop_field_index)
                if estimated_pop is None or estimated_pop == NULL:
                    # otherwise just use existing estimated pop as starting point
                    estimated_pop = f.attribute(handler.estimated_pop_idx)
                self.original_populations[f.id()] = estimated_pop

        # step 1: get all electorate features corresponding to affected electorates
        electorate_features = {f[handler.electorate_layer_field]: f for f in
                               handler.get_affected_districts(
                                   [handler.electorate_layer_field, handler.stats_nz_pop_field, 'estimated_pop'],
                                   needs_geometry=False)}

        self.new_populations = {}

        for district in handler.pending_affected_districts.keys():  # pylint: disable=consider-iterating-dictionary
            # use stats nz pop as initial estimate, if available
            estimated_pop = electorate_features[district].attribute(handler.stats_nz_pop_field_index)
            if estimated_pop is None or estimated_pop == NULL:
                # otherwise just use existing estimated pop as starting point
                estimated_pop = electorate_features[district].attribute(handler.estimated_pop_idx)
            # add new bits
            estimated_pop = handler.grow_population_with_added_meshblocks(district, estimated_pop)
            # minus lost bits
            estimated_pop = handler.shrink_population_by_removed_meshblocks(district, estimated_pop)

            self.new_populations[electorate_features[district].id()] = estimated_pop
Example #28
0
    def updateUiManyToMany(self):
        layer = self.relation().referencingLayer()
        request = self.relation().getRelatedFeaturesRequest(self.feature())
        filters = []
        for feature in layer.getFeatures(request):
            referencedFeatureRequest = self.nmRelation(
            ).getReferencedFeatureRequest(feature)
            filterExpression = referencedFeatureRequest.filterExpression()
            filters.append("(" + filterExpression.expression() + ")")

            nmRequest = QgsFeatureRequest()
            nmRequest.setFilterExpression(" OR ".join(filters))

            finalLayer = self.nmRelation().referencedLayer()
            for finalFeature in finalLayer.getFeatures(nmRequest):
                treeWidgetItem = QTreeWidgetItem(self.mFeaturesTreeWidget, [
                    QgsVectorLayerUtils.getFeatureDisplayString(
                        finalLayer, finalFeature)
                ])
                treeWidgetItem.setData(0, TreeWidgetItemRole.Type,
                                       TreeWidgetItemType.Feature)
                treeWidgetItem.setData(0, TreeWidgetItemRole.Layer, finalLayer)
                treeWidgetItem.setData(0, TreeWidgetItemRole.Feature, feature)
Example #29
0
def search_layer(layer, filter, field_list=None, with_geometry=False):
    """
    Search the given layer using the given filter.  Only return the fields passed in the field_list.
    :param layer: The layer to search
    :param filter: The filter to apply to the layer to find matching features.
    :param field_list: Only return data for the given fields.
    :param with_geometry: If True will also return geometry data. Leave False for faster search.
    :return: A iterator with the features found with the filter.
    """
    flags = QgsFeatureRequest.NoFlags
    if not with_geometry:
        flags = QgsFeatureRequest.NoGeometry

    request = QgsFeatureRequest()\
        .setFlags(flags)
    
    if filter:
        request.setFilterExpression(filter)

    if field_list:
        request.setSubsetOfAttributes(field_list)

    return layer.getFeatures(request)
    def read(self, feature_type, bbox = None, attributes = None, geometry=True, feature_filter=None):
        if not isinstance(feature_type, FeatureType):
            raise TypeError()
        lyr = self._connectlayer(feature_type)

        request = None
        if bbox or attributes is not None or not geometry or feature_filter:
            request = QgsFeatureRequest()
            if bbox:
                rect = QgsRectangle(*bbox)
                request.setFilterRect(rect)
            if attributes:
                request.setSubsetOfAttributes(attributes, lyr.pendingFields())
            if not geometry:
                request.setFlags(QgsFeatureRequest.NoGeometry)
            if feature_filter:
                request.setFilterExpression(feature_filter)
                #lyr.setSubsetString(feature_filter)

        # return listoffeatures
        # filter is maybe a QgsFeatureRequest
        # http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/vector.html#iterating-over-a-subset-of-features
        return list(lyr.getFeatures(request) if request else lyr.getFeatures())
Example #31
0
    def createWrapper(self, layer, filter=None):
        """
        Basic setup of a relation widget wrapper.
        Will create a new wrapper and set its feature to the one and only book
        in the table.
        It will also assign some instance variables to help

         * self.widget The created widget
         * self.table_view The table view of the widget

        :return: The created wrapper
        """
        if layer == self.vl_books:
            relation = self.rel_b
            nmrel = self.rel_a
        else:
            relation = self.rel_a
            nmrel = self.rel_b

        self.wrapper = QgsRelationWidgetWrapper(layer, relation)
        self.wrapper.setConfig({'nm-rel': nmrel.id()})
        context = QgsAttributeEditorContext()
        context.setMapCanvas(self.mapCanvas)
        context.setVectorLayerTools(self.vltools)
        self.wrapper.setContext(context)

        self.widget = self.wrapper.widget()
        self.widget.show()

        request = QgsFeatureRequest()
        if filter:
            request.setFilterExpression(filter)
        book = next(layer.getFeatures(request))
        self.wrapper.setFeature(book)

        self.table_view = self.widget.findChild(QTableView)
        return self.wrapper
    def createWrapper(self, layer, filter=None):
        """
        Basic setup of a relation widget wrapper.
        Will create a new wrapper and set its feature to the one and only book
        in the table.
        It will also assign some instance variables to help

         * self.widget The created widget
         * self.table_view The table view of the widget

        :return: The created wrapper
        """
        if layer == self.vl_b:
            relation = self.rel_b
            nmrel = self.rel_a
        else:
            relation = self.rel_a
            nmrel = self.rel_b

        parent = QWidget()
        self.wrapper = QgsRelationWidgetWrapper(layer, relation)
        self.wrapper.setConfig({'nm-rel': nmrel.id()})
        context = QgsAttributeEditorContext()
        context.setVectorLayerTools(self.vltools)
        self.wrapper.setContext(context)

        self.widget = self.wrapper.widget()
        self.widget.show()

        request = QgsFeatureRequest()
        if filter:
            request.setFilterExpression(filter)
        book = layer.getFeatures(request).next()
        self.wrapper.setFeature(book)

        self.table_view = self.widget.findChild(QTableView)
        return self.wrapper
Example #33
0
    def _populate_cache(self):
        req = QgsFeatureRequest()
        filter = self.__filter_expression or ""
        if filter:
            filter += " and "
        filter += "{} >= {} and {} <= {}".format(self.__min_x_field,
                                                 self.__data_rect.x(),
                                                 self.__max_x_field,
                                                 self.__data_rect.right())
        req.setFilterExpression(filter)
        req.setSubsetOfAttributes(
            [self.__min_x_field, self.__max_x_field, self.__y_field],
            self.__layer.fields())
        req.addOrderBy(self.__min_x_field)

        # reset cache for picking
        self.__min_x_values = []
        self.__max_x_values = []
        self.__y_values = []

        for f in self.__layer.getFeatures(req):
            self.__min_x_values.append(f[self.__min_x_field])
            self.__max_x_values.append(f[self.__max_x_field])
            self.__y_values.append(f[self.__y_field])
    def electorate_meshblocks(self, electorate_id, electorate_type: str,
                              scenario_id) -> QgsFeatureIterator:
        """
        Returns meshblock features currently assigned to an electorate in a
        given scenario
        :param electorate_id: electorate id
        :param electorate_type: electorate type, e.g. 'GN','GS','M'
        :param scenario_id: scenario id
        """
        request = QgsFeatureRequest()

        type_field = '{}_id'.format(electorate_type.lower())
        type_field_index = self.meshblock_electorate_layer.fields(
        ).lookupField(type_field)
        assert type_field_index >= 0

        request.setFilterExpression(
            QgsExpression.createFieldEqualityExpression(
                'scenario_id', scenario_id))
        request.combineFilterExpression(
            QgsExpression.createFieldEqualityExpression(
                type_field, electorate_id))

        return self.meshblock_electorate_layer.getFeatures(request)
Example #35
0
    def get_nodes(self, wb_polygon, model_part):
        """Returns a dictionary with node ids by category:

        {
            '1d': [..., ...],
            '2d': [..., ...],
            '2d_groundwater': [..., ...],
        }
        """

        log.info('polygon of wb area: %s', wb_polygon.exportToWkt())

        nodes = {
            '1d': [],
            '2d': [],
            '2d_groundwater': [],
        }

        lines, points, pumps = self.ts_datasource.rows[0].get_result_layers()

        # use bounding box and spatial index to prefilter lines
        request_filter = QgsFeatureRequest().setFilterRect(
            wb_polygon.geometry().boundingBox())
        if model_part == '1d':
            request_filter.setFilterExpression(u'"type" = \'1d\'')
        elif model_part == '2d':
            request_filter.setFilterExpression(
                u'"type" = \'2d\' OR "type" = \'2d_groundwater\'')
        else:
            request_filter.setFilterExpression(
                u'"type" = \'1d\' OR "type" = \'2d\' OR "type" = \'2d_groundwater\''
            )
        # todo: check if boundary nodes could not have rain, infiltration, etc.

        for point in points.getFeatures(request_filter):
            # test if points are contained by polygon
            if wb_polygon.contains(point.geometry()):
                _type = point['type']
                nodes[_type].append(point['id'])

        return nodes
    def searchFieldInLayer(self, layer, searchStr, comparisonMode, selectedField):
        '''Do a string search on a specific column in the table.'''
        if self.killed:
            return

        request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([selectedField], layer.fields())
        if comparisonMode == 0: # Searching for an exact match
            request.setFilterExpression('"{}" LIKE \'{}\''.format(selectedField,searchStr))
        elif comparisonMode == 1: # contains string
            request.setFilterExpression('"{}" ILIKE \'%{}%\''.format(selectedField,searchStr))
        else: # begins with string
            request.setFilterExpression('"{}" ILIKE \'{}%\''.format(selectedField,searchStr))

        for feature in layer.getFeatures(request):
            # Check to see if it has been aborted
            if self.killed is True:
                return
            f = feature.attribute(selectedField)
            self.foundmatch.emit(layer, feature, selectedField, str(f))
            self.found += 1
            if self.found >= self.maxResults:
                self.killed=True
                return
Example #37
0
    def processAlgorithm(self, progress):
        network = dataobjects.getObjectFromUri(
            self.getParameterValue(self.NETWORK_LAYER))
        # Ensure that outlet arc is selected
        if network.selectedFeatureCount() != 1:
            raise GeoAlgorithmExecutionException(
                self.tr('Seems oulet arc is not selected. Select outlet'
                        'arc in the stream network layer and try again.'))

        # First add new fields to the network layer
        networkProvider = network.dataProvider()
        networkProvider.addAttributes(
            [QgsField('StrahOrder', QVariant.Int, '', 10),    # Strahler order
             QgsField('DownNodeId', QVariant.Int, '', 10),    # downstream node id
             QgsField('UpNodeId', QVariant.Int, '', 10),      # upstream node id
             QgsField('DownArcId', QVariant.Int, '', 10),     # downstream arc id
             QgsField('UpArcId', QVariant.String, '', 250),   # comma separated list of upstream arc ids
             QgsField('Length', QVariant.Double, '', 20, 6),  # length of the arc
             QgsField('LengthDown', QVariant.Double, '', 20, 6), # length downstream
             QgsField('LengthUp', QVariant.Double, '', 20, 6)])  # length upstream
        network.updateFields()

        # Determine indexes of the fields
        idxStrahler = network.fieldNameIndex('StrahOrder')
        idxDownNodeId = network.fieldNameIndex('DownNodeId')
        idxUpNodeId = network.fieldNameIndex('UpNodeId')
        idxDownArcId = network.fieldNameIndex('DownArcId')
        idxUpArcId = network.fieldNameIndex('UpArcId')
        idxLength = network.fieldNameIndex('Length')
        idxLenDown = network.fieldNameIndex('LengthDown')
        idxLenUp = network.fieldNameIndex('LengthUp')

        # Generate arc adjacency dictionary
        # Algorithm at pages 79-80 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Generating arc adjacency dictionary...'))
        self.arcsPerNode = arcsAadjacencyDictionary(network)

        # Node indexing
        # Algorithm at pages 80-81 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Indexing nodes...'))
        self.dwUpNodesId = dict()

        # Outlet arc and its upstream node
        outletArc = network.selectedFeatures()[0]
        upNode = outletArc.geometry().asPolyline()[-1]

        # Dictionary for storing node indexes per arc.
        # For outlet arc we assign -1 for downstream and 0 for upstream nodes
        self.dwUpNodesId[outletArc.id()] = [-1, 0]
        # Current node id
        self.nodeId = 0

        # Start recursive node indexing procedure
        self.nodeIndexing(outletArc, upNode)

        # Write node indices to the network layer attributes
        progress.setInfo(self.tr('Assigning indices...'))
        for i in self.dwUpNodesId.keys():
            nodeIds = self.dwUpNodesId[i]
            attrs = {idxDownNodeId:nodeIds[0], idxUpNodeId:nodeIds[1]}
            networkProvider.changeAttributeValues({i: attrs})

        # Mapping between upstream node id from attribute table and  QGIS
        # feature id. Will be used to sort features from the network table
        myNetwork = dict()

        # Find upstream and downstream arc ids for each arc in the stream
        # network layer. First we generate helper arcPerNodeId dictionary
        # with node ids as keys and lists of arc ids connected to this node
        # as values
        # Algorithm at pages 55-56 "Automated AGQ4Vector Watershed.pdf"
        arcsPerNodeId = dict()
        for f in network.getFeatures():
            if f['UpNodeId'] not in arcsPerNodeId:
                arcsPerNodeId[f['UpNodeId']] = [f.id()]
            else:
                arcsPerNodeId[f['UpNodeId']].append(f.id())

            if f['DownNodeId'] not in arcsPerNodeId:
                arcsPerNodeId[f['DownNodeId']] = [f.id()]
            else:
                arcsPerNodeId[f['DownNodeId']].append(f.id())

            # Also populate mapping between upstream node id and feature id
            myNetwork[f['UpNodeId']] = f.id()

        # Populating upstream and downstream arc ids
        # Iterate over all arcs in the stream network layer
        for f in network.getFeatures():
            fid = f.id()
            # Determine upstream node id
            upNodeId = f['UpNodeId']

            attrs = {idxDownArcId:fid}
            changes = dict()
            ids = []

            # Iterate over all arcs connected to the upstream node with
            # given id, skipping current arc
            for i in arcsPerNodeId[upNodeId]:
                if i != fid:
                    # Modify DownArcId
                    changes[i] = attrs
                    # Collect ids of the arcs located upstream
                    ids.append(str(i))

            networkProvider.changeAttributeValues(changes)
            networkProvider.changeAttributeValues({fid:{idxUpArcId:','.join(ids)}})

            # Also calculate length of the current arc
            networkProvider.changeAttributeValues({fid:{idxLength:f.geometry().length()}})

        # Calculate length upstream for arcs
        # Algorithm at pages 61-62 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Calculating length upstream...'))
        req = QgsFeatureRequest()
        # Iterate over upsteram node ids starting from the last ones
        # which represents source arcs
        for nodeId in sorted(myNetwork.keys(), reverse=True):
            f = network.getFeatures(req.setFilterFid(myNetwork[nodeId])).next()
            arcLen = f['Length']
            upstreamArcs = f['UpArcId']
            if not upstreamArcs:
                networkProvider.changeAttributeValues({f.id():{idxLenUp: arcLen}})
            else:
                length = []
                for i in upstreamArcs.split(','):
                    f = network.getFeatures(req.setFilterFid(int(i))).next()
                    if f['LengthUp']:
                        length.append(f['LengthUp'])
                    upLen = max(length) if len(length) > 0  else 0.0
                networkProvider.changeAttributeValues({myNetwork[nodeId]:{idxLenUp:arcLen + upLen}})

        # Calculate length downstream for arcs
        # Algorithm at pages 62-63 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Calculating length downstream...'))
        first = True
        # Iterate over upsteram node ids starting from the first one
        # which represents downstream node of the outlet arc
        for nodeId in sorted(myNetwork.keys()):
            f = network.getFeatures(req.setFilterFid(myNetwork[nodeId])).next()
            # for outlet arc downstream length set to zero
            if first:
                networkProvider.changeAttributeValues({myNetwork[nodeId]:{idxLenDown:0.0}})
                first = False
                continue

            arcLen = f['Length']
            downArcId = f['DownArcId']
            f = network.getFeatures(req.setFilterFid(downArcId)).next()
            lenDown = f['LengthDown'] if f['LengthDown'] else 0.0
            networkProvider.changeAttributeValues({myNetwork[nodeId]:{idxLenDown: arcLen + lenDown}})

        # calculate Strahler orders
        # Algorithm at pages 65-66 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Calculating Strahler orders...'))
        # Iterate over upsteram node ids starting from the last ones
        # which represents source arcs
        for nodeId in sorted(myNetwork.keys(), reverse=True):
            f = network.getFeatures(req.setFilterFid(myNetwork[nodeId])).next()
            fid = f.id()
            upstreamArcs = f['UpArcId']
            if upstreamArcs == NULL:
                networkProvider.changeAttributeValues({fid:{idxStrahler: 1}})
            else:
                orders = []
                for i in upstreamArcs.split(','):
                    f = network.getFeatures(req.setFilterFid(int(i))).next()
                    if f['StrahOrder']:
                        orders.append(f['StrahOrder'])
                orders.sort(reverse=True)
                if len(orders) == 1:
                    order = orders[0]
                elif len(orders) >= 2:
                    diff = orders[0] - orders[1]
                    if diff == 0:
                        order = orders[0] + 1
                    else:
                        order = max([orders[0], orders[1]])
                networkProvider.changeAttributeValues({fid:{idxStrahler: order}})

        # Calculate order frequency
        progress.setInfo(self.tr('Calculating order frequency...'))

        maxOrder = int(network.maximumValue(idxStrahler))
        ordersFrequency = dict()
        bifRatios = dict()

        # Initialize dictionaries
        for i in xrange(1, maxOrder + 1):
            ordersFrequency[i] = dict(N=0.0, Ndu=0.0, Na=0.0)
            bifRatios[i] = dict(Rbu=0.0, Rbdu=0.0, Ru=0.0)

        for i in xrange(1, maxOrder + 1):
            req.setFilterExpression('"StrahOrder" = %s' % i)
            for f in network.getFeatures(req):
                order = int(f['StrahOrder'])
                upstreamArcs = f['UpArcId'].split(',') if f['UpArcId'] else []
                if len(upstreamArcs) == 0:
                    ordersFrequency[i]['N'] += 1.0
                elif len(upstreamArcs) > 1:
                    ordersFrequency[order]['N'] += 1.0
                    for j in upstreamArcs:
                        f = network.getFeatures(QgsFeatureRequest().setFilterFid(int(j))).next()
                        upOrder = int(f['StrahOrder'])
                        diff = upOrder - order
                        if diff == 1:
                            ordersFrequency[upOrder]['Ndu'] += 1.0
                        if diff > 1:
                            ordersFrequency[upOrder]['Na'] += 1.0

        writerOrders = self.getOutputFromName(
            self.ORDER_FREQUENCY).getTableWriter(['order', 'N', 'NDU', 'NA'])

        writerBifrat = self.getOutputFromName(
            self.BIFURCATION_PARAMS).getTableWriter(['order', 'RBD', 'RB', 'RU'])

        # Calculate bifurcation parameters
        progress.setInfo(self.tr('Calculating bifurcation parameters...'))
        for k, v in ordersFrequency.iteritems():
            if k != maxOrder:
                bifRatios[k]['Rbu'] = ordersFrequency[k]['N'] / ordersFrequency[k + 1]['N']
                bifRatios[k]['Rbdu'] = ordersFrequency[k]['Ndu'] / ordersFrequency[k + 1]['N']
            else:
                bifRatios[k]['Rbu'] = 0.0
                bifRatios[k]['Rbdu'] = 0.0

            bifRatios[k]['Ru'] = bifRatios[k]['Rbu'] - bifRatios[k]['Rbdu']

            writerOrders.addRecord([k, v['N'], v['Ndu'], v['Na']])
            writerBifrat.addRecord([k, bifRatios[k]['Rbdu'], bifRatios[k]['Rbu'], bifRatios[k]['Ru']])

        del writerOrders
        del writerBifrat
Example #38
0
    canvas
)
bridge.setCanvasLayers()

# Get the layers in the project
layerList = p.mapLayersByName(parcelle_layer)
if not layerList:
    layers = p.mapLayers()
    for lname,layer in layers.items():
        print(lname+' '+layer.name()+' '+parcelle_layer)
    layerList = [ layer for lname,layer in layers.items() if layer.name() == parcelle_layer ]
layer = layerList[0]

# Get Feature
req = QgsFeatureRequest()
req.setFilterExpression(' "geo_parcelle" = \'%s\' ' % parcelle_id)
it = layer.getFeatures(req)
feat = None
for f in it:
    feat = f
    break

# Get connecion params
connectionParams = cadastre_common.getConnectionParameterFromDbLayer(layer)
connector = cadastre_common.getConnectorFromUri( connectionParams )

# Get compte communal
comptecommunal = cadastre_common.getCompteCommunalFromParcelleId(
    feat['geo_parcelle'],
    connectionParams,
    connector
Example #39
0
    def testSubsetStringFids(self):
        """
          - tests that feature ids are stable even if a subset string is set
          - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122)
        """

        tmpfile = os.path.join(self.basetestpath, 'subsetStringFids.sqlite')
        ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
        lyr.CreateField(ogr.FieldDefn('type', ogr.OFTInteger))
        lyr.CreateField(ogr.FieldDefn('value', ogr.OFTInteger))
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(0)
        f.SetField(0, 1)
        f.SetField(1, 11)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(1)
        f.SetField(0, 1)
        f.SetField(1, 12)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(2)
        f.SetField(0, 1)
        f.SetField(1, 13)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(3)
        f.SetField(0, 2)
        f.SetField(1, 14)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(4)
        f.SetField(0, 2)
        f.SetField(1, 15)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(5)
        f.SetField(0, 2)
        f.SetField(1, 16)
        lyr.CreateFeature(f)
        f = None
        ds = None

        vl = QgsVectorLayer(tmpfile + "|subset=type=2", 'test', 'ogr')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.fields().at(vl.fields().count() - 1).name() == "orig_ogc_fid")

        req = QgsFeatureRequest()
        req.setFilterExpression("value=16")
        it = vl.getFeatures(req)
        f = QgsFeature()
        self.assertTrue(it.nextFeature(f))
        self.assertTrue(f.id() == 5)

        # Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed
        req = QgsFeatureRequest()
        req.setSubsetOfAttributes([])
        it = vl.getFeatures(req)
        ids = []
        while it.nextFeature(f):
            ids.append(f.id())
        self.assertTrue(len(ids) == 3)
        self.assertTrue(3 in ids)
        self.assertTrue(4 in ids)
        self.assertTrue(5 in ids)

        # Check that subset string is correctly set on reload
        vl.reload()
        self.assertTrue(vl.fields().at(vl.fields().count() - 1).name() == "orig_ogc_fid")
Example #40
0
def polygonize(layer, callback=None):
    """Polygonize a raster layer into a vector layer using GDAL.

    Issue https://github.com/inasafe/inasafe/issues/3183

    :param layer: The layer to reproject.
    :type layer: QgsRasterLayer

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int) and 'maximum' (int). Defaults to
        None.
    :type callback: function

    :return: Reprojected memory layer.
    :rtype: QgsRasterLayer

    .. versionadded:: 4.0
    """
    output_layer_name = polygonize_steps['output_layer_name']
    processing_step = polygonize_steps['step_name']
    output_layer_name = output_layer_name % layer.keywords['layer_purpose']
    gdal_layer_name = polygonize_steps['gdal_layer_name']

    if layer.keywords.get('layer_purpose') == 'exposure':
        output_field = exposure_type_field
    else:
        output_field = hazard_value_field

    input_raster = gdal.Open(layer.source(), gdal.GA_ReadOnly)

    srs = osr.SpatialReference()
    srs.ImportFromWkt(input_raster.GetProjectionRef())

    temporary_dir = temp_dir(sub_dir='pre-process')
    out_shapefile = unique_filename(
        suffix='-%s.shp' % output_layer_name, dir=temporary_dir)

    driver = ogr.GetDriverByName("ESRI Shapefile")
    destination = driver.CreateDataSource(out_shapefile)

    output_layer = destination.CreateLayer(gdal_layer_name, srs)

    # We have no other way to use a shapefile. We need only the first 10 chars.
    field_name = output_field['field_name'][0:10]
    fd = ogr.FieldDefn(field_name, ogr.OFTInteger)
    output_layer.CreateField(fd)

    input_band = input_raster.GetRasterBand(1)
    # Fixme : add our own callback to Polygonize
    gdal.Polygonize(input_band, None, output_layer, 0, [], callback=None)
    destination.Destroy()

    vector_layer = QgsVectorLayer(out_shapefile, output_layer_name, 'ogr')

    # Let's remove polygons which were no data
    request = QgsFeatureRequest()
    expression = '"%s" = %s' % (field_name, no_data_value)
    request.setFilterExpression(expression)
    vector_layer.startEditing()
    for feature in vector_layer.getFeatures(request):
        vector_layer.deleteFeature(feature.id())
    vector_layer.commitChanges()

    # We transfer keywords to the output.
    vector_layer.keywords = layer.keywords.copy()
    vector_layer.keywords[
        layer_geometry['key']] = layer_geometry_polygon['key']

    vector_layer.keywords['title'] = output_layer_name
    # We just polygonized the raster layer. inasafe_fields do not exist.
    vector_layer.keywords['inasafe_fields'] = {
        output_field['key']: field_name
    }

    check_layer(vector_layer)
    return vector_layer
Example #41
0
def polygonize(layer):
    """Polygonize a raster layer into a vector layer using GDAL.

    Issue https://github.com/inasafe/inasafe/issues/3183

    :param layer: The layer to reproject.
    :type layer: QgsRasterLayer

    :return: Reprojected memory layer.
    :rtype: QgsRasterLayer

    .. versionadded:: 4.0
    """
    output_layer_name = polygonize_steps['output_layer_name']
    output_layer_name = output_layer_name % layer.keywords['layer_purpose']
    gdal_layer_name = polygonize_steps['gdal_layer_name']

    if layer.keywords.get('layer_purpose') == 'exposure':
        output_field = exposure_type_field
    else:
        output_field = hazard_value_field

    input_raster = gdal.Open(layer.source(), gdal.GA_ReadOnly)

    srs = osr.SpatialReference()
    srs.ImportFromWkt(input_raster.GetProjectionRef())

    temporary_dir = temp_dir(sub_dir='pre-process')
    out_shapefile = unique_filename(suffix='-%s.shp' % output_layer_name,
                                    dir=temporary_dir)

    driver = ogr.GetDriverByName("ESRI Shapefile")
    destination = driver.CreateDataSource(out_shapefile)

    output_layer = destination.CreateLayer(gdal_layer_name, srs)

    # We have no other way to use a shapefile. We need only the first 10 chars.
    field_name = output_field['field_name'][0:10]
    fd = ogr.FieldDefn(field_name, ogr.OFTInteger)
    output_layer.CreateField(fd)

    active_band = layer.keywords.get('active_band', 1)
    input_band = input_raster.GetRasterBand(active_band)
    # Fixme : add our own callback to Polygonize
    gdal.Polygonize(input_band, None, output_layer, 0, [], callback=None)
    destination.Destroy()

    vector_layer = QgsVectorLayer(out_shapefile, output_layer_name, 'ogr')

    # Let's remove polygons which were no data
    request = QgsFeatureRequest()
    expression = '"%s" = %s' % (field_name, no_data_value)
    request.setFilterExpression(expression)
    vector_layer.startEditing()
    for feature in vector_layer.getFeatures(request):
        vector_layer.deleteFeature(feature.id())
    vector_layer.commitChanges()

    # We transfer keywords to the output.
    vector_layer.keywords = layer.keywords.copy()
    vector_layer.keywords[
        layer_geometry['key']] = layer_geometry_polygon['key']

    vector_layer.keywords['title'] = output_layer_name
    # We just polygonized the raster layer. inasafe_fields do not exist.
    vector_layer.keywords['inasafe_fields'] = {output_field['key']: field_name}

    check_layer(vector_layer)
    return vector_layer
Example #42
0
    def runGetFeatureTests(self, provider):
        assert len([f for f in provider.getFeatures()]) == 5
        self.assert_query(provider, 'name ILIKE \'QGIS\'', [])
        self.assert_query(provider, '"name" IS NULL', [5])
        self.assert_query(provider, '"name" IS NOT NULL', [1, 2, 3, 4])
        self.assert_query(provider, '"name" NOT LIKE \'Ap%\'', [1, 3, 4])
        self.assert_query(provider, '"name" NOT ILIKE \'QGIS\'', [1, 2, 3, 4])
        self.assert_query(provider, '"name" NOT ILIKE \'pEAR\'', [1, 2, 4])
        self.assert_query(provider, 'name = \'Apple\'', [2])
        self.assert_query(provider, 'name <> \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'name = \'apple\'', [])
        self.assert_query(provider, '"name" <> \'apple\'', [1, 2, 3, 4])
        self.assert_query(provider, '(name = \'Apple\') is not null', [1, 2, 3, 4])
        self.assert_query(provider, 'name LIKE \'Apple\'', [2])
        self.assert_query(provider, 'name LIKE \'aPple\'', [])
        self.assert_query(provider, 'name ILIKE \'aPple\'', [2])
        self.assert_query(provider, 'name ILIKE \'%pp%\'', [2])
        self.assert_query(provider, 'cnt > 0', [1, 2, 3, 4])
        self.assert_query(provider, '-cnt > 0', [5])
        self.assert_query(provider, 'cnt < 0', [5])
        self.assert_query(provider, '-cnt < 0', [1, 2, 3, 4])
        self.assert_query(provider, 'cnt >= 100', [1, 2, 3, 4])
        self.assert_query(provider, 'cnt <= 100', [1, 5])
        self.assert_query(provider, 'pk IN (1, 2, 4, 8)', [1, 2, 4])
        self.assert_query(provider, 'cnt = 50 * 2', [1])
        self.assert_query(provider, 'cnt = 150 / 1.5', [1])
        self.assert_query(provider, 'cnt = 1000 / 10', [1])
        self.assert_query(provider, 'cnt = 1000/11+10', []) # checks that provider isn't rounding int/int
        self.assert_query(provider, 'pk = 9 // 4', [2]) # int division
        self.assert_query(provider, 'cnt = 99 + 1', [1])
        self.assert_query(provider, 'cnt = 101 - 1', [1])
        self.assert_query(provider, 'cnt - 1 = 99', [1])
        self.assert_query(provider, '-cnt - 1 = -101', [1])
        self.assert_query(provider, '-(-cnt) = 100', [1])
        self.assert_query(provider, '-(cnt) = -(100)', [1])
        self.assert_query(provider, 'cnt + 1 = 101', [1])
        self.assert_query(provider, 'cnt = 1100 % 1000', [1])
        self.assert_query(provider, '"name" || \' \' || "name" = \'Orange Orange\'', [1])
        self.assert_query(provider, '"name" || \' \' || "cnt" = \'Orange 100\'', [1])
        self.assert_query(provider, '\'x\' || "name" IS NOT NULL', [1, 2, 3, 4])
        self.assert_query(provider, '\'x\' || "name" IS NULL', [5])
        self.assert_query(provider, 'cnt = 10 ^ 2', [1])
        self.assert_query(provider, '"name" ~ \'[OP]ra[gne]+\'', [1])
        self.assert_query(provider, '"name"="name2"', [2, 4])  # mix of matched and non-matched case sensitive names
        self.assert_query(provider, 'true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'false', [])

        # Three value logic
        self.assert_query(provider, 'false and false', [])
        self.assert_query(provider, 'false and true', [])
        self.assert_query(provider, 'false and NULL', [])
        self.assert_query(provider, 'true and false', [])
        self.assert_query(provider, 'true and true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true and NULL', [])
        self.assert_query(provider, 'NULL and false', [])
        self.assert_query(provider, 'NULL and true', [])
        self.assert_query(provider, 'NULL and NULL', [])
        self.assert_query(provider, 'false or false', [])
        self.assert_query(provider, 'false or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'false or NULL', [])
        self.assert_query(provider, 'true or false', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true or NULL', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'NULL or false', [])
        self.assert_query(provider, 'NULL or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'NULL or NULL', [])
        self.assert_query(provider, 'not true', [])
        self.assert_query(provider, 'not false', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'not null', [])

        # not
        self.assert_query(provider, 'not name = \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'not name IS NULL', [1, 2, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' or name = \'Apple\'', [1, 2, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' or not name = \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' and pk = 4', [4])
        self.assert_query(provider, 'not name = \'Apple\' and not pk = 4', [1, 3])
        self.assert_query(provider, 'not pk IN (1, 2, 4, 8)', [3, 5])

        # type conversion - QGIS expressions do not mind that we are comparing a string
        # against numeric literals
        self.assert_query(provider, 'num_char IN (2, 4, 5)', [2, 4, 5])

        #function
        self.assert_query(provider, 'sqrt(pk) >= 2', [4, 5])
        self.assert_query(provider, 'radians(cnt) < 2', [1, 5])
        self.assert_query(provider, 'degrees(pk) <= 200', [1, 2, 3])
        self.assert_query(provider, 'abs(cnt) <= 200', [1, 2, 5])
        self.assert_query(provider, 'cos(pk) < 0', [2, 3, 4])
        self.assert_query(provider, 'sin(pk) < 0', [4, 5])
        self.assert_query(provider, 'tan(pk) < 0', [2, 3, 5])
        self.assert_query(provider, 'acos(-1) < pk', [4, 5])
        self.assert_query(provider, 'asin(1) < pk', [2, 3, 4, 5])
        self.assert_query(provider, 'atan(3.14) < pk', [2, 3, 4, 5])
        self.assert_query(provider, 'atan2(3.14, pk) < 1', [3, 4, 5])
        self.assert_query(provider, 'exp(pk) < 10', [1, 2])
        self.assert_query(provider, 'ln(pk) <= 1', [1, 2])
        self.assert_query(provider, 'log(3, pk) <= 1', [1, 2, 3])
        self.assert_query(provider, 'log10(pk) < 0.5', [1, 2, 3])
        self.assert_query(provider, 'round(3.14) <= pk', [3, 4, 5])
        self.assert_query(provider, 'round(0.314,1) * 10 = pk', [3])
        self.assert_query(provider, 'floor(3.14) <= pk', [3, 4, 5])
        self.assert_query(provider, 'ceil(3.14) <= pk', [4, 5])
        self.assert_query(provider, 'pk < pi()', [1, 2, 3])

        self.assert_query(provider, 'round(cnt / 66.67) <= 2', [1, 5])
        self.assert_query(provider, 'floor(cnt / 66.67) <= 2', [1, 2, 5])
        self.assert_query(provider, 'ceil(cnt / 66.67) <= 2', [1, 5])
        self.assert_query(provider, 'pk < pi() / 2', [1])
        self.assert_query(provider, 'pk = char(51)', [3])
        self.assert_query(provider, 'pk = coalesce(NULL,3,4)', [3])
        self.assert_query(provider, 'lower(name) = \'apple\'', [2])
        self.assert_query(provider, 'upper(name) = \'APPLE\'', [2])
        self.assert_query(provider, 'name = trim(\'   Apple   \')', [2])

        # geometry
        # azimuth and touches tests are deactivated because they do not pass for WFS provider
        #self.assert_query(provider, 'azimuth($geometry,geom_from_wkt( \'Point (-70 70)\')) < pi()', [1, 5])
        self.assert_query(provider, 'x($geometry) < -70', [1, 5])
        self.assert_query(provider, 'y($geometry) > 70', [2, 4, 5])
        self.assert_query(provider, 'xmin($geometry) < -70', [1, 5])
        self.assert_query(provider, 'ymin($geometry) > 70', [2, 4, 5])
        self.assert_query(provider, 'xmax($geometry) < -70', [1, 5])
        self.assert_query(provider, 'ymax($geometry) > 70', [2, 4, 5])
        self.assert_query(provider, 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', [4, 5])
        self.assert_query(provider, 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', [1, 2])
        #self.assert_query(provider, 'touches($geometry,geom_from_wkt( \'Polygon ((-70.332 66.33, -65.32 66.33, -65.32 78.3, -70.332 78.3, -70.332 66.33))\'))', [1, 4])
        self.assert_query(provider, 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)', [1, 2])
        self.assert_query(provider, 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', [4, 5])
        self.assert_query(provider, 'intersects($geometry,geom_from_gml( \'<gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon>\'))', [1, 2])

        # combination of an uncompilable expression and limit
        feature = next(self.vl.getFeatures('pk=4'))
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        scope.setVariable('parent', feature)
        context.appendScope(scope)

        request = QgsFeatureRequest()
        request.setExpressionContext(context)
        request.setFilterExpression('"pk" = attribute(@parent, \'pk\')')
        request.setLimit(1)

        values = [f['pk'] for f in self.vl.getFeatures(request)]
        self.assertEqual(values, [4])
def aggregation_summary(aggregate_hazard, aggregation, callback=None):
    """Compute the summary from the aggregate hazard to the analysis layer.

    Source layer :
    | haz_id | haz_class | aggr_id | aggr_name | total_feature |

    Target layer :
    | aggr_id | aggr_name |

    Output layer :
    | aggr_id | aggr_name | count of affected features per exposure type

    :param aggregate_hazard: The layer to aggregate vector layer.
    :type aggregate_hazard: QgsVectorLayer

    :param aggregation: The aggregation vector layer where to write statistics.
    :type aggregation: QgsVectorLayer

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int), 'maximum' (int) and 'step' (str).
        Defaults to None.
    :type callback: function

    :return: The new aggregation layer with summary.
    :rtype: QgsVectorLayer

    .. versionadded:: 4.0
    """
    output_layer_name = summary_2_aggregation_steps['output_layer_name']
    processing_step = summary_2_aggregation_steps['step_name']

    source_fields = aggregate_hazard.keywords['inasafe_fields']
    target_fields = aggregation.keywords['inasafe_fields']

    target_compulsory_fields = [
        aggregation_id_field,
        aggregation_name_field,
    ]
    check_inputs(target_compulsory_fields, target_fields)

    # Missing exposure_count_field
    source_compulsory_fields = [
        aggregation_id_field,
        aggregation_name_field,
        hazard_id_field,
        hazard_class_field,
        affected_field,
    ]
    check_inputs(source_compulsory_fields, source_fields)

    pattern = exposure_count_field['key']
    pattern = pattern.replace('%s', '')
    unique_exposure = read_dynamic_inasafe_field(
        source_fields, exposure_count_field)

    absolute_values = create_absolute_values_structure(
        aggregate_hazard, ['aggregation_id'])

    flat_table = FlatTable('aggregation_id', 'exposure_class')

    aggregation_index = source_fields[aggregation_id_field['key']]

    # We want to loop over affected features only.
    request = QgsFeatureRequest()
    request.setFlags(QgsFeatureRequest.NoGeometry)
    expression = '\"%s\" = \'%s\'' % (
        affected_field['field_name'], tr('True'))
    request.setFilterExpression(expression)
    for area in aggregate_hazard.getFeatures(request):

        for key, name_field in source_fields.iteritems():
            if key.endswith(pattern):
                aggregation_id = area[aggregation_index]
                exposure_class = key.replace(pattern, '')
                value = area[name_field]
                flat_table.add_value(
                    value,
                    aggregation_id=aggregation_id,
                    exposure_class=exposure_class
                )

        # We summarize every absolute values.
        for field, field_definition in absolute_values.iteritems():
            value = area[field]
            if not value or isinstance(value, QPyNullVariant):
                value = 0
            field_definition[0].add_value(
                value,
                aggregation_id=area[aggregation_index],
            )

    shift = aggregation.fields().count()

    aggregation.startEditing()

    add_fields(
        aggregation,
        absolute_values,
        [total_affected_field],
        unique_exposure,
        affected_exposure_count_field)

    aggregation_index = target_fields[aggregation_id_field['key']]

    request = QgsFeatureRequest()
    request.setFlags(QgsFeatureRequest.NoGeometry)
    for area in aggregation.getFeatures(request):
        aggregation_value = area[aggregation_index]
        total = 0
        for i, val in enumerate(unique_exposure):
            sum = flat_table.get_value(
                aggregation_id=aggregation_value,
                exposure_class=val
            )
            total += sum
            aggregation.changeAttributeValue(area.id(), shift + i, sum)

        aggregation.changeAttributeValue(
            area.id(), shift + len(unique_exposure), total)

        for i, field in enumerate(absolute_values.itervalues()):
            value = field[0].get_value(
                aggregation_id=aggregation_value,
            )
            target_index = shift + len(unique_exposure) + 1 + i
            aggregation.changeAttributeValue(
                area.id(), target_index, value)

    aggregation.commitChanges()

    aggregation.keywords['title'] = layer_purpose_aggregation_summary['name']
    if qgis_version() >= 21800:
        aggregation.setName(aggregation.keywords['title'])
    else:
        aggregation.setLayerName(aggregation.keywords['title'])
    aggregation.keywords['layer_purpose'] = (
        layer_purpose_aggregation_summary['key'])

    check_layer(aggregation)
    return aggregation
    def createPdf(self):
        '''
        Create a PDF from cadastre data
        '''
        params = self.request.parameterMap( )

        # Check if needed params are set
        if 'LAYER' not in params or 'PARCELLE' not in params or 'TYPE' not in params or 'MAP' not in params:
            body = {
                'status': 'fail',
                'message': 'Missing parameters: MAP, LAYER, PARCELLE, TYPE are required '
            }
            self.setJsonResponse( '200', body)
            return

        # Get layer and expression
        pmap = params['MAP']
        player = params['LAYER']
        pparcelle = params['PARCELLE']
        ptype = params['TYPE']

        # Check type
        if ptype.lower() not in ('parcelle', 'proprietaire'):
            QgsMessageLog.logMessage( "Cadastre - Parameter TYPE must be parcelle or proprietaire")
            body = {
                'status': 'fail',
                'message': 'Parameter TYPE must be parcelle or proprietaire'
            }
            self.setJsonResponse( '200', body)
            return

        # Open project
        self.projectPath = pmap
        pfile = QFileInfo( pmap )
        p = QgsProject.instance()
        p.read(pfile)

        # Find layer
        lr = QgsMapLayerRegistry.instance()
        layerList = [ layer for lname,layer in lr.mapLayers().items() if layer.name() == player ]
        if len(layerList ) != 1:
            QgsMessageLog.logMessage( "Cadastre - layer %s not in project" % player)
            body = {
                'status': 'fail',
                'message': 'The source layer cannot be found in the project'
            }
            self.setJsonResponse( '200', body)
            return
        layer = layerList[0]

        # Get feature
        import re
        pattern = re.compile("^([A-Z0-9]+)*$")
        if not pattern.match(pparcelle):
            QgsMessageLog.logMessage( "Cadastre - PARCELLE has not the correct format")
            body = {
                'status': 'fail',
                'message': 'PARCELLE has not the correct format'
            }
            self.setJsonResponse('200', body)
            return

        if self.debugMode:
            QgsMessageLog.logMessage( "cadastre debug - layer = %s  - geo_parcelle = %s" % ( layer.name(), pparcelle ))

        req = QgsFeatureRequest()
        req.setFilterExpression(' "geo_parcelle" = \'%s\' ' % pparcelle)

        it = layer.getFeatures(req)
        feat = None
        for f in it:
            feat = f
            break
        if not feat:
            QgsMessageLog.logMessage( "CADASTRE - No feature found for layer %s and parcelle %s" % (player, pparcelle))
            body = {
                'status': 'fail',
                'message': 'No feature found for layer %s and parcelle %s' % (player, pparcelle)
            }
            self.setJsonResponse('200', body)
            return

        if self.debugMode:
            QgsMessageLog.logMessage( "cadastre debug - feature geo_parcelle = %s" % feat['geo_parcelle'])


        # Get layer connection parameters
        self.connectionParams = cadastre_common.getConnectionParameterFromDbLayer(layer)
        if self.debugMode:
            QgsMessageLog.logMessage( "cadastre debug - connection params = %s" % self.connectionParams )

        self.connector = cadastre_common.getConnectorFromUri( self.connectionParams )
        if self.debugMode:
            QgsMessageLog.logMessage( "cadastre debug - after getting connector" )

        # Get compte communal
        comptecommunal = cadastre_common.getCompteCommunalFromParcelleId(
            feat['geo_parcelle'],
            self.connectionParams,
            self.connector
        )
        pmulti = 1
        if ptype == 'proprietaire' and pmulti == 1:
            comptecommunal = cadastre_common.getProprietaireComptesCommunaux(
                comptecommunal,
                self.connectionParams,
                self.connector
            )
        if self.debugMode:
            QgsMessageLog.logMessage( "cadastre debug - comptecommunal = %s" % comptecommunal )

        # Export PDF
        qex = cadastreExport(
            layer,
            ptype,
            comptecommunal,
            feat['geo_parcelle']
        )
        if self.debugMode:
            QgsMessageLog.logMessage( "cadastre debug - after instanciating cadastreExport" )

        paths = qex.exportAsPDF()
        if self.debugMode:
            QgsMessageLog.logMessage( "cadastre debug - after exportAsPDF(), path: %s" % paths )

        if paths:
            tokens = []
            for path in paths:
                uid = uuid4()

                if self.debugMode:
                    QgsMessageLog.logMessage( "cadastre debug - item path: %s" % path )
                newpath = os.path.join(
                    tempfile.gettempdir(),
                    '%s.pdf' % uid
                )
                if self.debugMode:
                    QgsMessageLog.logMessage( "cadastre debug - item newpath: %s" % newpath )
                os.rename(path,newpath)
                tokens.append( str(uid) )

            body = {
                'status': 'success',
                'message': 'PDF generated',
                'data': {
                    'url': {
                        'request': 'getPdf',
                        'service': 'cadastre',
                        'token': None
                    },
                    'tokens': tokens
                }
            }

            self.setJsonResponse( '200', body)
            return
        else:
            QgsMessageLog.logMessage( "CADASTRE - Error during export: no PDF output")
            body = {
                'status': 'fail',
                'message': 'An error occured while generating the PDF'
            }
            self.setJsonResponse( '200', body)
            return
        def run_checks():
            self.assertEqual([f.name() for f in vl.fields()], ['fid', 'type', 'value'])

            # expression
            req = QgsFeatureRequest()
            req.setFilterExpression("value=16")
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter fid
            req = QgsFeatureRequest()
            req.setFilterFid(5)
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter fids
            req = QgsFeatureRequest()
            req.setFilterFids([5])
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # check with subset of attributes
            req = QgsFeatureRequest()
            req.setFilterFids([5])
            req.setSubsetOfAttributes([2])
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes()[2], 16)
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter rect and expression
            req = QgsFeatureRequest()
            req.setFilterExpression("value=16 or value=14")
            req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5))
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter rect and fids
            req = QgsFeatureRequest()
            req.setFilterFids([3, 5])
            req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5))
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed
            req = QgsFeatureRequest()
            req.setSubsetOfAttributes([])
            it = vl.getFeatures(req)
            ids = []
            geoms = {}
            while it.nextFeature(f):
                ids.append(f.id())
                geoms[f.id()] = f.geometry().asWkt()
            self.assertCountEqual(ids, [3, 4, 5])
            self.assertEqual(geoms, {3: 'Point (3 3)', 4: 'Point (4 4)', 5: 'Point (5 5)'})
def assign_cost_to_cells(network_graph, source, destination, id_field):
    """Assign the nearest destination point from the source layer.

    :param network_graph: The network graph.
    :type network_graph: Graph

    :param source: Grid as a polygon vector layer
    :type source: QgsVectorLayer

    :param destination: The destination point layer.
    :type destination: QgsVectorLayer

    :param id_field: The ID field in the destination layer.
    :type id_field: basestring
    """
    spatial_index = create_spatial_index(destination)
    destination_features = {}
    for feature in destination.getFeatures():
        destination_features[feature.id()] = feature
    index_id_field = destination.fieldNameIndex(id_field)

    fields = [QgsField('distance', QVariant.Int)]
    routes = create_memory_layer(
        'routes', QGis.Line, destination.crs(), fields)
    routes.startEditing()

    source.startEditing()
    source.addAttribute(
        QgsField('destination_id', QVariant.Int, len=5, prec=0))
    dest_id_field = source.fieldNameIndex('destination_id')
    source.addAttribute(QgsField('distance', QVariant.Int, len=5, prec=0))
    distance_field = source.fieldNameIndex('distance')
    source.commitChanges()

    request = QgsFeatureRequest()
    request.setFilterExpression('"has_road" = \'true\'')
    # request.setLimit(20)  # Hack for now to speedup development
    i = 0
    for source_cell in source.getFeatures(request):
        source_geometry_point = source_cell.geometry().centroid().asPoint()
        desination_id = source_cell['destination_id']
        if desination_id is None or isinstance(desination_id, QPyNullVariant):
            source.startEditing()
            nearest_health_points = spatial_index.nearestNeighbor(
                source_geometry_point, 5)
            minimum_distance = None
            minimal_geom = None
            for health_point in nearest_health_points:
                try:
                    i += 1
                    p = destination_features[health_point].geometry().asPoint()
                    geom, distance, _ = network_graph.route(
                        source_geometry_point, p)
                except:
                    distance = -1

                if minimum_distance is None or (
                                minimum_distance > distance >= 0):
                    minimal_geom = geom
                    minimum_distance = distance

            if minimum_distance:
                feature = QgsFeature()
                feature.setGeometry(minimal_geom)
                feature.setAttributes([minimum_distance])
                routes.addFeatures([feature])

                index_id = destination_features[health_point][index_id_field]
                destination_value = index_id
            else:
                destination_value = '-1'
                minimum_distance = '-1'

            source.changeAttributeValue(
                source_cell.id(), dest_id_field, destination_value)
            source.changeAttributeValue(
                source_cell.id(), distance_field, minimum_distance)
            intersecting_blocks(minimal_geom, destination_value, grid)
            source.commitChanges()

        else:
            print 'speedup'
            geom, distance, _ = network_graph.route(
                source_geometry_point,
                destination_features[desination_id].geometry().asPoint())

    source.commitChanges()
    # source.commitErrors()
    routes.commitChanges()
    print 'Call : %s' % i
    return routes, source
Example #47
0
def featureRequest(expr):
    request = QgsFeatureRequest()
    request.setFilterExpression(expr)
    return request
Example #48
0
    def processAlgorithm(self, progress):
        network = dataobjects.getObjectFromUri(
            self.getParameterValue(self.NETWORK_LAYER))

        # Ensure that Strahler orders assigned
        idxStrahler= findField(network, 'StrahOrder')
        if idxStrahler == -1:
            raise GeoAlgorithmExecutionException(
                self.tr('Seems Strahler orders is not assigned. '
                        'Please run corresponding tool and try again.'))

        # Generate helper dictionaries
        myNetwork, arcsPerNodeId = makeHelperDictionaries(network)

        # Calculate order frequency
        progress.setInfo(self.tr('Calculating order frequency...'))

        maxOrder = int(network.maximumValue(idxStrahler))
        ordersFrequency = dict()
        bifRatios = dict()

        # Initialize dictionaries
        for i in xrange(1, maxOrder + 1):
            ordersFrequency[i] = dict(N=0.0, Ndu=0.0, Na=0.0)
            bifRatios[i] = dict(Rbu=0.0, Rbdu=0.0, Ru=0.0)

        req = QgsFeatureRequest()
        for i in xrange(1, maxOrder + 1):
            req.setFilterExpression('"StrahOrder" = %s' % i)
            for f in network.getFeatures(req):
                order = int(f['StrahOrder'])
                upstreamArcs = f['UpArcId'].split(',') if f['UpArcId'] else []
                if len(upstreamArcs) == 0:
                    ordersFrequency[i]['N'] += 1.0
                elif len(upstreamArcs) > 1:
                    ordersFrequency[order]['N'] += 1.0
                    for j in upstreamArcs:
                        f = network.getFeatures(QgsFeatureRequest().setFilterFid(int(j))).next()
                        upOrder = int(f['StrahOrder'])
                        diff = upOrder - order
                        if diff == 1:
                            ordersFrequency[upOrder]['Ndu'] += 1.0
                        if diff > 1:
                            ordersFrequency[upOrder]['Na'] += 1.0

        writerOrders = self.getOutputFromName(
            self.ORDER_FREQUENCY).getTableWriter(['order', 'N', 'NDU', 'NA'])

        writerBifrat = self.getOutputFromName(
            self.BIFURCATION_PARAMS).getTableWriter(['order', 'RBD', 'RB', 'RU'])

        # Calculate bifurcation parameters
        progress.setInfo(self.tr('Calculating bifurcation parameters...'))
        for k, v in ordersFrequency.iteritems():
            if k != maxOrder:
                bifRatios[k]['Rbu'] = ordersFrequency[k]['N'] / ordersFrequency[k + 1]['N']
                bifRatios[k]['Rbdu'] = ordersFrequency[k]['Ndu'] / ordersFrequency[k + 1]['N']
            else:
                bifRatios[k]['Rbu'] = 0.0
                bifRatios[k]['Rbdu'] = 0.0

            bifRatios[k]['Ru'] = bifRatios[k]['Rbu'] - bifRatios[k]['Rbdu']

            writerOrders.addRecord([k, v['N'], v['Ndu'], v['Na']])
            writerBifrat.addRecord([k, bifRatios[k]['Rbdu'], bifRatios[k]['Rbu'], bifRatios[k]['Ru']])

        del writerOrders
        del writerBifrat
Example #49
0
    def __load_feature(self, feature):
        # FIXME this code too similar to main_dialog.load_plots
        # FIXME find a way to factor

        feature_id = feature[self.__config["id_column"]]
        feature_name = feature[self.__config["name_column"]]

        for item in self.__list.selectedItems():
            # now add the selected configuration
            cfg = item.data(Qt.UserRole)
            if cfg["type"] in ("cumulative", "instantaneous", "continuous"):
                layerid = cfg["source"]
                data_l = QgsProject.instance().mapLayers()[layerid]
                req = QgsFeatureRequest()
                filter_expr = "{}='{}'".format(cfg["feature_ref_column"],
                                               feature_id)
                req.setFilterExpression(filter_expr)

                title = cfg["name"]

                if cfg.get_filter_value():
                    filter_expr += " and {}='{}'".format(
                        cfg["feature_filter_column"], cfg.get_filter_value())

                    title = cfg.get_filter_value()
                else:
                    title = cfg["name"]

                f = None
                # test if the layer actually contains data
                for f in data_l.getFeatures(req):
                    break
                if f is None:
                    return
                if cfg["type"] == "instantaneous":
                    uom = cfg.get_uom()
                    data = LayerData(data_l,
                                     cfg["event_column"],
                                     cfg["value_column"],
                                     filter_expression=filter_expr,
                                     uom=uom)
                    uom = data.uom()
                    self.__viewer.add_data_cell(data,
                                                title,
                                                uom,
                                                station_name=feature_name,
                                                config=cfg)
                    self.__viewer.add_scale()
                if cfg["type"] == "continuous":
                    uom = cfg.get_uom()
                    fids = [f.id() for f in data_l.getFeatures(req)]
                    data = FeatureData(
                        data_l,
                        cfg["values_column"],
                        feature_ids=fids,
                        x_start_fieldname=cfg["start_measure_column"],
                        x_delta_fieldname=cfg["interval_column"])
                    self.__viewer.add_data_cell(data,
                                                title,
                                                uom,
                                                station_name=feature_name,
                                                config=cfg)
                elif cfg["type"] == "cumulative":
                    self.__viewer.add_histogram(
                        data_l,
                        filter_expression=filter_expr,
                        column_mapping={
                            f: cfg[f]
                            for f in ("min_event_column", "max_event_column",
                                      "value_column")
                        },
                        title=title,
                        config=cfg,
                        station_name=feature_name)

            elif cfg["type"] == "image":
                self.__viewer.add_imagery_from_db(cfg, feature_id)

        QDialog.accept(self)
Example #50
0
    def runGetFeatureTests(self, provider):
        assert len([f for f in provider.getFeatures()]) == 5
        self.assert_query(provider, 'name ILIKE \'QGIS\'', [])
        self.assert_query(provider, '"name" IS NULL', [5])
        self.assert_query(provider, '"name" IS NOT NULL', [1, 2, 3, 4])
        self.assert_query(provider, '"name" NOT LIKE \'Ap%\'', [1, 3, 4])
        self.assert_query(provider, '"name" NOT ILIKE \'QGIS\'', [1, 2, 3, 4])
        self.assert_query(provider, '"name" NOT ILIKE \'pEAR\'', [1, 2, 4])
        self.assert_query(provider, 'name = \'Apple\'', [2])
        self.assert_query(provider, 'name <> \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'name = \'apple\'', [])
        self.assert_query(provider, '"name" <> \'apple\'', [1, 2, 3, 4])
        self.assert_query(provider, '(name = \'Apple\') is not null', [1, 2, 3, 4])
        self.assert_query(provider, 'name LIKE \'Apple\'', [2])
        self.assert_query(provider, 'name LIKE \'aPple\'', [])
        self.assert_query(provider, 'name ILIKE \'aPple\'', [2])
        self.assert_query(provider, 'name ILIKE \'%pp%\'', [2])
        self.assert_query(provider, 'cnt > 0', [1, 2, 3, 4])
        self.assert_query(provider, '-cnt > 0', [5])
        self.assert_query(provider, 'cnt < 0', [5])
        self.assert_query(provider, '-cnt < 0', [1, 2, 3, 4])
        self.assert_query(provider, 'cnt >= 100', [1, 2, 3, 4])
        self.assert_query(provider, 'cnt <= 100', [1, 5])
        self.assert_query(provider, 'pk IN (1, 2, 4, 8)', [1, 2, 4])
        self.assert_query(provider, 'cnt = 50 * 2', [1])
        self.assert_query(provider, 'cnt = 99 + 1', [1])
        self.assert_query(provider, 'cnt = 101 - 1', [1])
        self.assert_query(provider, 'cnt - 1 = 99', [1])
        self.assert_query(provider, '-cnt - 1 = -101', [1])
        self.assert_query(provider, '-(-cnt) = 100', [1])
        self.assert_query(provider, '-(cnt) = -(100)', [1])
        self.assert_query(provider, 'cnt + 1 = 101', [1])
        self.assert_query(provider, 'cnt = 1100 % 1000', [1])
        self.assert_query(provider, '"name" || \' \' || "name" = \'Orange Orange\'', [1])
        self.assert_query(provider, '"name" || \' \' || "cnt" = \'Orange 100\'', [1])
        self.assert_query(provider, '\'x\' || "name" IS NOT NULL', [1, 2, 3, 4])
        self.assert_query(provider, '\'x\' || "name" IS NULL', [5])
        self.assert_query(provider, 'cnt = 10 ^ 2', [1])
        self.assert_query(provider, '"name" ~ \'[OP]ra[gne]+\'', [1])
        self.assert_query(provider, '"name"="name2"', [2, 4])  # mix of matched and non-matched case sensitive names
        self.assert_query(provider, 'true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'false', [])

        # Three value logic
        self.assert_query(provider, 'false and false', [])
        self.assert_query(provider, 'false and true', [])
        self.assert_query(provider, 'false and NULL', [])
        self.assert_query(provider, 'true and false', [])
        self.assert_query(provider, 'true and true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true and NULL', [])
        self.assert_query(provider, 'NULL and false', [])
        self.assert_query(provider, 'NULL and true', [])
        self.assert_query(provider, 'NULL and NULL', [])
        self.assert_query(provider, 'false or false', [])
        self.assert_query(provider, 'false or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'false or NULL', [])
        self.assert_query(provider, 'true or false', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true or NULL', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'NULL or false', [])
        self.assert_query(provider, 'NULL or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'NULL or NULL', [])
        self.assert_query(provider, 'not true', [])
        self.assert_query(provider, 'not false', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'not null', [])

        # not
        self.assert_query(provider, 'not name = \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'not name IS NULL', [1, 2, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' or name = \'Apple\'', [1, 2, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' or not name = \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' and pk = 4', [4])
        self.assert_query(provider, 'not name = \'Apple\' and not pk = 4', [1, 3])
        self.assert_query(provider, 'not pk IN (1, 2, 4, 8)', [3, 5])

        # type conversion - QGIS expressions do not mind that we are comparing a string
        # against numeric literals
        self.assert_query(provider, 'num_char IN (2, 4, 5)', [2, 4, 5])

        # geometry
        self.assert_query(provider, 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', [1, 2])

        # combination of an uncompilable expression and limit
        feature = next(self.vl.getFeatures('pk=4'))
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        scope.setVariable('parent', feature)
        context.appendScope(scope)

        request = QgsFeatureRequest()
        request.setExpressionContext(context)
        request.setFilterExpression('"pk" = attribute(@parent, \'pk\')')
        request.setLimit(1)

        values = [f['pk'] for f in self.vl.getFeatures(request)]
        self.assertEqual(values, [4])
Example #51
0
    def processAlgorithm(self, parameters, context, feedback):
        if parameters[self.SPOKES] == parameters[self.HUBS]:
            raise QgsProcessingException(
                self.tr('Same layer given for both hubs and spokes'))

        hub_source = self.parameterAsSource(parameters, self.HUBS, context)
        spoke_source = self.parameterAsSource(parameters, self.SPOKES, context)
        field_hub = self.parameterAsString(parameters, self.HUB_FIELD, context)
        field_hub_index = hub_source.fields().lookupField(field_hub)
        field_spoke = self.parameterAsString(parameters, self.SPOKE_FIELD,
                                             context)
        field_spoke_index = hub_source.fields().lookupField(field_spoke)

        fields = vector.combineFields(hub_source.fields(),
                                      spoke_source.fields())

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               QgsWkbTypes.LineString,
                                               hub_source.sourceCrs())

        hubs = hub_source.getFeatures()
        total = 100.0 / hub_source.featureCount() if hub_source.featureCount(
        ) else 0

        matching_field_types = hub_source.fields().at(field_hub_index).type(
        ) == spoke_source.fields().at(field_spoke_index).type()

        for current, hub_point in enumerate(hubs):
            if feedback.isCanceled():
                break

            if not hub_point.hasGeometry():
                continue

            p = hub_point.geometry().boundingBox().center()
            hub_x = p.x()
            hub_y = p.y()
            hub_id = str(hub_point[field_hub])
            hub_attributes = hub_point.attributes()

            request = QgsFeatureRequest().setDestinationCrs(
                hub_source.sourceCrs())
            if matching_field_types:
                request.setFilterExpression(
                    QgsExpression.createFieldEqualityExpression(
                        field_spoke, hub_attributes[field_hub_index]))

            spokes = spoke_source.getFeatures()
            for spoke_point in spokes:
                if feedback.isCanceled():
                    break

                spoke_id = str(spoke_point[field_spoke])
                if hub_id == spoke_id:
                    p = spoke_point.geometry().boundingBox().center()
                    spoke_x = p.x()
                    spoke_y = p.y()

                    f = QgsFeature()
                    f.setAttributes(hub_attributes + spoke_point.attributes())
                    f.setGeometry(
                        QgsGeometry.fromPolyline([
                            QgsPointXY(hub_x, hub_y),
                            QgsPointXY(spoke_x, spoke_y)
                        ]))
                    sink.addFeature(f, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Example #52
0
def zonal_stats(raster, vector):
    """Reclassify a continuous raster layer.

    Issue https://github.com/inasafe/inasafe/issues/3190

    The algorithm will take care about projections.
    We don't want to reproject the raster layer.
    So if CRS are different, we reproject the vector layer and then we do a
    lookup from the reprojected layer to the original vector layer.

    :param raster: The raster layer.
    :type raster: QgsRasterLayer

    :param vector: The vector layer.
    :type vector: QgsVectorLayer

    :return: The output of the zonal stats.
    :rtype: QgsVectorLayer

    .. versionadded:: 4.0
    """
    output_layer_name = zonal_stats_steps['output_layer_name']

    exposure = raster.keywords['exposure']
    if raster.crs().authid() != vector.crs().authid():
        layer = reproject(vector, raster.crs())

        # We prepare the copy
        output_layer = create_memory_layer(
            output_layer_name,
            vector.geometryType(),
            vector.crs(),
            vector.fields()
        )
        copy_layer(vector, output_layer)
    else:
        layer = create_memory_layer(
            output_layer_name,
            vector.geometryType(),
            vector.crs(),
            vector.fields()
        )
        copy_layer(vector, layer)

    input_band = layer.keywords.get('active_band', 1)
    analysis = QgsZonalStatistics(
        layer,
        raster,
        'exposure_',
        input_band,
        QgsZonalStatistics.Sum)
    result = analysis.calculateStatistics(None)
    LOGGER.debug(tr('Zonal stats on %s : %s' % (raster.source(), result)))

    output_field = exposure_count_field['field_name'] % exposure
    if raster.crs().authid() != vector.crs().authid():
        output_layer.startEditing()
        field = create_field_from_definition(
            exposure_count_field, exposure)

        output_layer.addAttribute(field)
        new_index = output_layer.fields().lookupField(field.name())
        old_index = layer.fields().lookupField('exposure_sum')
        for feature_input, feature_output in zip(
                layer.getFeatures(), output_layer.getFeatures()):
            output_layer.changeAttributeValue(
                feature_input.id(), new_index, feature_input[old_index])
        output_layer.commitChanges()
        layer = output_layer
    else:
        fields_to_rename = {
            'exposure_sum': output_field
        }
        if qgis_version() >= 21600:
            rename_fields(layer, fields_to_rename)
        else:
            copy_fields(layer, fields_to_rename)
            remove_fields(layer, list(fields_to_rename.keys()))
        layer.commitChanges()

    # The zonal stats is producing some None values. We need to fill these
    # with 0. See issue : #3778
    # We should start a new editing session as previous fields need to be
    # committed first.
    layer.startEditing()
    request = QgsFeatureRequest()
    expression = '\"%s\" is None' % output_field
    request.setFilterExpression(expression)
    request.setFlags(QgsFeatureRequest.NoGeometry)
    index = layer.fields().lookupField(output_field)
    for feature in layer.getFeatures():
        if feature[output_field] is None:
            layer.changeAttributeValue(feature.id(), index, 0)
    layer.commitChanges()

    layer.keywords = raster.keywords.copy()
    layer.keywords['inasafe_fields'] = vector.keywords['inasafe_fields'].copy()
    layer.keywords['inasafe_default_values'] = (
        raster.keywords['inasafe_default_values'].copy())

    key = exposure_count_field['key'] % raster.keywords['exposure']

    # Special case here, one field is the exposure count and the total.
    layer.keywords['inasafe_fields'][key] = output_field
    layer.keywords['inasafe_fields'][total_field['key']] = output_field

    layer.keywords['exposure_keywords'] = raster.keywords.copy()
    layer.keywords['hazard_keywords'] = vector.keywords[
        'hazard_keywords'].copy()
    layer.keywords['aggregation_keywords'] = (
        vector.keywords['aggregation_keywords'])
    layer.keywords['layer_purpose'] = (
        layer_purpose_aggregate_hazard_impacted['key'])

    layer.keywords['title'] = output_layer_name

    check_layer(layer)
    return layer
Example #53
0
def zonal_stats(raster, vector):
    """Reclassify a continuous raster layer.

    Issue https://github.com/inasafe/inasafe/issues/3190

    The algorithm will take care about projections.
    We don't want to reproject the raster layer.
    So if CRS are different, we reproject the vector layer and then we do a
    lookup from the reprojected layer to the original vector layer.

    :param raster: The raster layer.
    :type raster: QgsRasterLayer

    :param vector: The vector layer.
    :type vector: QgsVectorLayer

    :return: The output of the zonal stats.
    :rtype: QgsVectorLayer

    .. versionadded:: 4.0
    """
    output_layer_name = zonal_stats_steps['output_layer_name']

    exposure = raster.keywords['exposure']
    if raster.crs().authid() != vector.crs().authid():
        layer = reproject(vector, raster.crs())

        # We prepare the copy
        output_layer = create_memory_layer(
            output_layer_name,
            vector.geometryType(),
            vector.crs(),
            vector.fields()
        )
        copy_layer(vector, output_layer)
    else:
        layer = create_memory_layer(
            output_layer_name,
            vector.geometryType(),
            vector.crs(),
            vector.fields()
        )
        copy_layer(vector, layer)

    input_band = layer.keywords.get('active_band', 1)
    analysis = QgsZonalStatistics(
        layer,
        raster,
        'exposure_',
        input_band,
        QgsZonalStatistics.Sum)
    result = analysis.calculateStatistics(None)
    LOGGER.debug(tr('Zonal stats on %s : %s' % (raster.source(), result)))

    output_field = exposure_count_field['field_name'] % exposure
    if raster.crs().authid() != vector.crs().authid():
        output_layer.startEditing()
        field = create_field_from_definition(
            exposure_count_field, exposure)

        output_layer.addAttribute(field)
        new_index = output_layer.fields().lookupField(field.name())
        old_index = layer.fields().lookupField('exposure_sum')
        for feature_input, feature_output in zip(
                layer.getFeatures(), output_layer.getFeatures()):
            output_layer.changeAttributeValue(
                feature_input.id(), new_index, feature_input[old_index])
        output_layer.commitChanges()
        layer = output_layer
    else:
        fields_to_rename = {
            'exposure_sum': output_field
        }
        if qgis_version() >= 21600:
            rename_fields(layer, fields_to_rename)
        else:
            copy_fields(layer, fields_to_rename)
            remove_fields(layer, list(fields_to_rename.keys()))
        layer.commitChanges()

    # The zonal stats is producing some None values. We need to fill these
    # with 0. See issue : #3778
    # We should start a new editing session as previous fields need to be
    # committed first.
    layer.startEditing()
    request = QgsFeatureRequest()
    expression = '\"%s\" is None' % output_field
    request.setFilterExpression(expression)
    request.setFlags(QgsFeatureRequest.NoGeometry)
    index = layer.fields().lookupField(output_field)
    for feature in layer.getFeatures():
        if feature[output_field] is None:
            layer.changeAttributeValue(feature.id(), index, 0)
    layer.commitChanges()

    layer.keywords = raster.keywords.copy()
    layer.keywords['inasafe_fields'] = vector.keywords['inasafe_fields'].copy()
    layer.keywords['inasafe_default_values'] = (
        raster.keywords['inasafe_default_values'].copy())

    key = exposure_count_field['key'] % raster.keywords['exposure']

    # Special case here, one field is the exposure count and the total.
    layer.keywords['inasafe_fields'][key] = output_field
    layer.keywords['inasafe_fields'][total_field['key']] = output_field

    layer.keywords['exposure_keywords'] = raster.keywords.copy()
    layer.keywords['hazard_keywords'] = vector.keywords[
        'hazard_keywords'].copy()
    layer.keywords['aggregation_keywords'] = (
        vector.keywords['aggregation_keywords'])
    layer.keywords['layer_purpose'] = (
        layer_purpose_aggregate_hazard_impacted['key'])

    layer.keywords['title'] = output_layer_name

    check_layer(layer)
    return layer
Example #54
0
def aggregation_summary(aggregate_hazard, aggregation, callback=None):
    """Compute the summary from the aggregate hazard to the analysis layer.

    Source layer :
    | haz_id | haz_class | aggr_id | aggr_name | total_feature |

    Target layer :
    | aggr_id | aggr_name |

    Output layer :
    | aggr_id | aggr_name | count of affected features per exposure type

    :param aggregate_hazard: The layer to aggregate vector layer.
    :type aggregate_hazard: QgsVectorLayer

    :param aggregation: The aggregation vector layer where to write statistics.
    :type aggregation: QgsVectorLayer

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int), 'maximum' (int) and 'step' (str).
        Defaults to None.
    :type callback: function

    :return: The new aggregation layer with summary.
    :rtype: QgsVectorLayer

    .. versionadded:: 4.0
    """
    output_layer_name = summary_2_aggregation_steps['output_layer_name']
    processing_step = summary_2_aggregation_steps['step_name']

    source_fields = aggregate_hazard.keywords['inasafe_fields']
    target_fields = aggregation.keywords['inasafe_fields']

    target_compulsory_fields = [
        aggregation_id_field,
        aggregation_name_field,
    ]
    check_inputs(target_compulsory_fields, target_fields)

    # Missing exposure_count_field
    source_compulsory_fields = [
        aggregation_id_field,
        aggregation_name_field,
        hazard_id_field,
        hazard_class_field,
        affected_field,
    ]
    check_inputs(source_compulsory_fields, source_fields)

    pattern = exposure_count_field['key']
    pattern = pattern.replace('%s', '')
    unique_exposure = read_dynamic_inasafe_field(source_fields,
                                                 exposure_count_field)

    absolute_values = create_absolute_values_structure(aggregate_hazard,
                                                       ['aggregation_id'])

    flat_table = FlatTable('aggregation_id', 'exposure_class')

    aggregation_index = source_fields[aggregation_id_field['key']]

    # We want to loop over affected features only.
    request = QgsFeatureRequest()
    request.setFlags(QgsFeatureRequest.NoGeometry)
    expression = '\"%s\" = \'%s\'' % (affected_field['field_name'], tr('True'))
    request.setFilterExpression(expression)
    for area in aggregate_hazard.getFeatures(request):

        for key, name_field in source_fields.iteritems():
            if key.endswith(pattern):
                aggregation_id = area[aggregation_index]
                exposure_class = key.replace(pattern, '')
                value = area[name_field]
                flat_table.add_value(value,
                                     aggregation_id=aggregation_id,
                                     exposure_class=exposure_class)

        # We summarize every absolute values.
        for field, field_definition in absolute_values.iteritems():
            value = area[field]
            if not value or isinstance(value, QPyNullVariant):
                value = 0
            field_definition[0].add_value(
                value,
                aggregation_id=area[aggregation_index],
            )

    shift = aggregation.fields().count()

    aggregation.startEditing()

    add_fields(aggregation, absolute_values, [total_affected_field],
               unique_exposure, affected_exposure_count_field)

    aggregation_index = target_fields[aggregation_id_field['key']]

    request = QgsFeatureRequest()
    request.setFlags(QgsFeatureRequest.NoGeometry)
    for area in aggregation.getFeatures(request):
        aggregation_value = area[aggregation_index]
        total = 0
        for i, val in enumerate(unique_exposure):
            sum = flat_table.get_value(aggregation_id=aggregation_value,
                                       exposure_class=val)
            total += sum
            aggregation.changeAttributeValue(area.id(), shift + i, sum)

        aggregation.changeAttributeValue(area.id(),
                                         shift + len(unique_exposure), total)

        for i, field in enumerate(absolute_values.itervalues()):
            value = field[0].get_value(aggregation_id=aggregation_value, )
            target_index = shift + len(unique_exposure) + 1 + i
            aggregation.changeAttributeValue(area.id(), target_index, value)

    aggregation.commitChanges()

    aggregation.keywords['title'] = layer_purpose_aggregation_summary['name']
    if qgis_version() >= 21800:
        aggregation.setName(aggregation.keywords['title'])
    else:
        aggregation.setLayerName(aggregation.keywords['title'])
    aggregation.keywords['layer_purpose'] = (
        layer_purpose_aggregation_summary['key'])

    check_layer(aggregation)
    return aggregation
Example #55
0
    def testSubsetStringFids(self):
        """
          - tests that feature ids are stable even if a subset string is set
          - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122)
        """

        tmpfile = os.path.join(self.basetestpath, 'subsetStringFids.sqlite')
        ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test',
                             geom_type=ogr.wkbPoint,
                             options=['FID=fid'])
        lyr.CreateField(ogr.FieldDefn('type', ogr.OFTInteger))
        lyr.CreateField(ogr.FieldDefn('value', ogr.OFTInteger))
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(0)
        f.SetField(0, 1)
        f.SetField(1, 11)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(1)
        f.SetField(0, 1)
        f.SetField(1, 12)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(2)
        f.SetField(0, 1)
        f.SetField(1, 13)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(3)
        f.SetField(0, 2)
        f.SetField(1, 14)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(4)
        f.SetField(0, 2)
        f.SetField(1, 15)
        lyr.CreateFeature(f)
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(5)
        f.SetField(0, 2)
        f.SetField(1, 16)
        lyr.CreateFeature(f)
        f = None
        ds = None

        vl = QgsVectorLayer(tmpfile + "|subset=type=2", 'test', 'ogr')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.fields().at(vl.fields().count() -
                                       1).name() == "orig_ogc_fid")

        req = QgsFeatureRequest()
        req.setFilterExpression("value=16")
        it = vl.getFeatures(req)
        f = QgsFeature()
        self.assertTrue(it.nextFeature(f))
        self.assertTrue(f.id() == 5)

        # Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed
        req = QgsFeatureRequest()
        req.setSubsetOfAttributes([])
        it = vl.getFeatures(req)
        ids = []
        while it.nextFeature(f):
            ids.append(f.id())
        self.assertTrue(len(ids) == 3)
        self.assertTrue(3 in ids)
        self.assertTrue(4 in ids)
        self.assertTrue(5 in ids)

        # Check that subset string is correctly set on reload
        vl.reload()
        self.assertTrue(vl.fields().at(vl.fields().count() -
                                       1).name() == "orig_ogc_fid")
Example #56
0
        def run_checks():
            self.assertEqual([f.name() for f in vl.fields()],
                             ['fid', 'type', 'value'])

            # expression
            req = QgsFeatureRequest()
            req.setFilterExpression("value=16")
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter fid
            req = QgsFeatureRequest()
            req.setFilterFid(5)
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter fids
            req = QgsFeatureRequest()
            req.setFilterFids([5])
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # check with subset of attributes
            req = QgsFeatureRequest()
            req.setFilterFids([5])
            req.setSubsetOfAttributes([2])
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes()[2], 16)
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter rect and expression
            req = QgsFeatureRequest()
            req.setFilterExpression("value=16 or value=14")
            req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5))
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter rect and fids
            req = QgsFeatureRequest()
            req.setFilterFids([3, 5])
            req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5))
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed
            req = QgsFeatureRequest()
            req.setSubsetOfAttributes([])
            it = vl.getFeatures(req)
            ids = []
            geoms = {}
            while it.nextFeature(f):
                ids.append(f.id())
                geoms[f.id()] = f.geometry().asWkt()
            self.assertCountEqual(ids, [3, 4, 5])
            self.assertEqual(geoms, {
                3: 'Point (3 3)',
                4: 'Point (4 4)',
                5: 'Point (5 5)'
            })
Example #57
0
    def fetch_values_from_layer(self):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
        """
        (Re)fetches plot values from the source layer.
        """

        # Note: we keep things nice and efficient and only iterate a single time over the layer!

        if not self.context_generator:
            context = QgsExpressionContext()
            context.appendScopes(
                QgsExpressionContextUtils.globalProjectLayerScopes(
                    self.source_layer))
        else:
            context = self.context_generator.createExpressionContext()
            # add a new scope corresponding to the source layer -- this will potentially overwrite any other
            # layer scopes which may be present in the context (e.g. from atlas layers), but we need to ensure
            # that source layer fields and attributes are present in the context
            context.appendScope(
                self.source_layer.createExpressionContextScope())

        self.settings.data_defined_properties.prepare(context)

        self.fetch_layout_properties(context)

        def add_source_field_or_expression(field_or_expression):
            field_index = self.source_layer.fields().lookupField(
                field_or_expression)
            if field_index == -1:
                expression = QgsExpression(field_or_expression)
                if not expression.hasParserError():
                    expression.prepare(context)
                return expression, expression.needsGeometry(
                ), expression.referencedColumns()

            return None, False, {field_or_expression}

        x_expression, x_needs_geom, x_attrs = add_source_field_or_expression(self.settings.properties['x_name']) if \
            self.settings.properties[
                'x_name'] else (None, False, set())
        y_expression, y_needs_geom, y_attrs = add_source_field_or_expression(self.settings.properties['y_name']) if \
            self.settings.properties[
                'y_name'] else (None, False, set())
        z_expression, z_needs_geom, z_attrs = add_source_field_or_expression(self.settings.properties['z_name']) if \
            self.settings.properties[
                'z_name'] else (None, False, set())
        additional_info_expression, additional_needs_geom, additional_attrs = add_source_field_or_expression(
            self.settings.layout['additional_info_expression']
        ) if self.settings.layout['additional_info_expression'] else (None,
                                                                      False,
                                                                      set())

        attrs = set().union(
            self.settings.data_defined_properties.referencedFields(), x_attrs,
            y_attrs, z_attrs, additional_attrs)

        request = QgsFeatureRequest()

        if self.settings.data_defined_properties.property(
                PlotSettings.PROPERTY_FILTER).isActive():
            expression = self.settings.data_defined_properties.property(
                PlotSettings.PROPERTY_FILTER).asExpression()
            request.setFilterExpression(expression)
            request.setExpressionContext(context)

        request.setSubsetOfAttributes(attrs, self.source_layer.fields())

        if not x_needs_geom and not y_needs_geom and not z_needs_geom and not additional_needs_geom and not self.settings.data_defined_properties.hasActiveProperties(
        ):
            request.setFlags(QgsFeatureRequest.NoGeometry)

        visible_geom_engine = None
        if self.visible_features_only and self.visible_region is not None:
            ct = QgsCoordinateTransform(
                self.visible_region.crs(), self.source_layer.crs(),
                QgsProject.instance().transformContext())
            try:
                rect = ct.transformBoundingBox(self.visible_region)
                request.setFilterRect(rect)
            except QgsCsException:
                pass
        elif self.visible_features_only and self.polygon_filter is not None:
            ct = QgsCoordinateTransform(
                self.polygon_filter.crs(), self.source_layer.crs(),
                QgsProject.instance().transformContext())
            try:
                rect = ct.transformBoundingBox(
                    self.polygon_filter.geometry.boundingBox())
                request.setFilterRect(rect)
                g = self.polygon_filter.geometry
                g.transform(ct)

                visible_geom_engine = QgsGeometry.createGeometryEngine(
                    g.constGet())
                visible_geom_engine.prepareGeometry()
            except QgsCsException:
                pass

        if self.selected_features_only:
            it = self.source_layer.getSelectedFeatures(request)
        else:
            it = self.source_layer.getFeatures(request)

        # Some plot types don't draw individual glyphs for each feature, but aggregate them instead.
        # In that case it doesn't make sense to evaluate expressions for settings like marker size or color for each
        # feature. Instead, the evaluation should be executed only once for these settings.
        aggregating = self.settings.plot_type in ['box', 'histogram']
        executed = False

        xx = []
        yy = []
        zz = []
        additional_hover_text = []
        marker_sizes = []
        colors = []
        stroke_colors = []
        stroke_widths = []
        for f in it:
            if visible_geom_engine and not visible_geom_engine.intersects(
                    f.geometry().constGet()):
                continue

            self.settings.feature_ids.append(f.id())
            context.setFeature(f)

            x = None
            if x_expression:
                x = x_expression.evaluate(context)
                if x == NULL or x is None:
                    continue
            elif self.settings.properties['x_name']:
                x = f[self.settings.properties['x_name']]
                if x == NULL or x is None:
                    continue

            y = None
            if y_expression:
                y = y_expression.evaluate(context)
                if y == NULL or y is None:
                    continue
            elif self.settings.properties['y_name']:
                y = f[self.settings.properties['y_name']]
                if y == NULL or y is None:
                    continue

            z = None
            if z_expression:
                z = z_expression.evaluate(context)
                if z == NULL or z is None:
                    continue
            elif self.settings.properties['z_name']:
                z = f[self.settings.properties['z_name']]
                if z == NULL or z is None:
                    continue

            if additional_info_expression:
                additional_hover_text.append(
                    additional_info_expression.evaluate(context))
            elif self.settings.layout['additional_info_expression']:
                additional_hover_text.append(
                    f[self.settings.layout['additional_info_expression']])

            if x is not None:
                xx.append(x)
            if y is not None:
                yy.append(y)
            if z is not None:
                zz.append(z)

            if self.settings.data_defined_properties.isActive(
                    PlotSettings.PROPERTY_MARKER_SIZE):
                default_value = self.settings.properties['marker_size']
                context.setOriginalValueVariable(default_value)
                value, _ = self.settings.data_defined_properties.valueAsDouble(
                    PlotSettings.PROPERTY_MARKER_SIZE, context, default_value)
                marker_sizes.append(value)
            if self.settings.data_defined_properties.isActive(
                    PlotSettings.PROPERTY_STROKE_WIDTH):
                default_value = self.settings.properties['marker_width']
                context.setOriginalValueVariable(default_value)
                value, _ = self.settings.data_defined_properties.valueAsDouble(
                    PlotSettings.PROPERTY_STROKE_WIDTH, context, default_value)
                stroke_widths.append(value)

            if self.settings.data_defined_properties.isActive(
                    PlotSettings.PROPERTY_COLOR) and (not aggregating
                                                      or not executed):
                default_value = QColor(self.settings.properties['in_color'])
                value, conversion_success = self.settings.data_defined_properties.valueAsColor(
                    PlotSettings.PROPERTY_COLOR, context, default_value)
                if conversion_success:
                    # We were given a valid color specification, use that color
                    colors.append(value.name())
                else:
                    try:
                        # Attempt to interpret the value as a list of color specifications
                        value_list = self.settings.data_defined_properties.value(
                            PlotSettings.PROPERTY_COLOR, context)
                        color_list = [
                            QgsSymbolLayerUtils.decodeColor(item).name()
                            for item in value_list
                        ]
                        colors.extend(color_list)
                    except TypeError:
                        # Not a list of color specifications, use the default color instead
                        colors.append(default_value.name())

            if self.settings.data_defined_properties.isActive(
                    PlotSettings.PROPERTY_STROKE_COLOR) and (not aggregating
                                                             or not executed):
                default_value = QColor(self.settings.properties['out_color'])
                value, conversion_success = self.settings.data_defined_properties.valueAsColor(
                    PlotSettings.PROPERTY_STROKE_COLOR, context, default_value)
                if conversion_success:
                    # We were given a valid color specification, use that color
                    stroke_colors.append(value.name())
                else:
                    try:
                        # Attempt to interpret the value as a list of color specifications
                        value_list = self.settings.data_defined_properties.value(
                            PlotSettings.PROPERTY_STROKE_COLOR, context)
                        color_list = [
                            QgsSymbolLayerUtils.decodeColor(item).name()
                            for item in value_list
                        ]
                        stroke_colors.extend(color_list)
                    except TypeError:
                        # Not a list of color specifications, use the default color instead
                        stroke_colors.append(default_value.name())

            executed = True

        self.settings.additional_hover_text = additional_hover_text
        self.settings.x = xx
        self.settings.y = yy
        self.settings.z = zz
        if marker_sizes:
            self.settings.data_defined_marker_sizes = marker_sizes
        if colors:
            self.settings.data_defined_colors = colors
        if stroke_colors:
            self.settings.data_defined_stroke_colors = stroke_colors
        if stroke_widths:
            self.settings.data_defined_stroke_widths = stroke_widths
Example #58
0
def zonal_stats(raster, vector, callback=None):
    """Reclassify a continuous raster layer.

    Issue https://github.com/inasafe/inasafe/issues/3190


    :param raster: The raster layer.
    :type raster: QgsRasterLayer

    :param vector: The vector layer.
    :type vector: QgsVectorLayer

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int), 'maximum' (int) and 'step' (str).
        Defaults to None.
    :type callback: function

    :return: The output of the zonal stats.
    :rtype: QgsVectorLayer

    .. versionadded:: 4.0
    """
    output_layer_name = zonal_stats_steps['output_layer_name']
    processing_step = zonal_stats_steps['step_name']

    layer = create_memory_layer(
        output_layer_name,
        vector.geometryType(),
        vector.crs(),
        vector.fields()
    )

    copy_layer(vector, layer)

    analysis = QgsZonalStatistics(
        layer, raster.source(), 'exposure_', 1, QgsZonalStatistics.Sum)
    result = analysis.calculateStatistics(None)
    LOGGER.debug(tr('Zonal stats on %s : %s' % (raster.source(), result)))

    layer.startEditing()
    exposure = raster.keywords['exposure']
    output_field = exposure_count_field['field_name'] % exposure
    fields_to_rename = {
        'exposure_sum': output_field
    }
    copy_fields(layer, fields_to_rename)
    remove_fields(layer, fields_to_rename.keys())

    layer.commitChanges()

    # The zonal stats is producing some None values. We need to fill these
    # with 0. See issue : #3778
    # We should start a new editing session as previous fields need to be
    # commited first.
    layer.startEditing()
    request = QgsFeatureRequest()
    expression = '\"%s\" is None' % output_field
    request.setFilterExpression(expression)
    request.setFlags(QgsFeatureRequest.NoGeometry)
    index = layer.fieldNameIndex(output_field)
    for feature in layer.getFeatures():
        if feature[output_field] is None:
            layer.changeAttributeValue(feature.id(), index, 0)
    layer.commitChanges()

    layer.keywords = raster.keywords.copy()
    layer.keywords['inasafe_fields'] = vector.keywords['inasafe_fields'].copy()
    layer.keywords['inasafe_default_values'] = (
        raster.keywords['inasafe_default_values'].copy())

    key = exposure_count_field['key'] % raster.keywords['exposure']

    # Special case here, one field is the exposure count and the total.
    layer.keywords['inasafe_fields'][key] = output_field
    layer.keywords['inasafe_fields'][total_field['key']] = output_field

    layer.keywords['exposure_keywords'] = raster.keywords.copy()
    layer.keywords['hazard_keywords'] = vector.keywords[
        'hazard_keywords'].copy()
    layer.keywords['aggregation_keywords'] = (
        vector.keywords['aggregation_keywords'])
    layer.keywords['layer_purpose'] = (
        layer_purpose_aggregate_hazard_impacted['key'])

    layer.keywords['title'] = output_layer_name

    check_layer(layer)
    return layer