Select to view content in your preferred language

Getting XY from mouse click using python

28150
22
02-03-2012 07:42 AM
MichelleHawks
New Contributor
Hi all,
I would like to create a button that captures the location of the next mouse click and displays it in LAT/LONG. I imagine is would have to open a submenu which would be closed when the user is finished getting location information. Is there any way to do this using python?
Tags (2)
0 Kudos
22 Replies
DavidAllen
Frequent Contributor
I'm getting the code to work for onMouseDownMap, but while in layout view the value I'm getting back is still in page coordinates and not map coordinates ... unless I go to the data view. Then I get map coordinates.

Is this how it's supposed to work, or is there a was to focus the data frame and get map coordinates.

class Sel_Property(object):
    """Implementation for Notifications_addin.selectproperty (Tool)"""
    def __init__(self):
        self.enabled = True
        self.shape = "NONE" # Can set to "Line", "Circle" or "Rectangle" ...
    def onMouseDownMap(self, x, y, button, shift):
        pythonaddins.MessageBox("Your mouse clicked at " + str(x) + " , " + str(y),"My Coordinates:")
0 Kudos
JamesCrandall
MVP Alum
I'm getting the code to work for onMouseDownMap, but while in layout view the value I'm getting back is still in page coordinates and not map coordinates ... unless I go to the data view. Then I get map coordinates.

Is this how it's supposed to work, or is there a was to focus the data frame and get map coordinates.

class Sel_Property(object):
    """Implementation for Notifications_addin.selectproperty (Tool)"""
    def __init__(self):
        self.enabled = True
        self.shape = "NONE" # Can set to "Line", "Circle" or "Rectangle" ...
    def onMouseDownMap(self, x, y, button, shift):
        pythonaddins.MessageBox("Your mouse clicked at " + str(x) + " , " + str(y),"My Coordinates:")


David,

While this is the reverse of what you want, I think it should be able to give you some ideas.  I will need to do the same as you soon, but just havn't had the opportunity to do so just yet.

I think you will need get the properties of the DataFrame to convert from page units to preferred projected coordinates.

http://gis.stackexchange.com/questions/21514/convert-point-xy-to-page-units-xy-using-arcpy
0 Kudos
DavidAllen
Frequent Contributor
David,

While this is the reverse of what you want, I think it should be able to give you some ideas.  I will need to do the same as you soon, but just havn't had the opportunity to do so just yet.

I think you will need get the properties of the DataFrame to convert from page units to preferred projected coordinates.

http://gis.stackexchange.com/questions/21514/convert-point-xy-to-page-units-xy-using-arcpy


Here's what I discovered when using the onMouseDown and onMouseDownMap in a Python add-in.

The function onMouseDown will return a set of pixel values showing the coordinates of where you clicked, measured in pixels from the upper left of the map display window.

The function onMouseDownMap is sensitive to your current view. If you are in data view, it returns coordinates in the map's coordinate system. If you are in layout view, it returns coordinates in page units - but only allows you to click inside the data frame element.

The fix is as suggested by James (Thanks!!). Convert the page coordinates to map coordinates. To do this, I find the lower left page X coordinate and the click point X value and subtract the two. That's how far over from the edge of the data frame I clicked in inches. Then (for feet) divide by twelve and multiply by the scale of the map. That's the distance in map units I am from the edge of the data frame. Then I find the data frame's minimum X value in map units and add the calculated distance. Repeat for Y. Here's the code for a tool in my add-in that lets you click in the map while in layout view and select a feature from a layer called "Cadastre".

class Sel_Property(object):
    """Implementation for Notifications_addin.selectproperty (Tool)"""
    def __init__(self):
        self.enabled = False
        self.shape = "NONE" # Can set to "Line", "Circle" or "Rectangle" for interactive shape drawing and to activate the onLine/Polygon/Circle event sinks.
    def onMouseDownMap(self, x, y, button, shift):
        thisMap = arcpy.mapping.MapDocument("CURRENT")
        data_frame = arcpy.mapping.ListDataFrames(thisMap)[0]
        page_x = x
        page_y = y

        """Convert page coordinates to projected coordinates"""

        #get the data frame dimensions in page units
        df_page_w = data_frame.elementWidth
        df_page_h = data_frame.elementHeight
        df_page_x_min = data_frame.elementPositionX
        df_page_y_min = data_frame.elementPositionY
        df_page_x_max = df_page_w + df_page_x_min
        df_page_y_max = df_page_h + df_page_y_min

        #get the data frame projected coordinates
        df_min_x = data_frame.extent.XMin
        df_min_y = data_frame.extent.YMin
        df_max_x = data_frame.extent.XMax
        df_max_y = data_frame.extent.YMax
        df_proj_w = data_frame.extent.width
        df_proj_h = data_frame.extent.height
        #ensure the coordinates are in the dataframe
        if page_x < df_page_x_min or page_x > df_page_x_max:
            raise ValueError ('X coordinate is not within map portion of the page.')

        if page_y < df_page_y_min or page_y > df_page_y_max:
            raise ValueError ('Y coordinate is not within map portion of the page.')

        #scale the projected coordinates to map units from the lower left of the data frame
        scale = data_frame.scale/12 # converting scale factor to feet per inch
        map_x = df_min_x + ((page_x - df_page_x_min)*scale)
        map_y = df_min_y + ((page_y - df_page_y_min)*scale)
        # pythonaddins.MessageBox("Coordiantes are" + str(map_x) + " and " + str(map_y),"Title")

        pointGeom = arcpy.PointGeometry(arcpy.Point(map_x,map_y), thisMap.activeDataFrame.spatialReference)
        layers = arcpy.mapping.ListLayers(thisMap)
        for lyr in layers:
            if lyr.name == "Cadastre":
                arcpy.SelectLayerByLocation_management(lyr,"INTERSECT",pointGeom)
                thisMap.activeView = "PAGE_LAYOUT"
                arcpy.RefreshActiveView()
                data_frame.zoomToSelectedFeatures()
                data_frame.scale = data_frame.scale * 5.2