# Converting Map Coordinates to Layout Coordinates in rotated Dataframe?

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.

Original layout:

Script:

``````import arcpy, os, traceback, sys,time
import numpy as np

try:
def showPyMessage():
arcpy.AddMessage(str(time.ctime()) + " - " + message)
def Rotate(xM,yM,angle,xc,yc):
x=xM-xc;y=yM-yc
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:

Important settings of layout anchor point:

• I don't think the center of data frame rotation is the center of page layout. Have you tested this solution? Sep 25, 2015 at 0:18
• Pictures above are tests' results. I tested on 0,30,60,90 Sep 25, 2015 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, 2015 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 Sep 25, 2015 at 0:39

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)
``````
• 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, 2015 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. Sep 23, 2015 at 23:37