Is there a way to use a spatial query to invert X and Y coordinates in QGIS?
I propose a solution using PyQGIS: the several codes instantly work from the Python Console, but they can easily be implemented in separate scripts (see the edit at the end of the answer). Each script will return a new memory vector layer storing the inverted lon/lat coordinates for the geometries.
I tested the solution on several datasets available from Natural Earth Data.
Solution for point vector layers
Code
layer = iface.activeLayer()
crs = layer.crs().toWkt()
# Create the output layer
outLayer = QgsVectorLayer('Point?crs='+ crs, 'inverted' , 'memory')
prov = outLayer.dataProvider()
fields = layer.pendingFields()
prov.addAttributes(fields)
outLayer.updateFields()
for feat in layer.getFeatures():
attrs = feat.attributes()
geom = feat.geometry()
coords = geom.asPoint()
new_coords = (QgsPoint(coords[1], coords[0]))
geom=QgsGeometry.fromPoint(new_coords)
outGeom = QgsFeature()
outGeom.setGeometry(geom)
outGeom.setAttributes(attrs)
prov.addFeatures([outGeom])
# Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)
Graphical example
Before:
After:
Solution for line vector layers
Code
layer = iface.activeLayer()
crs = layer.crs().toWkt()
# Create the output layer
outLayer = QgsVectorLayer('LineString?crs='+ crs, 'inverted' , 'memory')
prov = outLayer.dataProvider()
fields = layer.pendingFields()
prov.addAttributes(fields)
outLayer.updateFields()
for feat in layer.getFeatures():
attrs = feat.attributes()
geom = feat.geometry()
coords = geom.asMultiPolyline()
if coords:
new_coords = [[QgsPoint(y, x) for x, y in z] for z in coords]
geom=QgsGeometry.fromMultiPolyline(new_coords)
else:
coords = geom.asPolyline()
new_coords = [QgsPoint(y, x) for x, y in coords]
geom=QgsGeometry.fromPolyline(new_coords)
outGeom = QgsFeature()
outGeom.setGeometry(geom)
outGeom.setAttributes(attrs)
prov.addFeatures([outGeom])
# Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)
Graphical example
Before:
After:
Solution for polygon vector layers
Code
layer = iface.activeLayer()
crs = layer.crs().toWkt()
# Create the output layer
outLayer = QgsVectorLayer('Polygon?crs='+ crs, 'inverted' , 'memory')
prov = outLayer.dataProvider()
fields = layer.pendingFields()
prov.addAttributes(fields)
outLayer.updateFields()
for feat in layer.getFeatures():
attrs = feat.attributes()
geom = feat.geometry()
coords = geom.asMultiPolygon()
if coords:
new_coords=[[[QgsPoint(y, x) for x, y in z] for z in coord] for coord in coords]
geom=QgsGeometry.fromMultiPolygon(new_coords)
else:
coords = geom.asPolygon()
new_coords=[[QgsPoint(y, x) for x, y in z] for z in coords]
geom=QgsGeometry.fromPolygon(new_coords)
outGeom = QgsFeature()
outGeom.setGeometry(geom)
outGeom.setAttributes(attrs)
prov.addFeatures([outGeom])
# Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)
Graphical example
Before:
After:
EDIT
The codes above were implemented by @gisnside in a separate script that can be added to the Processing Toolbox (it substantially adapts the proper code to the geometry type).
#!/usr/bin/python
# encoding: utf-8
# Created by mgri
# Adapted for processing toolbox by gisnside
# This script inverts X and Y coordinates of a vector layer
##Vector_tools=group
##Invert_XY=name
##vector_layer=vector
from qgis.core import *
layer = processing.getObject(vector_layer)
crs = layer.crs().toWkt()
geometryType = layer.geometryType()
if geometryType == QGis.Point:
# Create the output layer
outLayer = QgsVectorLayer('Point?crs='+ crs, 'inverted' , 'memory')
prov = outLayer.dataProvider()
fields = layer.pendingFields()
prov.addAttributes(fields)
outLayer.updateFields()
for feat in layer.getFeatures():
attrs = feat.attributes()
geom = feat.geometry()
coords = geom.asPoint()
new_coords = (QgsPoint(coords[1], coords[0]))
geom=QgsGeometry.fromPoint(new_coords)
outGeom = QgsFeature()
outGeom.setGeometry(geom)
outGeom.setAttributes(attrs)
prov.addFeatures([outGeom])
# Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)
elif geometryType == QGis.Line:
# Create the output layer
outLayer = QgsVectorLayer('LineString?crs='+ crs, 'inverted' , 'memory')
prov = outLayer.dataProvider()
fields = layer.pendingFields()
prov.addAttributes(fields)
outLayer.updateFields()
for feat in layer.getFeatures():
attrs = feat.attributes()
geom = feat.geometry()
coords = geom.asMultiPolyline()
if coords:
new_coords = [[QgsPoint(y, x) for x, y in z] for z in coords]
geom=QgsGeometry.fromMultiPolyline(new_coords)
else:
coords = geom.asPolyline()
new_coords = [QgsPoint(y, x) for x, y in coords]
geom=QgsGeometry.fromPolyline(new_coords)
outGeom = QgsFeature()
outGeom.setGeometry(geom)
outGeom.setAttributes(attrs)
prov.addFeatures([outGeom])
# Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)
elif geometryType == QGis.Polygon:
# Create the output layer
outLayer = QgsVectorLayer('Polygon?crs='+ crs, 'inverted' , 'memory')
prov = outLayer.dataProvider()
fields = layer.pendingFields()
prov.addAttributes(fields)
outLayer.updateFields()
for feat in layer.getFeatures():
attrs = feat.attributes()
geom = feat.geometry()
coords = geom.asMultiPolygon()
if coords:
new_coords=[[[QgsPoint(y, x) for x, y in z] for z in coord] for coord in coords]
geom=QgsGeometry.fromMultiPolygon(new_coords)
else:
coords = geom.asPolygon()
new_coords=[[QgsPoint(y, x) for x, y in z] for z in coords]
geom=QgsGeometry.fromPolygon(new_coords)
outGeom = QgsFeature()
outGeom.setGeometry(geom)
outGeom.setAttributes(attrs)
prov.addFeatures([outGeom])
# Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)
You can use the Affine Transformation plugin to do this.
It's not particularly fast, so you might want to try on some fairly simple geometries to begin with. Also, it only works with editable layers, so you will need to convert your delimited file into an editable format.
Once installed, the plugin goes under Vector > Geoprocessing tools > Affine Transformation
Note! this plugin edits the layer in-place, rather than creating a new layer. So I recommend you run it on a copy.
Next, use the following settings...
x' = 0.0 x + 1.0 y + 0.0
y' = 1.0 x + 0.0 y + 0.0
as seen below...
Here, I've swapped the x and y values for the UK, which sends it out into the Indian ocean, consistent with swapping the X and Y.
Just to be complete on the question : there is a "Swap XY" plugin in QGIS plugin list. It didn't work at first on my computer so I discounted it in my question, but I solved this. It can do the X/Y inversion too. One just need to look for SWAP XY in the plugin repository.
It adds a button one can click. It will then modify the current selected layer and invert coordinates. The creator added a warning it can sometime corrupt the data or not invert all coordinates.