list map name that is reference to a layout in arcgis pro project

1245
9
Jump to solution
12-19-2022 11:12 AM
BarakGarty
New Contributor II

I have a arcgis pro project that has 3 layouts each is references (linked or whatever the terminology may be) to one of the 3 maps that this project also have.

I tried to write code that uses a for loop to loop over the layout names and over the map name that associated to each layout. code below.

However i am able to get a list of all layouts and print that list of strings (keysList) but the map names that link to them is not returning. I read there a MapFrame element within a layout object that to my understanding contains the map name (among other elements, but I don't find how to call it and loop over it to access this attribute.

 

Any help is appriciates.

 

 

import arcpy
keysList = []
valuesList = []

aprx = arcpy.mp.ArcGISProject("CURRENT")

    for lyt in aprx.listLayouts():
        for m in lyt.listElements():
            keysList.append(lyt.name)
            valuesList.append(m.name)
print(keysList)
print(valuesList)

 

 

 

0 Kudos
1 Solution

Accepted Solutions
AlfredBaldenweck
MVP Regular Contributor

You were very close, just needed to filter the list.

import arcpy
keysList = []
valuesList = []

aprx = arcpy.mp.ArcGISProject("CURRENT")

for lyt in aprx.listLayouts():
    #Filter down the list to only map frames
    for m in lyt.listElements("MAPFRAME_ELEMENT"):
    #You want the name of the map in map frame, not the map frame itself
        keysList.append(lyt.name)
        valuesList.append(m.map.name)
print(keysList)
print(valuesList)
'''Result'''
#['Layout', 'Layout']
#['Extent', 'Grey-scale']

It might be cleaner to make a dictionary:

import arcpy
mapDict= {}

aprx = arcpy.mp.ArcGISProject("CURRENT")
for lyt in aprx.listLayouts():
    #Filter down the list to only map frames
    for m in lyt.listElements("MAPFRAME_ELEMENT"):
        if lyt.name in mapDict:
            #You want the name of the map in map frame, not the map frame itself
            mapDict[lyt.name].append(m.map.name)
        else:
            mapDict[lyt.name]=[m.map.name]
print(mapDict)
'''Result'''
#{'Layout': ['Extent', 'Grey-scale']}

 Helpful pages:

Layout class 

Map Frame class 

 

Hope this helps!

View solution in original post

9 Replies
AlfredBaldenweck
MVP Regular Contributor

You were very close, just needed to filter the list.

import arcpy
keysList = []
valuesList = []

aprx = arcpy.mp.ArcGISProject("CURRENT")

for lyt in aprx.listLayouts():
    #Filter down the list to only map frames
    for m in lyt.listElements("MAPFRAME_ELEMENT"):
    #You want the name of the map in map frame, not the map frame itself
        keysList.append(lyt.name)
        valuesList.append(m.map.name)
print(keysList)
print(valuesList)
'''Result'''
#['Layout', 'Layout']
#['Extent', 'Grey-scale']

It might be cleaner to make a dictionary:

import arcpy
mapDict= {}

aprx = arcpy.mp.ArcGISProject("CURRENT")
for lyt in aprx.listLayouts():
    #Filter down the list to only map frames
    for m in lyt.listElements("MAPFRAME_ELEMENT"):
        if lyt.name in mapDict:
            #You want the name of the map in map frame, not the map frame itself
            mapDict[lyt.name].append(m.map.name)
        else:
            mapDict[lyt.name]=[m.map.name]
print(mapDict)
'''Result'''
#{'Layout': ['Extent', 'Grey-scale']}

 Helpful pages:

Layout class 

Map Frame class 

 

Hope this helps!

BarakGarty
New Contributor II

Thank you Alfred. And you are right, I should have used a dictionary instead of two lists. Most appreciated your answer and feedback.

0 Kudos
chandlercoleman1
New Contributor

can this code work in 2.8? when I run the code m.map.name is not recognized.

 

0 Kudos
AlfredBaldenweck
MVP Regular Contributor

This is so weird. 

It should work; I tested it a few times before posting, and I work in 2.9, so there isn't a huge difference.

However, when I try it today, I also have a runtime error.

Specifically, it looks like I can call methods on the map, but I can't call its properties; m.map.listLayers() works, but m.map.mapUnits does not. 

I'm going to submit a ticket for this and hopefully we'll get some resolution.

0 Kudos
AlfredBaldenweck
MVP Regular Contributor

Wait I think I figured it out.

I dug into my testing projects a little more to see where the error was occuring.

Specifically, it always occurred on the same Layout out of the four in the project.

I checked the layout, and guess what? The dataframe isn't referencing any map. Not sure when or how that happened, but here we are.

AlfredBaldenweck_0-1674226949603.pngAlfredBaldenweck_1-1674226972363.png

For some reason, I couldn't get it to tell me straight out if it wasn't referencing anything.

So I ended up just making the whole thing a try/except.

 

import arcpy
mapDict= {}
errorList = []
aprx = arcpy.mp.ArcGISProject("CURRENT")
for lyt in aprx.listLayouts():
    #Filter down the list to only map frames
    for m in lyt.listElements("MAPFRAME_ELEMENT"):
        try:
            if lyt.name in mapDict:
                #You want the name of the map in map frame, not the map frame itself
                mapDict[lyt.name].append(m.map.name)
            else:
                mapDict[lyt.name]=[m.map.name]
        except:
            errorList.append(lyt.name)
            
print(mapDict, "\n")

print("The following layouts had errors. \n" 
      "Check to see if their map frames are referencing a map.",
      "\n".join(errorList))


'''Results'''
#{'Layout': ['Data Call Wkbk'], 'Layout1': ['Georeferencing'], 'Layout2': ['Map1', 'Tracy_TallgrassMap']} 

#The following layouts had errors. 
#Check to see if their map frames are referencing a map.  Wind Project_2021_Fred

 

 

chandlercoleman1
New Contributor

Thank works nicely.  Thankyou.

0 Kudos
chandlercoleman1
New Contributor

Hi again.  I was hoping you could help me understand how to use this code to pull the layers that are in the layout.  I am trying to pull this data into a CSV line by line:

layout name, map name, layer name, visible, etc

layout name, map name, layer name, visible, etc

I have some code that basically does this, but for an MDX.  I can't figure out how to make it do it for an APRX.  Any ideas would be appreciated.  thanks, chandler

0 Kudos
AlfredBaldenweck
MVP Regular Contributor

 

import arcpy
import csv
import pandas as pd

mapList= []
errorList = []
# Enter in the properties you care about
propList= ['brightness', 'visible', 'isBroken']
outCSV = r'W:\Downloads\testing.csv'

aprx = arcpy.mp.ArcGISProject("CURRENT")
for lyt in aprx.listLayouts():
    # Filter down the list to only map frames
    for m in lyt.listElements("MAPFRAME_ELEMENT"):
        try:
            for lay in m.map.listLayers(): 
                # Ignore group and base layers
                if lay.isGroupLayer is True:
                    continue
                if lay.isBasemapLayer is True:
                    continue
                tempList= [lyt.name, m.map.name, lay.name]
                for prop in propList:
                    #print(getattr(lay, prop,""))
                    tempList.extend([getattr(lay, prop,"")])
                mapList.append(tempList)    
                
        except:
            errorList.append(lyt.name)

with open(outCSV, 'w', newline='') as file:
        writer = csv.writer(file)
        heading = ["Layout", "Map", "Layer"]
        heading.extend(propList)
        writer.writerow(heading)
        writer.writerows(mapList)

#Delete duplicates. 
print("Deleting duplicates")
df = pd.read_csv(outCSV)
# This way drops any duplicate maps, leaving only the entries 
#    for the first layout in which they appear.
df= df.drop_duplicates(subset=heading[1:])
# This one just drops duplicates
#df= df.drop_duplicates()
df.to_csv(outCSV)

print("done")
if len(errorList)>0:
    print("The following layouts had errors. \n" 
          "Check to see if their map frames are referencing a map.",
          "\n".join(errorList))

 

This ought to do it.

It'll print out an excel sheet (file path in Line 9) containing the following columns: Layout, Map name, Layer name, and then whatever properties you want, as entered into propList (Line 8 )(don't worry about the name, that goes in by default).

The end result looks like this.

AlfredBaldenweck_0-1674845187532.png

 

As presented right now, it also gets rid of duplicate entries for maps. To ignore this and list all maps, regardless of how many times they appear, just comment out Line 43 and un-comment Line 45.

If you're interested in just one layout, you can filter it down in Line 12, e.g. aprx.listLayouts('Layout 1')

 

Hope this helps!

0 Kudos
chandlercoleman1
New Contributor
Thanks for getting back to me. I appreciate your help. Let me know what you find out.

Chandler Coleman
D 208 387 7138 M 208 949 9309
hdrinc.com/follow-us<>

From: Esri Community
Sent: Friday, January 20, 2023 7:39 AM
To: Coleman, Chandler
Subject: Re: list map name that is reference to a layout in arcgis pro project (Subscription Update)

CAUTION: [EXTERNAL] This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.


*** DO NOT REPLY TO THIS E-MAIL ***

To respond, use the hyperlinked Response Options at the bottom of your notification below OR visit the Esri Community post directly and reply from there.

Hi chandlercoleman1,

AlfredBaldenweck (Regular Contributor) posted a new reply in Python Questions<> on 01-20-2023 06:35 AM:

________________________________
Re: list map name that is reference to a layout in arcgis pro project<>

This is so weird. It should work; I tested it a few times before posting, and I work in 2.9, so there isn't a huge difference. However, when I try it today, I also have a runtime error. Specifically, it looks like I can call methods on the map, but I can't call its properties; m.map.listLayers() works, but m.map.mapUnits does not. I'm going to submit a ticket for this and hopefully we'll get some resolution.

Reply | Give Kudos<>

________________________________

Esri Community sent this message to chandler.coleman@hdrinc.com.
You are receiving this email because a new message matches your subscription to a topic.
If you do not want to receive notification for this message, unsubscribe the topic<> or mute the message<>.
To manage your email notifications, go to your settings in the community<>.
0 Kudos