3

I want to get the row, col coordinates of a raster I'm viewing in QGIS by clicking on a pixel. I found Displaying row/column of point in raster using QGIS?, which presumably provides hints about how to go about this. However, I am unable to implement it successfully.

I think the appropriate route is to use the QGIS Python console--I don't care where or how the row, col coordinates are displayed as long as I can see it update as I click different pixels. I have been trying a variety of things all day, but haven't made much progress. My plan was to use the above-provided code, but I am having trouble getting QGIS to return the coordinates from a map-clicked pixel.

For example, I tried implementing the code at Getting coordinates by clicking on QGIS Canvas with PyQGIS?, but I am not even sure how to run it. I saved it as a separate py file, imported it in the QGIS console, but I am not sure how to run vector_selectbypoint from within the python console as it is a class.

Does anyone have any tips for how I should be approaching this?

0

1 Answer 1

5

Given a rectified image, that is an image without rotation, or a regular raster, you may paste the following scripts into the Python console or execute them as script from the editor. Each of them outputs row and columns indices (0..x/y).

The first script is based on class QgsMapTool implementing canvasPressEvent() method. It evaluates clicks with the left mouse button. Once executed the tool remains active until another map tool is activated.

For more details see this answer.

from qgis.gui import QgsMapTool
from PyQt4.QtCore import Qt, QPoint
from math import floor

# references to QGIS objects 
canvas = iface.mapCanvas() 
layer = iface.activeLayer() 
data_provider = layer.dataProvider()

# properties to map mouse position to row/col index of the raster in memory 
extent = data_provider.extent() 
width = data_provider.xSize() if data_provider.capabilities() & data_provider.Size else 1000 
height = data_provider.ySize() if data_provider.capabilities() & data_provider.Size else 1000 
xres = extent.width() / width 
yres = extent.height() / height

class ClickTool(QgsMapTool): 
    def __init__(self, canvas):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas 

    def canvasPressEvent(self, event):
        if event.button() == Qt.LeftButton: 
            x = event.pos().x()
            y = event.pos().y()

            # clicked position on screen to map coordinates
            point = self.canvas.getCoordinateTransform().toMapCoordinates(x, y)

            if extent.xMinimum() <= point.x() <= extent.xMaximum() and \
                extent.yMinimum() <= point.y() <= extent.yMaximum():
                col = int(floor((point.x() - extent.xMinimum()) / xres))
                row = int(floor((extent.yMaximum() - point.y()) / yres))

                print row, col

tool = ClickTool(iface.mapCanvas())
iface.mapCanvas().setMapTool(tool)

The second script will output the row and column index of the raster below the current cursor position, and is updated while the cursor is moving. When the cursor is outside the extend of the raster, then nothing is printed.

from math import floor

# references to QGIS objects 
canvas = iface.mapCanvas() 
layer = iface.activeLayer() 
data_provider = layer.dataProvider()

# properties to map mouse position to row/col index of the raster in memory 
extent = data_provider.extent() 
width = data_provider.xSize() if data_provider.capabilities() & data_provider.Size else 1000 
height = data_provider.ySize() if data_provider.capabilities() & data_provider.Size else 1000 
xres = extent.width() / width 
yres = extent.height() / height

# slot called whenever mouse position changes 
def show_raster_row_col(point):
    if extent.xMinimum() <= point.x() <= extent.xMaximum() and \
        extent.yMinimum() <= point.y() <= extent.yMaximum():
        col = int(floor((point.x() - extent.xMinimum()) / xres))
        row = int(floor((extent.yMaximum() - point.y()) / yres))

        # output row and column index to console
        print row, col

# connect slot to canvas signal
canvas.xyCoordinates.connect(show_raster_row_col)

To stop the script, type the following line into the console:

canvas.xyCoordinates.disconnect(show_raster_row_col)
6
  • Thanks for the contribution, but have you used this? It continually outputs coordinates, even when I move my mouse off the screen. I cannot read them because the list is updated so frequently. In my question, I request the coordinates to be output on clicking--do you know the commands for that? If not, this is at least a better jumping-off point for me.
    – Jon
    Commented Nov 13, 2017 at 16:33
  • I should also note that I needed to put the xres and yres commands on separate lines to avoid a Syntax error.
    – Jon
    Commented Nov 13, 2017 at 16:35
  • Thanks for the update, @Detlev. I needed to replace your first two lines with these: from qgis.gui import QgsMapTool; from PyQt4.QtCore import QPoint, Qt. Otherwise Qt could not be found in qgis.gui and QgsMapTool was undefined. But now it works and I have a template for future modifications! I'm running QGIS 2.14.2 FWIW.
    – Jon
    Commented Nov 13, 2017 at 23:36
  • Thanks for the hints, I obviously copied wrong lines into the editor widget here.
    – Detlev
    Commented Nov 14, 2017 at 6:21
  • 3
    To get this working in QGIS 3 (which uses Python 3), all you need to do is change print(row, col) to print(f'{row}, {col}').
    – gbmhunter
    Commented Feb 19, 2019 at 19:54

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.