Wednesday 18 November 2015

pyqgis - Getting row, col on click of a pixel on a QGIS map



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?



Answer



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)

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...