Converting Map Coordinates to Layout Coordinates in rotated Dataframe?
Here is a tested solution:
Install comtypes and snippet102 (How do I access ArcObjects from Python?) with your python installation
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)
Original layout:
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:
Important settings of layout anchor point: