Is there any way to modify a map's coordinate system in ArcGIS Pro using Python?
Done. It looked like I was the first vote. Can you vote for your own idea?
I'm trying to do the same thing - set the coordinate system of an ArcGIS Pro Map object using arcpy. Just downloaded ArcGIS Pro 2.2 and there still doesn't seem to be a way. Anybody come across any solutions / workarounds in the last couple of years?
It now appears that there is a "Camera" object associated to Map and MapFrame objects. Within the Camera class there is a getExtent() and setExtent() method that returns or sets and Extent object, which has a spatialReference property.
you can 'get' the spatial reference from a map in the project like this:
aprx = arcpy.mp.ArcGISProject("c:\esri\project.aprx")
maps = aprx.listMaps()
map = maps[0]
print(dir(map))
#...
print(dir(map.getDefinition("V2").spatialReference))
and, while you cannot 'set' the spatial reference using 'arcpy', you can with a few additional libraries:
import arcpy
import xml.etree.ElementTree as ET
import tempfile
import os
import shutil
from zipfile import ZipFile
print("setting spatial reference")
output_project = "MASTER"
out_dir = os.path.dirname(__file__)
new_aprx_path = os.path.join(out_dir, output_project + "_Project", output_project) + ".aprx"
tempDirMod = tempfile.mkdtemp()
print("tempDirMod:")
print(tempDirMod)
with ZipFile(new_aprx_path, 'r') as zipObj:
# Extract all the contents of aprx (zip file) in temporary directory
zipObj.extractall(tempDirMod)
aprx = arcpy.mp.ArcGISProject(new_aprx_path)
maps = aprx.listMaps()
for m in maps:
extracted_map_CIM_path = m.getDefinition("V2").uRI #i.e. 'CIMPATH=map11/map11.xml' --> "C:\admin\create_query_layers\MASTER_Project\MASTER\map11\map11.xml"
xml_path = extracted_map_CIM_path.split("=")[1]
this_map_xml = os.path.join(tempDirMod, xml_path)
tree = ET.parse(this_map_xml)
root = tree.getroot()
DefaultExtent = root.find("DefaultExtent")
Xmin = ET.SubElement(DefaultExtent, "XMin")
Xmin.text = "-180"
Ymin = ET.SubElement(DefaultExtent, "YMin")
Ymin.text = "-90"
Xmax = ET.SubElement(DefaultExtent, "XMax")
Xmax.text = "180"
Ymax = ET.SubElement(DefaultExtent, "YMax")
Ymax.text = "90"
SpatialReference = ET.SubElement(DefaultExtent, "SpatialReference")
SpatialReference.set("xsi:type", "typens:GeographicCoordinateSystem")
WKT = ET.SubElement(SpatialReference, "WKT")
WKT.text = r"GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433],AUTHORITY["EPSG",4326]]"
XOrigin = ET.SubElement(SpatialReference, "XOrigin")
XOrigin.text = "-400"
YOrigin = ET.SubElement(SpatialReference, "YOrigin")
YOrigin.text = "-400"
XYScale = ET.SubElement(SpatialReference, "XYScale")
XYScale.text = "999999999.99999988"
ZOrigin = ET.SubElement(SpatialReference, "ZOrigin")
ZOrigin.text = "-100000"
ZScale = ET.SubElement(SpatialReference, "ZScale")
ZScale.text = "10000"
MOrigin = ET.SubElement(SpatialReference, "MOrigin")
MOrigin.text = "-100000"
MScale = ET.SubElement(SpatialReference, "MScale")
MScale.text = "10000"
XYTolerance = ET.SubElement(SpatialReference, "XYTolerance")
XYTolerance.text = "8.983152841195215e-09"
ZTolerance = ET.SubElement(SpatialReference, "ZTolerance")
ZTolerance.text = "0.001"
MTolerance = ET.SubElement(SpatialReference, "MTolerance")
MTolerance.text = "0.001"
HighPrecision = ET.SubElement(SpatialReference, "HighPrecision")
HighPrecision.text = "true"
LeftLongitude = ET.SubElement(SpatialReference, "LeftLongitude")
LeftLongitude.text = "-180"
WKID = ET.SubElement(SpatialReference, "WKID")
WKID.text = "4326"
LatestWKID = ET.SubElement(SpatialReference, "LatestWKID")
LatestWKID.text = "4326"
#IMPORTANT NOTE: if you have no spatial reference in your map yet you will want to append a new Element to the xml (as below). Otherwise do as above with DefaultExtent where you would find the SpatialRefrence Node and overwrite existing data.
SpatialReference2 =ET.Element("SpatialReference")
SpatialReference2.set("xsi:type", "typens:GeographicCoordinateSystem")
WKT = ET.SubElement(SpatialReference2, "WKT")
WKT.text = r"GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433],AUTHORITY["EPSG",4326]]"
XOrigin = ET.SubElement(SpatialReference2, "XOrigin")
XOrigin.text = "-400"
YOrigin = ET.SubElement(SpatialReference2, "YOrigin")
YOrigin.text = "-400"
XYScale = ET.SubElement(SpatialReference2, "XYScale")
XYScale.text = "999999999.99999988"
ZOrigin = ET.SubElement(SpatialReference2, "ZOrigin")
ZOrigin.text = "-100000"
ZScale = ET.SubElement(SpatialReference2, "ZScale")
ZScale.text = "10000"
MOrigin = ET.SubElement(SpatialReference2, "MOrigin")
MOrigin.text = "-100000"
MScale = ET.SubElement(SpatialReference2, "MScale")
MScale.text = "10000"
XYTolerance = ET.SubElement(SpatialReference2, "XYTolerance")
XYTolerance.text = "8.983152841195215e-09"
ZTolerance = ET.SubElement(SpatialReference2, "ZTolerance")
ZTolerance.text = "0.001"
MTolerance = ET.SubElement(SpatialReference2, "MTolerance")
MTolerance.text = "0.001"
HighPrecision = ET.SubElement(SpatialReference2, "HighPrecision")
HighPrecision.text = "true"
LeftLongitude = ET.SubElement(SpatialReference2, "LeftLongitude")
LeftLongitude.text = "-180"
WKID = ET.SubElement(SpatialReference2, "WKID")
WKID.text = "4326"
LatestWKID = ET.SubElement(SpatialReference2, "LatestWKID")
LatestWKID.text = "4326"
root.append(SpatialReference2)
#convert xml byte string to string
new_xml = str(ET.tostring(root), 'utf-8')
#write xml over top old file
with open(this_map_xml, "w") as xmlW:
#xml 'wrangler' replaces stubborn escaping and quotation types
xmlW.write(new_xml.replace("&", "&").replace('"',"'"))
##Delete reference to aprx
del aprx
#rezip everything.
shutil.make_archive(os.path.join(out_dir, output_project + "_Project", output_project), "zip", tempDirMod)
new_aprx_path_with_sr = os.path.join(out_dir, output_project + "_Project", output_project + "_withSR") + ".aprx"
# rename the .zip file to .aprx
os.rename(os.path.join(out_dir, output_project + "_Project", output_project + ".zip"), new_aprx_path_with_sr)
#end set spatial ref
* i pulled this from a larger project i'm working on and it hasn't been tested in the above state and may need tweeks.
This is an old thread, but it led me to believe this wasn't possible for a long time. After looking over documentation, I was able to use arcpy to set the spatial reference on the map object.
Something like this works for me:
Thanks Ryan, your reply to an old thread saved my bacon!
Thanks for the answer Ryan. This is what my code looks like. Where DEM is the filepath for a layer you want your map to match CRS of.
aprx = arcpy.mp.ArcGISProject("CURRENT")
mapx = aprx.activeMap
mapx.spatialReference = arcpy.Describe(DEM).spatialReference