[GIS] Setting ArcMap data frame extent with ArcPy

arcgis-10.4arcmaparcpyextents

I am currently working on a Python script (v2.7) to automatically update/adjust an ArcMap (v10.4.1) MXD file, including adding several layers and adjusting the data frame extent. The code is running without any documented errors and completes successfully, however I'm experiencing a strange issue with setting the data frame extent just before saving the final map.

I have based my code on the ArcGIS documentation found here, with the relevant code extracts shown below. At present, the new extent is not saving within the MXD document, instead rendering a 'global' extent when the final MXD document is loaded within ArcMap (the extent is large enough to encompass all layers). What is really confusing is that I have added a few print statements within the code to check the extent values before and after being set, and these are all returning the correct values (i.e. according to ArcPy, the extent is being set correctly). All other modifications to the MXD (e.g. layers, symbology, text annotations etc.) are also saving correctly.

Python Code:

# Setup the MXD document:
mxd = arcpy.mapping.MapDocument(mxd_output_path)
data_frame = arcpy.mapping.ListDataFrames(mxd, "Monitoring")[0] #only one data frame in the MXD file.

# Calculate and print the default MXD data frame extent:
print 'Extent check 1:'
newExtent = data_frame.extent
print newExtent.XMin, newExtent.YMin, newExtent.XMax, newExtent.YMax

# [Remove irrelevant layers here]
# [Add new layers here]
mxd.save()
# [Update legend here]
mxd.save()
# [Update layer symbology here]
mxd.save()
# [Update text annotations here]
mxd.save()

# Calculate and print the current MXD data frame extent now that layers have been added/removed:
newExtent = data_frame.extent
print 'Extent check 2:'
print newExtent.XMin, newExtent.YMin, newExtent.XMax, newExtent.YMax

# Print the desired MXD extent (to check values are correct):
print 'Desired MXD Extent:'
print mxd_extent

# Set the new desired extent:
newExtent.XMin, newExtent.YMin = int(mxd_extent[0]), int(mxd_extent[1])
newExtent.XMax, newExtent.YMax = int(mxd_extent[2]), int(mxd_extent[3])
data_frame.extent = newExtent

# Now check the MXD extent again to ensure the values have been set correctly:
newExtent = data_frame.extent
print 'Updated Extent:'
print newExtent.XMin, newExtent.YMin, newExtent.XMax, newExtent.YMax

mxd.save()

sys.exit()

Output:

Extent check 1:
1416032.76389 6813235.09719 1469048.16389 6844138.89719  # Default extent of the initial MXD data frame.

Extent check 2:
1213148.14815 6688750.0 1636851.85185 6936250.0  # Extent of the initial MXD data frame after adding desired layers (a global extent to cover all layers). This is the extent rendered by ArcMap when loading the final saved MXD. 

Desired MXD Extent:
[1461338.0, 6811715.394055312, 1471338.0, 6817544.605944688]  # Desired extent values.

Updated Extent:
1461338.0 6811708.82692 1471338.0 6817550.17308  # Data frame extent values according to ArcPy after being updated (values are correct).

Final extent within ArcMap 10.4.1:

XMin: 1213148.148148148 m
YMin: 6689007.066639897 m
XMax: 1636851.851851852 m
YMax: 6935992.933360104 m

# Final extent is still the automatic 'global' extent for all layers (see Extent check 2).

Can anyone see if I've missed anything in the process for saving the desired extent to the MXD document?

Best Answer

As commented by @FelixIP:

I had no trouble changing extent after using

newExt=arcpy.Extent(ext.XMin-100,ext.YMin-100,ext.XMax-100,ext.YMax-100)

df.extent=newExt

There is something interesting about aspect ratio

and:

You missed "A copy of the Extent object must be made before modifying its properties" from help

The help being referred to is for DataFrame where it says:

A copy of the Extent object must be made before modifying its properties. The modified copy is then used to set the new extent properties. Note: If you try to set the extent by simply referencing the Extent object, changes won't be saved. For example, df.extent.xMin = some value won't work.

Related Question