7

I am trying to convert Map X and Y coordinates to corresponding Layout coordinates in a rotated dataframe.

The code found in this answer to Convert point XY to page units XY using arcpy? works fine, but only for unrotated dataframes.

I've also found a modification of the above code in this post on Reddit, but that doesn't seem to work either. I believe the code was making use of a rotation matrix as discussed in this post, but without success, in my opinion.

The results I get are somewhat close when the dataframe is not rotated very much, but they exaggerate the greater the rotation.

Has anyone had definitive success with converting X and Y coordinates to Layout coordinates?

I'm looking for a python solution within ArcGIS. I'm using 10.3.1 Standard License.

5
+50

Original layout:

enter image description here

Script:

import arcpy, os, traceback, sys,time
import numpy as np
from math import radians,sin,cos

try:
    def showPyMessage():
        arcpy.AddMessage(str(time.ctime()) + " - " + message)
    def Rotate(xM,yM,angle,xc,yc):
        x=xM-xc;y=yM-yc
        a=radians(angle)
        xN=cos(a)*x+sin(a)*y
        yN=-sin(a)*x+cos(a)*y
        return xN+xc,yN+yc
    def getCoeffs(df,angle):
        #get the data frame dimensions in map units
        df_map_w = df.elementWidth
        df_map_h = df.elementHeight
        df_map_x = df.elementPositionX
        df_map_y = df.elementPositionY
        #get the data frame projected coordinates
        min_x = df.extent.XMin
        min_y = df.extent.YMin
        max_x = df.extent.XMax
        max_y = df.extent.YMax
        A=[[min_x,min_y,1],
           [min_x,max_y,1],
           [max_x,max_y,1]]
        B=[df_map_x,df_map_x,df_map_x+df_map_w]
        A=np.array(A)
        B=np.array(B)
        #get x coefficients
        cX=np.linalg.solve(A,B)
        B=[df_map_y,df_map_y+df_map_h,df_map_y+df_map_h]
        B=np.array(B)
        #get y coefficients
        cY=np.linalg.solve(A,B)
        return (cX,cY)

    mxd = arcpy.mapping.MapDocument("CURRENT")
    df = arcpy.mapping.ListDataFrames(mxd)[0]

    angle=df.rotation
    df.rotation=0
    coeffs=getCoeffs(df,angle)
    df.rotation=angle

    cX=coeffs[0]
    cY=coeffs[1]
    coords=[[1742928.372, 6003489.49],
            [1743016.349, 6003489.49],
            [1743104.325, 6003489.49]]
    for i in range(3):
        x,y=coords[i]
        xP=x*cX[0]+y*cX[1]+cX[2]
        yP=x*cY[0]+y*cY[1]+cY[2]
        XC=df.elementPositionX+df.elementWidth/2
        YC=df.elementPositionY+df.elementHeight/2
        xP,yP=Rotate (xP,yP,-angle,XC,YC)
        elm = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT",chr(65+i))[0]
        elm.elementPositionX=xP
        elm.elementPositionY=yP
    arcpy.RefreshActiveView()


except:
    message = "\n*** PYTHON ERRORS *** "; showPyMessage()
    message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
    message = "Python Error Info: " +  str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()

Results:

enter image description here

enter image description here

Important settings of layout anchor point:

enter image description here

  • I don't think the center of data frame rotation is the center of page layout. Have you tested this solution? – Farid Cheraghi Sep 25 '15 at 0:18
  • Pictures above are tests' results. I tested on 0,30,60,90 – FelixIP Sep 25 '15 at 0:23
  • +1 This is what I had in mind. Thanks very much for this. Unfortunately, I won't have a chance to test this for several weeks as I will be at another office. But this looks like exactly what I want. I like that you used numpy as well. Can't wait to try it out. – Fezter Sep 25 '15 at 0:34
  • It needs a bit of clean-up, eg changing getCoeffs(df,angle) to getCoeffs(df). Nothing worked until I cheated with frame rotation, i.e. un-rotate it first and restore rotation. Good question, thank you – FelixIP Sep 25 '15 at 0:39
5

Here is a tested solution:

  1. Install comtypes and snippet102 (How do I access ArcObjects from Python?) with your python installation

  2. use the following python function (based on comtypes). Make sure ArcMap is open. It is tested with rotated dataframes.

Python code:

def MapCoord_2_PageCoord(mapX,mapY):
    from snippets102 import GetLibPath, InitStandalone, NewObj,CType
    from comtypes.client import GetModule, CreateObject

    import comtypes.gen.esriFramework as esriFramework
    import comtypes.gen.esriArcMapUI as esriArcMapUI
    import comtypes.gen.esriCarto as esriCarto

    m = GetModule(GetLibPath() + "esriGeometry.olb")
    #ptInRealCoords =(486408.414,3577354.986)
    ptInRealCoords = CreateObject(m.Point, interface=m.IPoint)
    ptInRealCoords.PutCoords(mapX,mapY)

    pApp = NewObj(esriFramework.AppROT, esriFramework.IAppROT).Item(0)
    pDoc = pApp.Document
    pMxDoc = CType(pDoc, esriArcMapUI.IMxDocument)

    mapActiveView = CType(pMxDoc.FocusMap,esriCarto.IActiveView)
    pageLayoutActiveView = CType(pMxDoc.PageLayout,esriCarto.IActiveView)


    pDisTrans = mapActiveView.ScreenDisplay.DisplayTransformation
    deviceX, deviceY = pDisTrans.FromMapPoint(ptInRealCoords)

    pDisTrans = pageLayoutActiveView.ScreenDisplay.DisplayTransformation
    pageX,pageY = pDisTrans.ToMapPoint(deviceX, deviceY).QueryCoords()

    print pageX,pageY


MapCoord_2_PageCoord(486408.414,3577354.986)
  • 1
    Thanks @Farid Cher, this looks promising. I have had a look at using ArcObjects in Python, and if I have to, I'll run with this. I'd prefer not to, however, as I don't want to have to install comtypes and snippets on all the machines that will be using the tool. I was hoping I could just use trigonometry. However, if that can't be done in arcpy, then I'll definitely use this solution. – Fezter Sep 23 '15 at 23:18
  • You are welcome. First I tried to write it in pure python but to no avail. The point is, I don't know when we apply rotation to data frame, what is the center of rotation. If we could calculate this point then it would be trivial to transform the page layout coords. – Farid Cheraghi Sep 23 '15 at 23:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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