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
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)
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
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)
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'
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)
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}})
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])
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}})
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)
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()
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']}})
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())))
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)
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
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
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
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
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)
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())
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
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)
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
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
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
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")
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
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
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
def featureRequest(expr): request = QgsFeatureRequest() request.setFilterExpression(expr) return request
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
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)
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])
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 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
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 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 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
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