I have a MultiPoint layer in QGIS 3.18 that I wanted to add x and y coordinates to in its attribute table. Normally, I can just use field calculator and calculate the new field to be $x
or $y
.
How do I achieve the same thing in PyQGIS?
My current workflow:
pr = multiPointLayer.dataProvider()
pr.addAttributes([QgsField("x_coord", QVariant.Double), QgsField("y_coord", QVariant.Double)])
multiPointLayer.updateFields()
with edit(multiPointLayer):
for feature in multiPointLayer.getFeatures():
feature['x_coord'] = ???
feature['y_coord'] = ???
multiPointLayer.updateFeature(feature)
QgsProject.instance().addMapLayer(multiPointLayer)
PyQGIS is unwilling to handle MultiPoint layers, seems like -- and when I use the Add X/Y coordinates algorithm provided by QGIS it wanted me to use single points, but I'd much rather keep it a MultiPoint layer since they can be relatively large.
Turns out, all I had to do is to convert my multipoint layer to singlepoint. When Clipping a point layer, the output point layer gets automatically converted to a multipoint one, which caused the issue. The commenting about a multipoint layer made me aware of the properties of the multipoint type.
-
5How are you going to get multiple point vales in a single row? If all the multipoints are degenerate (singleton), you're wasting the storage overhead and costing yourself spatial index inefficiency.Vince– Vince2021年08月23日 03:25:24 +00:00Commented Aug 23, 2021 at 3:25
-
I suppose I gotta convert the multipoint layer from multipart to singlepart first to convert the layer back to a simple point layer. That's a good point about multipoints -- I didn't fully understand what that file type is.WFL.GIS– WFL.GIS2021年08月23日 03:52:30 +00:00Commented Aug 23, 2021 at 3:52
-
2Maybe this one can help you: gis.stackexchange.com/questions/380783/… and additionally you may need to loop over each multipoint part.Taras– Taras ♦2021年08月23日 04:48:20 +00:00Commented Aug 23, 2021 at 4:48
1 Answer 1
Here are three solutions. You can either
- Get a list, array or concatenated string of all x and y coordinates of each MultiPoint
- Get the x and y coordinate of the centroid of each MultiPoint
- Get the x and y coordinates of the first point of each MultiPoint
If not using the centroid, you need to loop through the vertices of each MultiPoint-Feature just as you would do it with a MultiLineString or a MultiPolygon.
#multiPointLayer = QgsProject.instance().mapLayersByName('Dissolved')[0] # get a layer
pr = multiPointLayer.dataProvider()
# Note the change of fieldtypes:
pr.addAttributes([
# Will store the concatenated string of all x and y coordinates of each MultiPoint:
QgsField("x_coords", QVariant.String),
QgsField("y_coords", QVariant.String),
# Will store the x and y coordinate of the centroid of each MultiPoint:
QgsField("x_coord_centroid", QVariant.Double),
QgsField("y_coord_centroid", QVariant.Double),
# Will store the x and y coordinates of the first point of each MultiPoint:
QgsField("x_coord_firstpoint", QVariant.Double),
QgsField("y_coord_firstpoint", QVariant.Double)
])
multiPointLayer.updateFields()
with edit(multiPointLayer):
for feature in multiPointLayer.getFeatures():
geom = feature.geometry() # get the geometry of the current feature
x_arr = [] # create an empty list
y_arr = [] # create an empty list
for part in geom.parts(): # loop through the parts of each multipoint feature
for p in part.vertices(): # now "loop through" each vertex of each part (actually a loop isnt really needed but easier to implement, since each part always has exact one vertex)
x_arr.append(p.x()) # get the x coordinate of that vertex (p.x()) and append it to the list
y_arr.append(p.y()) # get the y coordinate of that vertex (p.y()) and append it to the list
# Same as array_to_string(array_foreach(generate_series(0,num_points($geometry)-1),x_at(@element)),','):
feature['x_coords'] = ','.join(str(x) for x in x_arr) # turn the list of x coordinates into a comma spearated string. Therefore we need to iterate over the list and convert each double value to a string
feature['y_coords'] = ','.join(str(y) for y in y_arr) # turn the list of y coordinates into a comma spearated string. Therefore we need to iterate over the list and convert each double value to a string
# Same as x($geometry) and y($geometry):
feature['x_coord_centroid'] = geom.centroid().asPoint().x() # get the x coordinate of the multipoint features centroid
feature['y_coord_centroid'] = geom.centroid().asPoint().y() # get the y coordinate of the multipoint features centroid
# Same as $x and $y:
feature['x_coord_firstpoint'] = x_arr[0] # get the x coordinate of the first point of each MultiPoint
feature['y_coord_firstpoint'] = y_arr[0] # get the y coordinate of the first point of each MultiPoint
multiPointLayer.updateFeature(feature)
QgsProject.instance().addMapLayer(multiPointLayer)
A side note on your expressions, not PyQGIS related:
If you type $x
or $y
in fieldcaluclator on a MultiPoint-layer, you will always get the coordinate of the "first" point. This is mentioned in the function description.
If you use x($geometry)
or y($geometry)
, you will get the centroid for each MultiPoint.
If you want another coordinate than the one from the first point, you can use x_at()
or y_at()
, e.g. x_at(2)
to return the x coordinate of the 3rd point of a MultiPoint.
You can also use x_at()
and y_at()
to return an array of all x and y coordinates of a MultiPoint by combining it with num_points()
, generate_series()
and array_foreach()
, e.g. by using array_foreach(generate_series(0,num_points($geometry)-1),x_at(@element))
to get an array of all x coordinates of each MultiPoint or array_foreach(generate_series(0,num_points($geometry)-1),y_at(@element))
to get an array of all y coordinates of each MultiPoint.
-
Turns out it was a relatively simple fix for me, as I needed to just convert my multipoint layer to a singlepoint one (the layer I was working with was a singlepoint layer but somehow automatically converted to multipoint after it was clipped). But I understood the answer you provided in terms of accessing certain coordinates in an actual multipoint layer. Thank you!WFL.GIS– WFL.GIS2021年08月23日 20:25:16 +00:00Commented Aug 23, 2021 at 20:25
Explore related questions
See similar questions with these tags.