Hi Richard On Tue, Feb 5, 2013 at 7:27 PM, Richard Duivenvoorde <rdmaili...@duif.net> wrote: > Hi Devs, > > I used the following in a python plugin to select features: > > self.provider.select(self.provider.attributeIndexes(), mapCanvasExtent, > True, True) > > is there somewhere an example how to do this in the new api using > > QgsFeatureIterator QgsOgrProvider::getFeatures( const QgsFeatureRequest& > request ) > > and python?
I haven't updated the examples yet, sorry. Here we go in Python: for f in layer.getFeatures(): print f["name"].toString(), f.geometry().exportToWkt() This will use give you all features from a layer with geometries and attributes. If no request is specified in the getFeatures() call, it will use default request which fetches everything - equal to calling getFeatures(QgsFeatureRequest()). The getFeatures() call returns QgsFeatureIterator instance. Python bindings of this class support python's iterator protocol [1] so you can use it directly in a 'for' cycle as shown above. Of course it is still possible to original C++ API style, but it does not feel very pythonic: f = QgsFeature() iter = layer.getFeatures() while iter.nextFeature(f): print f["name"].toString(), f.geometry().exportToWkt() I strongly recommend the former variant - it's easier to write and understand, so less prone to errors. Access to attributes: there is no f.attributeMap() anymore, because attributes are now stored in a vector (Python: list) instead of a map (Python: dict). QgsFeature class emulates python container object [2] so you can access attributes as if QgsFeature instance was a list or dictionary, with keys being either field indices or field names: f[0] ... first attribute f["type"] ... attribute named "type" It is still possible to get all attributes: f.attributes() returns a list of values. Attribute values are returned as QVariant's as before, so in order to access a string attribute you need to do something like f["name"].toString(), for integers it is the cryptic f["speed"].toInt()[0]. At some point (before the release of 2.0) I would like to switch QGIS to use newer PyQt4 API that does automatic conversion of QVariant to python objects. This will cause that f["name"] or f["speed"] will directly return a string or int without the need to call toString()/toInt() methods). Currently we have three types of requests: 1. no filter (default), 2. filter by rectangle, 3. filter by feature ID. Fetching of features within a rectangle is done this way: rect = QgsRectangle(-10,-10,10,10) request = QgsFeatureRequest().setFilterRect(rect) for f in layer.getFeatures(request): # usual stuff here with the feature For the sake of processing speed, some providers may return features that are not in the rectangle (only their bounding box intersects the rectangle). Usually this is not a problem (e.g. for rendering), but for some cases such as identification of features in particular rectangle this is not wanted. In old API, setting fourth argument of select() to true returned only features that really intersected the rectangle. In new API this is done with a flag: request.setFlags(QgsFeatureRequest.ExactIntersect) Another type of requests are requests for a particular feature ID. In these cases we expect just one feature so we could directly fetch just one feature from the iterator: request = QgsFeatureRequest().setFilterFid(14) f = l.getFeatures(request).next() In case feature with given ID does not exist, python exception StopIteration is raised. If developers would like to optimize the requests to avoid fetching things that are not required, it is possible to: - avoid fetching of geometry: request.setFlags(QgsFeatureRequest.NoGeometry) - fetch only some (or no) attributes - e.g. fetch just first two attributes: request.setSubsetOfAttributes([0,1]) Even though API allows that, it is currently not possible to have concurrent feature iterators on one layer or data provider, something like this: iter1 = layer.getFeatures() iter2. = layer.getFeatures() # do something with both iter1 and iter2 This will NOT work - in the second getFeatures() call the iter1 will get closed and it will not return any more features. In the future some providers will support concurrent iterators, there will be probably another provider capability that would determine if a provider supports that. I hope I haven't forgotten any important use case. If more examples are necessary, I will try to provide them. Please do not hesitate to ask if things are not clear yet. Regards Martin [1] http://docs.python.org/2/library/stdtypes.html#generator-types [2] http://docs.python.org/2/reference/datamodel.html#object.__getitem__ _______________________________________________ Qgis-developer mailing list Qgis-developer@lists.osgeo.org http://lists.osgeo.org/mailman/listinfo/qgis-developer