Select to view content in your preferred language

Automating layout extent fail on one map

88
2
Sunday
DominicRobergeIADOT
Frequent Contributor

Hello,

I created a script that loop through 3 maps, update a definition query based on a parameter then change the extent of the layout and export the layout to PDF. It's "kind of working" however, every time I run the process ONE map (never the same) get stuck on the extent of the previous selection. Below is the code and the details info the process.

Weird thing is if I look in all 3 maps, the query definition has been updated...

import arcpy
import os
import sys
from arcgis import GIS
from datetime import datetime

# Get today's date
today = datetime.today()

formatted_date = today.strftime("%m%d%Y")

#********************************************************************************************

def GRMapExtent(MapName,LayerName,FieldNumber,FieldName, LayoutName):
    map_name = MapName  
    arcpy.AddMessage("         " +map_name)
    layer_name = LayerName  
    map_frame_name = 'Map Frame'  

    # Access the map
    map_obj = aprx.listMaps(map_name)[0]

    # Get the layer
    layer = map_obj.listLayers(layer_name)[0]

    # Use arcpy.Describe to get extent
    desc = arcpy.Describe(layer)
    layer_extent = desc.extent

    count_result = arcpy.management.GetCount(layer)
    record_count = int(count_result[0])
    arcpy.AddMessage("         number of records: " + str(record_count))

        # Access the layout and map frame
    layout = aprx.listLayouts(LayoutName)[0]  # or specify layout by name: aprx.listLayouts("LayoutName")[0]
    map_frame = layout.listElements("mapframe_element", map_frame_name)[0]
    
    cursor = arcpy.da.SearchCursor(layer, ['SHAPE@',FieldNumber,FieldName]) 
    arcpy.AddMessage("*****************")
    for c in cursor:
        arcpy.AddMessage(u'         {0},{1}'.format(c[1],c[2]))
        strName = c[2]
        arcpy.AddMessage("         Final Name: " + str(strName))
        extent = c[0].extent
        paddingFirst = extent.XMax-extent.XMin
        padding = (float(paddingFirst)/float(20))
        new_extent=arcpy.Extent(extent.XMin-padding,extent.YMin-padding,extent.XMax+padding,extent.YMax+padding,None,None,None,None,extent.spatialReference)

        # Set the map frame extent to the layer extent
        map_frame.camera.setExtent(new_extent)    
        arcpy.AddMessage("         " +"Mainframe extent done")

        GRLayoutTitle(SAGFieldNunber + " : "+strName+ " "+ l)
        arcpy.AddMessage("         " +"Title update")
        GRExportLayouttoPDF(template_name,strName,formatted_date)
        arcpy.AddMessage("         " +"Export to PDF done")
    #sys.exit(0)

def GRLayoutTitle(TitleName):
    elm_name = "SAG Title" # the name you assign to the title (TEXT) element
    p = arcpy.mp.ArcGISProject("CURRENT")
    for lyt in p.listLayouts(): # get the element
        for elm in lyt.listElements("TEXT_ELEMENT"):
            if elm.name == elm_name:
                elm.text = TitleName

def GRExportLayouttoPDF(layoutName,FieldName, strDate):
    layout_name = layoutName  # Name of the layout in your project
    output_folder= r"C:\GIS\OUTPUT_PDF"  
    output_name = layoutName+"_"+FieldName+"_"+strDate+".pdf"
    layout = aprx.listLayouts(layout_name)[0]
    layout.exportToPDF(output_folder+"\\"+output_name, resolution=200)

#********************************************************************************************

arcpy.AddMessage("Let's update the Definition queries")
aprx = arcpy.mp.ArcGISProject("CURRENT")
LyrName = arcpy.GetParameterAsText(0)  
FieldName = arcpy.GetParameterAsText(1)
name_field = 'SAG_FieldNumber'  #'SAG_SiteName'
SAGFieldNunber = arcpy.GetParameterAsText(2)
SAGFieldName = 'SAG_FieldName'
listMaps = ['2021 Ortho','2023 Ortho','LIDAR']  
for l in listMaps:
    arcpy.AddMessage(l + "-------------------------------------------")
    NewMapName = "SAG_Manure_Map_"+l
    template_name = "SAG_Manure_Layout_"+l
    newDefinitionQueryString = "SAG_FieldNumber = "+SAGFieldNunber      

    arcpy.AddMessage(newDefinitionQueryString)
    m= aprx.listMaps(NewMapName)[0]   
    arcpy.AddMessage(NewMapName)
    for lyr in m.listLayers():
        arcpy.AddMessage(lyr.name)
        if lyr.name ==LyrName:                                  
            arcpy.AddMessage("We found our layer to update")
            if lyr.supports('DefinitionQuery'):
                arcpy.AddMessage("here we go")

                # Updade Definition query
                
                dql = lyr.listDefinitionQueries()
                arcpy.AddMessage("original dql" + str(dql))
                for dq in dql:
                    arcpy.AddMessage("in dq")
                    dq['sql'] = newDefinitionQueryString
                lyr.updateDefinitionQueries(dql)
                arcpy.AddMessage("revised dql" + str(dql))

                
            count_result = arcpy.management.GetCount(lyr)
            record_count = int(count_result[0])
            arcpy.AddMessage("number of records: " + str(record_count))

    arcpy.AddMessage("Now let's change the extent of the map")
    GRMapExtent(NewMapName, LyrName,name_field,SAGFieldName,template_name)


arcpy.AddMessage("------------------------") 
arcpy.AddMessage("Definition query updated")   

 

This is the details from the proces

DominicRobergeIADOT_0-1752450689098.png

 

 I looked at this for too long:(

Any help would be much appreciated

0 Kudos
2 Replies
TonyAlmeida
MVP Regular Contributor

Try adding a delay between operations. Also try adding a clear election before export.

def GRMapExtent(MapName, LayerName, FieldNumber, FieldName, LayoutName):
    map_name = MapName  
    arcpy.AddMessage("         " + map_name)
    layer_name = LayerName  
    map_frame_name = 'Map Frame'  

    # Access the map
    map_obj = aprx.listMaps(map_name)[0]
    
    # Clear any existing selection
    for lyr in map_obj.listLayers():
        if lyr.isFeatureLayer:
            lyr.setSelectionSet(None)

    # Get the layer
    layer = map_obj.listLayers(layer_name)[0]
    
    # Refresh the map and layout
    aprx.save()
    time.sleep(1)  # Small delay

 

0 Kudos
DominicRobergeIADOT
Frequent Contributor

Thanks @TonyAlmeida but that didn't solved my issue. I also tried to create a function just for the query definition that didn't help either.

 

So I ended up splitting the code into 2 scripts: Step 1 create the query definition, Step2 update the layouts and PDF. Using a Mode Builder I can run both scripts at the same time and no issue.

I would love to get the code to run into 1 script but whatever works for now.

Thanks!

 

DominicRobergeIADOT_0-1752549553112.png

below was my revised code with the definition query function:

import arcpy
import os
import sys
from arcgis import GIS
from datetime import datetime

# Get today's date
today = datetime.today()

formatted_date = today.strftime("%m%d%Y")

#********************************************************************************************

def GRDefinitionQuery(MapName,LayerName,FieldNumber,LayoutName):
    newDefinitionQueryString = "SAG_FieldNumber = "+FieldNumber      
    arcpy.AddMessage(newDefinitionQueryString)
    
    m= aprx.listMaps(MapName)[0]   
    arcpy.AddMessage(MapName)
    
    for lyr in m.listLayers():
        arcpy.AddMessage(lyr.name)
        if lyr.name ==LayerName:                                  
            arcpy.AddMessage("We found our layer to update")
            if lyr.supports('DefinitionQuery'):
                arcpy.AddMessage("here we go")

                # Updade Definition query
                dql = lyr.listDefinitionQueries()
                arcpy.AddMessage("original dql" + str(dql))
                for dq in dql:
                    arcpy.AddMessage("in dq")
                    dq['sql'] = newDefinitionQueryString
                lyr.updateDefinitionQueries(dql)
                arcpy.AddMessage("revised dql" + str(dql))
            count_result = arcpy.management.GetCount(lyr)
            record_count = int(count_result[0])
            arcpy.AddMessage("number of records: " + str(record_count))
            break
    aprx.save()
    time.sleep(5)  # Small delay

def GRMapExtent(MapName,LayerName,FieldNumber,FieldName, LayoutName):
    map_name = MapName  
    arcpy.AddMessage("         " +map_name)
    layer_name = LayerName  
    map_frame_name = 'Map Frame'  

    # Access the map
    map_obj = aprx.listMaps(map_name)[0]

    # Clear any existing selection
    for lyr in map_obj.listLayers():
        if lyr.isFeatureLayer:
            lyr.setSelectionSet(None)

    # Get the layer
    layer = map_obj.listLayers(layer_name)[0]

    # Use arcpy.Describe to get extent
    desc = arcpy.Describe(layer)
    layer_extent = desc.extent

    count_result = arcpy.management.GetCount(layer)
    record_count = int(count_result[0])
    arcpy.AddMessage("         number of records: " + str(record_count))

        # Access the layout and map frame
    layout = aprx.listLayouts(LayoutName)[0]  # or specify layout by name: aprx.listLayouts("LayoutName")[0]
    map_frame = layout.listElements("mapframe_element", map_frame_name)[0]
    
    cursor = arcpy.da.SearchCursor(layer, ['SHAPE@',FieldNumber,FieldName]) 
    arcpy.AddMessage("*****************")
    for c in cursor:
        arcpy.AddMessage(u'         {0},{1}'.format(c[1],c[2]))
        strName = c[2]
        arcpy.AddMessage("         Final Name: " + str(strName))
        extent = c[0].extent
        paddingFirst = extent.XMax-extent.XMin
        padding = (float(paddingFirst)/float(20))
        new_extent=arcpy.Extent(extent.XMin-padding,extent.YMin-padding,extent.XMax+padding,extent.YMax+padding,None,None,None,None,extent.spatialReference)

        # Set the map frame extent to the layer extent
        map_frame.camera.setExtent(new_extent)    
        arcpy.AddMessage("         " +"Mainframe extent done")

        GRLayoutTitle(SAGFieldNunber + " : "+strName+ " "+ l)
        arcpy.AddMessage("         " +"Title update")
        GRExportLayouttoPDF(template_name,strName,formatted_date)
        arcpy.AddMessage("         " +"Export to PDF done")
    #sys.exit(0)

def GRLayoutTitle(TitleName):
    elm_name = "SAG Title" # the name you assign to the title (TEXT) element
    p = arcpy.mp.ArcGISProject("CURRENT")
    for lyt in p.listLayouts(): # get the element
        for elm in lyt.listElements("TEXT_ELEMENT"):
            if elm.name == elm_name:
                elm.text = TitleName

def GRExportLayouttoPDF(layoutName,FieldName, strDate):
    layout_name = layoutName  # Name of the layout in your project
    output_folder= r"C:\temp"  
    output_name = layoutName+"_"+FieldName+"_"+strDate+".pdf"
    layout = aprx.listLayouts(layout_name)[0]
    layout.exportToPDF(output_folder+"\\"+output_name, resolution=150)  #,jpeg_compression_quality=80, output_as_image=True,compress_vector_graphics=True

#********************************************************************************************

arcpy.AddMessage("Let's update the Definition queries")
aprx = arcpy.mp.ArcGISProject("CURRENT")
LyrName = arcpy.GetParameterAsText(0)  
FieldName = arcpy.GetParameterAsText(1)
name_field = 'SAG_FieldNumber'  #'SAG_SiteName'
SAGFieldNunber = arcpy.GetParameterAsText(2)
SAGFieldName = 'SAG_FieldName'
listMaps = ['2021 Ortho','2023 Ortho','LIDAR']

for l in listMaps:

    arcpy.AddMessage(l + "-------------------------------------------")
    NewMapName = "SAG_Manure_Map_"+l
    template_name = "SAG_Manure_Layout_"+l

    arcpy.AddMessage("Now let's change the Query Definituon")
    GRDefinitionQuery(NewMapName,LyrName, SAGFieldNunber,template_name)

    arcpy.AddMessage("Now let's change the extent of the map")
    GRMapExtent(NewMapName, LyrName,name_field,SAGFieldName,template_name)




arcpy.AddMessage("------------------------") 
arcpy.AddMessage("Definition query updated")   
0 Kudos