0

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.

PolyGeo
65.5k29 gold badges115 silver badges349 bronze badges
asked Aug 23, 2021 at 3:07
3
  • 5
    How 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. Commented 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. Commented Aug 23, 2021 at 3:52
  • 2
    Maybe this one can help you: gis.stackexchange.com/questions/380783/… and additionally you may need to loop over each multipoint part. Commented Aug 23, 2021 at 4:48

1 Answer 1

3

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.

answered Aug 23, 2021 at 8:34
1
  • 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! Commented Aug 23, 2021 at 20:25

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.