Trying to export a series of layouts with different definition queries and extent with arcpy

992
2
Jump to solution
02-20-2023 03:30 PM
TeaganMulford
New Contributor

I'm on ArcGIS Pro (self-taught) and I am trying to make a batch of layouts for different species occurrence records over the same extent. I have all the XY to Point data as a layer and have been using the display filter to limit which species is shown, then manually exporting the layout, and changing the species again. All other factors are the same, save the species. I want to automate this since I have 80 or so to do (and do this often). Using Map series hasn't worked, since the extent always changes, so I thought I would attempt with arcpy since I know a little bit about python...

Ideally, I want to create a layout for each species, with the same extent, layers, etc, but with a different species selected from the XY to Point layer. I then want to export the layout with the name of the species selected.

This is the code I have so far, and it all seems to work (i.e. it exports a pdf for each, with the layers I can see looking good, and runs without errors) but it has an odd extent, off to the right of the continental U.S., and a North arrow that is not in the layout I am calling. I got the extent values from the extent on the formatted layout/mapframe by looking in properties and copying the values there. Is there a way to edit the extent of the layout?

import arcpy, os

#Project path
aprx = arcpy.mp.ArcGISProject(
    r"pathtoproject.aprx")

# Set the name of the XY to Point table
table_name = "ScioSpecies"

# Set the name of the field that contains the class names
class_field = "Species"

#Set a reference to the map view in my project
map_view = aprx.listMaps()[0]


# Get a reference to the layout
layout = aprx.listLayouts()[0]

#Setting up layout/mapframe
map_frame = layout.listElements("MAPFRAME_ELEMENT")[0]
extent = arcpy.Extent(5331425.860609497, -12839586.820429197, -12017230.660916878, 4267200.242417085)
map_frame.camera.setExtent(extent)

class_list = []
with arcpy.da.SearchCursor(table_name, class_field) as cursor:
    for row in cursor:
        if row[0] not in class_list:
            class_list.append(row[0])
#Verify all species are present
print(class_list)

for species in class_list:
    arcpy.SelectLayerByAttribute_management(table_name, "NEW_SELECTION", "Species = '{}'".format(species))
    layout.exportToJPEG(
        r"pathtosavefile{}.jpg".format(species),
        resolution=800)

 

1 Solution

Accepted Solutions
TeaganMulford
New Contributor

Thank you! This led me to the solution, and although I don't need the text box now, thank you for showing me how to do it! 

Here's what I ended up doing.

#Project path
aprx = arcpy.mp.ArcGISProject(
    r"projectpath.aprx")


# Set the name of the field that contains the class names
class_field = "Species"

# Set Map View and Layout and Map Frame
map_view = aprx.listMaps("Map")[0]
layout = aprx.listLayouts("Layout2")[0]
map_frame = layout.listElements("MAPFRAME_ELEMENT")[0]

# Set species layer
species_lyr = map_view.listLayers("ScioSpecies")[0]

# Set shapefile polygon to custom extent
customextent = map_view.listLayers("customextent")[0]

# Set output
output_folder = output path

#clear out all the existing definitionqueries
species_lyr.updateDefinitionQueries([])


# Grab each species, and make sure all are present
class_list = []
with arcpy.da.SearchCursor(species_lyr, class_field) as cursor:
    for row in cursor:
        if row[0] not in class_list:
            class_list.append(row[0])

print(class_list)


#set the extent based on the species layer 
map_frame.camera.setExtent(map_frame.getLayerExtent(customextent, False, True))

#Loop for each species
for species in class_list:
    species_lyr.definitionQuery = "{0} = '{1}'".format(class_field,species)
    outfile = "{0}\\{1}.pdf".format(output_folder,species)
    layout.exportToJPEG(
        exportfolder".format(species),
        resolution=900)
    print("Successful export of ", species)

 I'm sure it's not the prettiest code, but it got the output I wanted, having the custom rectangle to define extent really helped to standardize all of them.  

View solution in original post

0 Kudos
2 Replies
dslamb2022
New Contributor III

Since your headline asks about definition queries I'll add to your code for that. If you aren't getting the layout you expect, you might want to use the wildcard feature in the listLayouts function to find the name of the layout. If the extent doesn't change on the layout between exports, then you probably don't need to change it. Or, you can get the layer's extent and set the camera to that.

 

map_view = aprx.listMaps("SpeciesMapName")[0]
layout = aprx.listLayouts("SpeciesLayoutName")[0]
map_frame = layout.listElements("MAPFRAME_ELEMENT")[0]
species_lyr = map_view.listLayers("ScioSpecies")[0]
#you can have a text box in your layout with a name, and change it to #species name
species_txt = None
for txt in layout.listElements("TEXT_ELEMENT"):
    if txt.name == "SpeciesName":
        species_txt = txt
        break
class_list = [row[0] for row in arcpy.da.SearchCursor(species_lyr,class_field)]
class_list = set(class_list)
#clear out all the existing definitionqueries
species_lyr.updateDefinitionQueries([])
for species in class_list:
    if species_txt is not None:
        species_txt.text = species
    species_lyr.definitionQuery = "{0} = '{1}'".format(class_field,species)
    #set the extent based on the species layer 
    map_frame.camera.setExtent(map_frame.getLayerExtent(species_lyr, False, True))
    #map_frame.camera.scale = scale_value
    outfile = "{0}\\{1}.pdf".format(output_folder,species)
    layout.exportToPDF(outfile, 300, 'BEST',output_as_image=True)
    time.sleep(1)

 

TeaganMulford
New Contributor

Thank you! This led me to the solution, and although I don't need the text box now, thank you for showing me how to do it! 

Here's what I ended up doing.

#Project path
aprx = arcpy.mp.ArcGISProject(
    r"projectpath.aprx")


# Set the name of the field that contains the class names
class_field = "Species"

# Set Map View and Layout and Map Frame
map_view = aprx.listMaps("Map")[0]
layout = aprx.listLayouts("Layout2")[0]
map_frame = layout.listElements("MAPFRAME_ELEMENT")[0]

# Set species layer
species_lyr = map_view.listLayers("ScioSpecies")[0]

# Set shapefile polygon to custom extent
customextent = map_view.listLayers("customextent")[0]

# Set output
output_folder = output path

#clear out all the existing definitionqueries
species_lyr.updateDefinitionQueries([])


# Grab each species, and make sure all are present
class_list = []
with arcpy.da.SearchCursor(species_lyr, class_field) as cursor:
    for row in cursor:
        if row[0] not in class_list:
            class_list.append(row[0])

print(class_list)


#set the extent based on the species layer 
map_frame.camera.setExtent(map_frame.getLayerExtent(customextent, False, True))

#Loop for each species
for species in class_list:
    species_lyr.definitionQuery = "{0} = '{1}'".format(class_field,species)
    outfile = "{0}\\{1}.pdf".format(output_folder,species)
    layout.exportToJPEG(
        exportfolder".format(species),
        resolution=900)
    print("Successful export of ", species)

 I'm sure it's not the prettiest code, but it got the output I wanted, having the custom rectangle to define extent really helped to standardize all of them.  

0 Kudos