Arcpy Dataframe

5723
11
09-07-2011 06:09 PM
PatrickFischer1
New Contributor III
Hi everyone, i'm trying to make a script that does the following

Pulls the coordinates from the active dataframe and inputs them into a polygon for a preselected feature class. In addition populates certain attribute fields from data saved in the MXD such as scale and creation date. Also there are some other particulars in the fields that I want calculate such as Producer, Notes, Product Type, Country Code. I've taken a look at Dataframe Extent under Arcpy and was wondering if it was possible to pull the current extent from the active dataframe. Looking at the example code I made a theory of using the "Current" command to pull the coordinates.

df = arcpy.mapping.ListDataFrames(mxd)[0]
newExtent = df.extent
newExtent.XMin, newExtent.YMin = -180.0, -90.0
newExtent.XMax, newExtent.YMax = 180.0, 90.0
df.extent = newExtent


That's the example code I found located at http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/DataFrame/00s300000003000000/  Any help and advice and help is greatly appreciated.
Tags (2)
0 Kudos
11 Replies
MathewCoyle
Frequent Contributor
Creating a polygon is fairly simple.

mxd = arcpy.mapping.MapDocument("CURRENT")
df = arcpy.mapping.ListDataFrames(mxd,"Layers")[0]

extent = df.extent
array = arcpy.Array()

array.add(extent.lowerLeft)
array.add(extent.lowerRight)
array.add(extent.upperRight)
array.add(extent.upperLeft)
array.add(extent.lowerLeft)
 
polygon = arcpy.Polygon(array)
arcpy.CopyFeatures_management(polygon, r"C:\GIS\Default.gdb\polytest")


After that adding fields and inputting some map document properties shouldn't be hard, but I don't have an example of it handy. See http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/MapDocument/00s30000000n000000/
0 Kudos
deleted-user-1T_bOHag6M8d
Occasional Contributor
I have a mostly-completed project that makes polygons of the main dataframe of each MXD in a given folder and saves the MXD properties and layer information in a file geodatabase. You can take a look at my code at https://bitbucket.org/npeihl/mapindextoolv2/overview.

I apologize for lack of documentation. I haven't put it into production yet.
0 Kudos
George_ChandeepCorea
New Contributor III
Hi,

I've created a script to do what you need and it's attached. Using the same code structure you should be able to populate the extra fields that you want.

If you have any issues please tell me as I would like to improve the script.

best,
0 Kudos
PatrickFischer1
New Contributor III
I actually was able to work through most of this. I was going to do the fields later as i'm taking this one step at a time. Right now the newest thing I am trying to implement is being able to select which dataframe from the mxd you want to use. The reason for this is that the amount of mxd's i'm looking at 500+ have different dataframe names. Now i'm using arcpy.GetParameter(0) as i'm running this through ArcGIS and not from python so that it is more user friendly to people who do not know python coding. basically rough gist of script so far is:

import arcpy, os, sys

mxdin = acrpy.GetParameter(0)


mxd = arcpy.mapping.MapDocument(mxdin)
df = arcpy.mapping.ListDataFrames(mxd,"Layers")[0]

extent = df.extent
array = arcpy.Array()

array.add(extent.lowerLeft)
array.add(extent.lowerRight)
array.add(extent.upperRight)
array.add(extent.upperLeft)
array.add(extent.lowerLeft)
 
try:

  polygon = arcpy.Polygon(array)
  arcpy.CopyFeatures_management(polygon, r"C:\GIS\Default.gdb\polytest"

except:
  print "Failed to create polygon"


I've thought of a couple ways to do it, I haven't tried anything yet though. Some of my ideas were to put the list of dataframes into an array and have a parameter that lets the user select from a drop down list which dataframe to use. Ideas?
0 Kudos
PatrickFischer1
New Contributor III
Ok I now have a working script that does everything I wanted to do. Some things i've noticed while running this is hat calculate fields is particularly slow, is there a way to speed it up or another function I can use instead? I took a few things from corea's script, thank you btw it was a great help. I have thought about using the rows part but i'm unsure how to use that exactly. This whole thing has been a wonderful learning process for me and i'm happy I was able to get to where i'm at now, thank you everyone 🙂

Here is my script in its current form.

# Dataframe To Feature Class tool.
# Pulls the extent of the active dataframe in an mxd, and fills out fields based on input values
# from the user.
# Author:  LCpl Patrick Fischer
# Riff.Ibanezius@gmail.com
# 3D Topo Plt, 3D Intel BN, Camp Hansen Okinawa, Japan

import arcpy, os, sys

# Deletes feature class from previous time the script was ran.
arcpy.Delete_management(r"Z:\Training\Python\test_scripts\Extent_map.gdb\polygon")

# Collect Parameters from User input

mxdin = arcpy.GetParameterAsText(0)

mxd = arcpy.mapping.MapDocument(mxdin)

df = arcpy.mapping.ListDataFrames(mxd, "La*") [0] # select main dataframe not location diagram


ext = df.extent
array = arcpy.Array()

array.add(ext.lowerLeft)
array.add(ext.lowerRight)
array.add(ext.upperRight)
array.add(ext.upperLeft)
array.add(ext.lowerLeft)

polygon = arcpy.Polygon(array, df.spatialReference)

arcpy.AddMessage("Extent has successfully been converted to a polygon")


#Checks spatial reference from the dataframe to see if it needs to be transformed into another projection.

if df.spatialReference == "WGS 1984":
    arcpy.Project_management(polygon, r"Z:\Training\Python\test_scripts\Extent_Map.gdb\polygon", "C:\Program Files\ArcGIS\Desktop10.0\Coordinate Systems\Geographic Coordinate Systems\World\WGS 1984.prj")

else:
    arcpy.CopyFeatures_management(polygon, r"Z:\Training\Python\test_scripts\Extent_Map.gdb\polygon")
    print 'Already projected into WGS 1984' #change to message box

arcpy.AddMessage("Successfuly projected into WGS 1984")
polypro = r"Z:\Training\Python\test_scripts\Extent_Map.gdb\polygon"

#add fields to new feature class

arcpy.AddField_management(polypro, "PRODUCT_ID", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "PRODUCT_DATE", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "SCALE", "FLOAT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "EDITION", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "CLASSIFICATION", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "TYPE", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "PRODUCER", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "COUNTRY_CODE", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "NOTES", "TEXT", "", "", 250, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "PDF_PATH", "TEXT", "", "", 250, "", "NULLABLE", "REQUIRED")

#Set parameters for user input

PROID = arcpy.GetParameterAsText(1)
PRODA = arcpy.GetParameterAsText(2)
ED = arcpy.GetParameterAsText(3)
CLA = arcpy.GetParameterAsText(4)
TYP = arcpy.GetParameterAsText(5)
PROD = arcpy.GetParameterAsText(6)
CC = arcpy.GetParameterAsText(7)
NOTES = arcpy.GetParameterAsText(8)
PDF = arcpy.GetParameterAsText(9)

arcpy.AddMessage("Calculating fields based on input values")

#Calculate Fields based on user input
for el in arcpy.mapping.ListLayoutElements(mxd, "DATAFRAME_ELEMENT"):
    SCALE = el.scale
    arcpy.CalculateField_management(polypro, "PRODUCT_ID", PROID, "", "")
    arcpy.CalculateField_management(polypro, "PRODUCT_DATE", PRODA, "", "")
    arcpy.CalculateField_management(polypro, "SCALE", SCALE, "", "")
    arcpy.CalculateField_management(polypro, "EDITION", ED, "", "")
    arcpy.CalculateField_management(polypro, "CLASSIFICATION", CLA, "", "")
    arcpy.CalculateField_management(polypro, "TYPE", TYP, "", "")
    arcpy.CalculateField_management(polypro, "PRODUCER", PROD, "", "") 
    arcpy.CalculateField_management(polypro, "COUNTRY_CODE", CC, "", "")
    arcpy.CalculateField_management(polypro, "NOTES", NOTES, "", "")
    arcpy.CalculateField_management(polypro, "PDF_PATH", PDF, "", "")

arcpy.AddMessage("Succesfully calculated fields, appending to Topo Products feature class.")

Feature = arcpy.GetParameterAsText(10)

arcpy.Append_management(polypro, Feature ", "NO_TEST", "", "")



Also sometimes i'll get an error about list is out of range, on one mxd it was due to what I think was to many data frames (around 50), but it happened again on another with just 2 data frames. I've ran this successfully with mxds with up to 5 data frames with no issues. Is this an anomaly or is something seriously wrong?
0 Kudos
MathewCoyle
Frequent Contributor
I find update cursor to be faster than calculate field in most operations.

Example
rows = arcpy.UpdateCursor(layer)
for row in rows:
    row.values = 1
    rows.updateRow(row)


For more detail see
http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//000v0000003m000000
0 Kudos
deleted-user-1T_bOHag6M8d
Occasional Contributor
Ok I now have a working script that does everything I wanted to do. Some things i've noticed while running this is hat calculate fields is particularly slow, is there a way to speed it up or another function I can use instead? I took a few things from corea's script, thank you btw it was a great help. I have thought about using the rows part but i'm unsure how to use that exactly. This whole thing has been a wonderful learning process for me and i'm happy I was able to get to where i'm at now, thank you everyone 🙂

Here is my script in its current form.

# Dataframe To Feature Class tool.
# Pulls the extent of the active dataframe in an mxd, and fills out fields based on input values
# from the user.
# Author:  LCpl Patrick Fischer
# Riff.Ibanezius@gmail.com
# 3D Topo Plt, 3D Intel BN, Camp Hansen Okinawa, Japan

import arcpy, os, sys

# Deletes feature class from previous time the script was ran.
arcpy.Delete_management(r"Z:\Training\Python\test_scripts\Extent_map.gdb\polygon")

# Collect Parameters from User input

mxdin = arcpy.GetParameterAsText(0)

mxd = arcpy.mapping.MapDocument(mxdin)

df = arcpy.mapping.ListDataFrames(mxd, "La*") [0] # select main dataframe not location diagram


ext = df.extent
array = arcpy.Array()

array.add(ext.lowerLeft)
array.add(ext.lowerRight)
array.add(ext.upperRight)
array.add(ext.upperLeft)
array.add(ext.lowerLeft)

polygon = arcpy.Polygon(array, df.spatialReference)

arcpy.AddMessage("Extent has successfully been converted to a polygon")


#Checks spatial reference from the dataframe to see if it needs to be transformed into another projection.

if df.spatialReference == "WGS 1984":
    arcpy.Project_management(polygon, r"Z:\Training\Python\test_scripts\Extent_Map.gdb\polygon", "C:\Program Files\ArcGIS\Desktop10.0\Coordinate Systems\Geographic Coordinate Systems\World\WGS 1984.prj")

else:
    arcpy.CopyFeatures_management(polygon, r"Z:\Training\Python\test_scripts\Extent_Map.gdb\polygon")
    print 'Already projected into WGS 1984' #change to message box

arcpy.AddMessage("Successfuly projected into WGS 1984")
polypro = r"Z:\Training\Python\test_scripts\Extent_Map.gdb\polygon"

#add fields to new feature class

arcpy.AddField_management(polypro, "PRODUCT_ID", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "PRODUCT_DATE", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "SCALE", "FLOAT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "EDITION", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "CLASSIFICATION", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "TYPE", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "PRODUCER", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "COUNTRY_CODE", "TEXT", "", "", 50, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "NOTES", "TEXT", "", "", 250, "", "NULLABLE", "REQUIRED")
arcpy.AddField_management(polypro, "PDF_PATH", "TEXT", "", "", 250, "", "NULLABLE", "REQUIRED")

#Set parameters for user input

PROID = arcpy.GetParameterAsText(1)
PRODA = arcpy.GetParameterAsText(2)
ED = arcpy.GetParameterAsText(3)
CLA = arcpy.GetParameterAsText(4)
TYP = arcpy.GetParameterAsText(5)
PROD = arcpy.GetParameterAsText(6)
CC = arcpy.GetParameterAsText(7)
NOTES = arcpy.GetParameterAsText(8)
PDF = arcpy.GetParameterAsText(9)

arcpy.AddMessage("Calculating fields based on input values")

#Calculate Fields based on user input
for el in arcpy.mapping.ListLayoutElements(mxd, "DATAFRAME_ELEMENT"):
    SCALE = el.scale
    arcpy.CalculateField_management(polypro, "PRODUCT_ID", PROID, "", "")
    arcpy.CalculateField_management(polypro, "PRODUCT_DATE", PRODA, "", "")
    arcpy.CalculateField_management(polypro, "SCALE", SCALE, "", "")
    arcpy.CalculateField_management(polypro, "EDITION", ED, "", "")
    arcpy.CalculateField_management(polypro, "CLASSIFICATION", CLA, "", "")
    arcpy.CalculateField_management(polypro, "TYPE", TYP, "", "")
    arcpy.CalculateField_management(polypro, "PRODUCER", PROD, "", "") 
    arcpy.CalculateField_management(polypro, "COUNTRY_CODE", CC, "", "")
    arcpy.CalculateField_management(polypro, "NOTES", NOTES, "", "")
    arcpy.CalculateField_management(polypro, "PDF_PATH", PDF, "", "")

arcpy.AddMessage("Succesfully calculated fields, appending to Topo Products feature class.")

Feature = arcpy.GetParameterAsText(10)

arcpy.Append_management(polypro, Feature ", "NO_TEST", "", "")



Also sometimes i'll get an error about list is out of range, on one mxd it was due to what I think was to many data frames (around 50), but it happened again on another with just 2 data frames. I've ran this successfully with mxds with up to 5 data frames with no issues. Is this an anomaly or is something seriously wrong?


I agree with Matthew that you should use a cursor instead of Calculating Fields. An Insert Cursor should work nicely for you.

Also, the "list out of range" error may be due to no Dataframes in the MXD that start with "La" as you specify when you are creating the "df" variable. If ArcPy can't find any dataframes in the MXD that start with "La" then it creates an empty list. Calling the first index "[0]" on an empty list returns the out of range error.
0 Kudos
PatrickFischer1
New Contributor III
I agree with Matthew that you should use a cursor instead of Calculating Fields. An Insert Cursor should work nicely for you.

Also, the "list out of range" error may be due to no Dataframes in the MXD that start with "La" as you specify when you are creating the "df" variable. If ArcPy can't find any dataframes in the MXD that start with "La" then it creates an empty list. Calling the first index "[0]" on an empty list returns the out of range error.


So i used cursor and rows and found it much more to my advantage. Works quite nicely. Still want to know how to put the list of dataframes into a list you can select from in arcCatalog.
0 Kudos
MathewCoyle
Frequent Contributor
Still want to know how to put the list of dataframes into a list you can select from in arcCatalog.


Not sure I quite understand what you are looking for. You mean just a table of the data frame names?
0 Kudos