Modify map coordinate system with arcpy.mp?

6576
16
10-31-2016 08:31 AM
BryanChastain
New Contributor III

Is there any way to modify a map's coordinate system in ArcGIS Pro using Python?

0 Kudos
16 Replies
JoshuaBixby
MVP Esteemed Contributor

Done.  It looked like I was the first vote.  Can you vote for your own idea?

0 Kudos
KeithMiller4
New Contributor III

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?

0 Kudos
DavidClark1
New Contributor II

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.

0 Kudos
MaxSquires
Occasional Contributor

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.

0 Kudos
RyanDavis1
Occasional Contributor

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:

mapx.spatialReference = arcpy.SpatialReference(prjFile)
 
where mapx is a map object.  Hope that helps someone.
DaveTaylor011
New Contributor II

Thanks Ryan, your reply to an old thread saved my bacon!

0 Kudos
ArtK
by
New Contributor III

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

0 Kudos