Custom brochure printing Python

6021
26
Jump to solution
06-05-2015 07:03 PM
AicamLaacouri
New Contributor III

Hi everyone- I have an idea and I am just starting to learn Python so I would like to know if my idea can be executed using Python... So I have a polygon shapefile with 1000 polygons. Each polygon is a field/farm, the attribute table has the name of the owner and his/her address. I also happen to have a raster image that cover the same geography (satellite image). I want to print a brochure/newsletter to send it to these clients. In the front page of the brochure I will have texts and the address of the client (for postage). In the back, I want to print the clipped raster using the polygon for each field (each client has one corresponding polygon) as the clipping extent. Can I make a Python script that will my client specific brochures, so that the front of the brochure has the name and address of the client, and the back of the brochure has an image of the field (from the satellite raster image).  I want to spend time and learn about this idea but I thought to ask first if such a task is possible using python/arcmap. Thanks. Esam

0 Kudos
26 Replies
IanMurray
Frequent Contributor

Yes I use Python extensively with my templates.  I had to create the same set of three maps for several hundred polygon features, so I set up a template for each of the three maps I need, and used python to make a feature layer of each polygon ID in turn, zoom to it, then control each text elements already in the templates with data from the attribute table accessed via a search cursor.  All the layers I need for each map already exist in the templates and I have them turned on and off via python depending on other attributes.  So in the end I created ~2000 map documents and pdfs for the several hundred geometries in my feature class.

I could post a sample code for working with one of the templates if you wanted to see what it looked like, the arcpy mapping module has a good amount of control for controlling elements within map documents.  I wouldn't post more than 1 though, since the code gets a bit long.

AicamLaacouri
New Contributor III

Hello there, Thanks for the help. Can you please explain what you mean by template in your first sentence.

Thanks

0 Kudos
IanMurray
Frequent Contributor

By template I mean I have a map document or set of map documents that have all the layers, text elements, layout elements etc already loaded into them that will be used for each type of map I need.  Thus I can use the same map templates over and over again and all will be assured to have the same features, same text elements, same layouts. I have a python script that iterates over features in a feature class, zooms to each features, symbolizes them, turns on and off various layers saved in each map, and controls my text and layout elements based on values in the attribute table.  I then save a copy of the created map in folders and export them to pdf.

Actually I'm currently working on a script to move my existing maps to a new template, some of the layout elements have changed and I need to adjust my existing maps.  Its been fun so far and almost done that one.  I will say that have a deliberate naming scheme for layers, layout elements, and map names have made the work substantially easier.

KelvinMwakomo
Occasional Contributor

Hi Ian

I would like to see a sample of code so you can post it please.

Kelvin!

0 Kudos
IanMurray
Frequent Contributor

I don't mind posting the whole thing actually.  Not quite as many comments as I would like in it, but if you have questions about how any of it works let me know.

The following script loops through features in a single shapefile or gdb with the particular fields I need, and uses those field values with several premade map templates to create a series of 3 maps for each feature in the shapefile or FC.  Each template already has all layers needed saved to it, as well as text elements created and named, but the values of these elements will change according to the field values.  All filepaths have been replaced with a generic filepath/ for my sake.  Important to note, I had to make a specific folder structure for how I wanted all the maps and pdfs saved prior to running this script, there are other ways to make sure they are created as a script such as this runs, but making it prior was easier.

#Importing Modules
import arcpy, time
#Checking start time
print time.time()
#Permanent Variables
shp = r"filepath\Export_Output.shp"
symbologyLayer = r"filepath\Test.lyr"
symbologyLayer2 = r"filepath\Test2.lyr"
outlayer = shp + "_lyr"
Month = "February"
Year = "2015"
OutputLoc = r"filepath" + "\\" 
DPI = 200
#fields from feature class that will be used for text elements/file naming
fields = [ "Acreage", "City", "County" , "Name" , "State", "ED_Region", "ID"]
#Looping through each record in shapefile or feature class
with arcpy.da.SearchCursor(shp, fields) as cursor:
    for row in cursor:
        if row[4] == "MS":
            pass
        else:
            SiteName = row[3]
            State = row[4]
            City = row[1]
            County = row[2]
            Acres = row[0]
            Region = row[5]
            Hectares = str(int(int(Acres) * .4047))
            Acres = str(int(Acres))
            ID = row[6]
                       
#Optional output additions for additional subfolders.        
            Output = OutputLoc +  Region +  "\\" + County + "\\"
            FileName = County + "_" + SiteName + "_" + str(ID) 
            Title = "Aerial Imagery & FEMA 100 Year Floodplain"
            Fullpath = Output + FileName
            
#Assembling Map - Selecting MXD, Dataframe, and New Layer for Aerial Map w/floodplain
            mxd = arcpy.mapping.MapDocument(r"filepath\AerialLetterTemplate.mxd")
            df = arcpy.mapping.ListDataFrames(mxd,"*")[0]
            newlayer = arcpy.mapping.Layer(shp)
            print "adding layer"
            arcpy.mapping.AddLayer(df, newlayer, "TOP")
            Layer = arcpy.mapping.ListLayers(mxd, newlayer.name)[0]
            #Selecting by Attribute, Zooming to Feature, and Setting Scale
            arcpy.SelectLayerByAttribute_management(Layer, "NEW_SELECTION", ' "Name" = ' + "'" + SiteName + "'"  )
            #Symbology from default lyr file
            arcpy.ApplySymbologyFromLayer_management (Layer, symbologyLayer)
            df.zoomToSelectedFeatures()
            print "Zooming to scale"
            #I set all my scales by multiples of 1200, engineers love this,  I take the initial zoom scale, round it to nearest integer, then zoom it out an additional 1200 
            df.scale = ((round(df.scale / 1200.0) * 1200) + 1200)
            if df.scale == 8400:
                df.scale = 9600
            arcpy.SelectLayerByAttribute_management(Layer, "CLEAR_SELECTION")
        
            #Editting Text Elements, names for text elements are hardcoded into the map
            print "Setting Text Elements"
            Layer2 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT" , "Site Name and Size") [0]
            Layer2.text = SiteName + "\n" + " \n+/-" + Acres + " Acres \n +/-" + Hectares + " Hectares"
            
            Layer3 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT" , "Title") [0]
            Layer3.text = Title + "\n" + SiteName + "\n" + City + ", " + State + " (" + County + " Co.)"
            
            Layer4 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT" , "Prepared by Date") [0]
            Layer4.text = "Prepared " + Month + " " + Year + " by:"
            arcpy.RefreshActiveView()
        
            #Saving and Exporting Map
            print "Saving Map"
            print Fullpath + "_Aerial.mxd"
            #mxd.saveACopy(OutputLoc + SiteName +" - Aerial.mxd")
            mxd.saveACopy(Fullpath + "_Aerial.mxd")
            print "Saving PDF"
            #arcpy.mapping.ExportToPDF(mxd, OutputLoc + SiteName + " _ Aerial.pdf", "Page_Layout", 640, 480, DPI)
            arcpy.mapping.ExportToPDF(mxd, Fullpath + "_Aerial.pdf", "Page_Layout", 640, 480, DPI)
            print "Save Complete!"
            del Layer; del Layer2; del Layer3; del Layer4; del mxd
            print time.time()
            print "Next Map"
#Assembling Map - Selecting MXD, Dataframe, and New Layer
        
            mxd = arcpy.mapping.MapDocument(r"filepath\TopoLetterTemplate.mxd")
            df = arcpy.mapping.ListDataFrames(mxd,"*")[0]
            arcpy.mapping.AddLayer(df, newlayer, "TOP")
            Layer = arcpy.mapping.ListLayers(mxd, newlayer.name)[0]
            arcpy.ApplySymbologyFromLayer_management (Layer, symbologyLayer)
            print Layer.name
            Title = "USGS Topo Map & NWI Wetlands"
            arcpy.SelectLayerByAttribute_management(Layer, "NEW_SELECTION", ' "Name" = ' + "'" + SiteName + "'"  )
            #Applying Symbology from default lyr file
            arcpy.ApplySymbologyFromLayer_management (Layer, symbologyLayer)
            df.zoomToSelectedFeatures()
            df.scale = ((round(df.scale / 1200.0) * 1200) + 1200)
            if df.scale == 8400:
                df.scale = 9600
            arcpy.SelectLayerByAttribute_management(Layer, "CLEAR_SELECTION")
        
#Setting Layer and Text Elements
            WetlandLayer = arcpy.mapping.ListLayers(mxd, "*" + State, df)[0]
            WetlandLayer.visible = True
   
            Layer2 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT" , "Site Name and Size") [0]
            Layer2.text = SiteName + "\n" + " \n+/-" + Acres + " Acres \n+/-" + Hectares + " Hectares"
            Layer3 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT" , "Title") [0]
            Layer3.text = Title + "\n" + SiteName + "\n" + City + ", " + State + " (" + County + " Co.)"
            Layer4 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT" , "Prepared by Date") [0]
            Layer4.text = "Prepared " + Month + " " + Year + " by:"
            arcpy.RefreshActiveView()
            #mxd.saveACopy(OutputLoc + SiteName +" - Aerial.mxd")
            mxd.saveACopy(Fullpath + "_Topo.mxd")
            print "Saving PDF"
            #arcpy.mapping.ExportToPDF(mxd, OutputLoc + SiteName + " - Aerial.pdf", "Page_Layout", 640, 480, DPI)
            arcpy.mapping.ExportToPDF(mxd, Fullpath + "_Topo.pdf", "Page_Layout", 640, 480, DPI)
            del Layer; del Layer2; del Layer3; del Layer4; del WetlandLayer; del mxd
            mxd = arcpy.mapping.MapDocument(r"filepath\LocationLetterTemplate.mxd")
            Title = "Site Location Map"
            #This map has multiple dataframes, which I need to loop through
            for df in arcpy.mapping.ListDataFrames(mxd):
               if df.name == "Area Map":
                    
                    arcpy.mapping.AddLayer(df, newlayer, "TOP")
                    Layer = arcpy.mapping.ListLayers(mxd, newlayer.name)[0]
                    OutLayer = "OutLayer_lyr1"
                    print Layer.name
                    arcpy.SelectLayerByAttribute_management(Layer, "NEW_SELECTION", ' "Name" = ' + "'" + SiteName + "'"   )
                    print "Making Feature Layer"
                    arcpy.MakeFeatureLayer_management(Layer, OutLayer)
                    OutLayer2 = arcpy.mapping.Layer(OutLayer)
                    arcpy.mapping.AddLayer(df, OutLayer2, "TOP")
                    print "Removing Old Layer"
                    Layer3 = arcpy.mapping.ListLayers(mxd, OutLayer2)[0]
                    #Applying Symbology from default lyr file
                    arcpy.ApplySymbologyFromLayer_management (Layer3, symbologyLayer)
                    df.zoomToSelectedFeatures()
                    df.scale = 126720
                    arcpy.SelectLayerByAttribute_management(Layer, "CLEAR_SELECTION")
                    arcpy.mapping.RemoveLayer(df, Layer)
                    del Layer; 
                elif df.name == "Inset":
                
                    arcpy.mapping.AddLayer(df, newlayer, "TOP")
                    Layer = arcpy.mapping.ListLayers(mxd, newlayer.name, df)[0]
                    OutLayerA = "OutLayer_lyr2"
                    print Layer.name
                    arcpy.SelectLayerByAttribute_management(Layer, "NEW_SELECTION", ' "Name" = ' + "'" + SiteName + "'"  )
                    #Applying Symbology from default lyr file
                    arcpy.MakeFeatureLayer_management(Layer, OutLayerA)
                    OutLayerC = arcpy.mapping.Layer(OutLayerA)
                    arcpy.mapping.AddLayer(df, OutLayerC, "TOP")
                    OutLayerB = arcpy.mapping.ListLayers(mxd, OutLayerC.name)[0]
                    arcpy.ApplySymbologyFromLayer_management (OutLayerB, symbologyLayer2)
                    df.zoomToSelectedFeatures()
                    df.scale = 2300000
                    arcpy.SelectLayerByAttribute_management(Layer, "CLEAR_SELECTION")
                    arcpy.mapping.RemoveLayer(df, Layer)
                
                
                    del OutLayer2; del OutLayerC; del OutLayerB; del Layer3
                else:
                    continue
            Layer3 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT" , "Title") [0]
            Layer3.text = Title + "\n" + SiteName + "\n" + City + ", " + State + " (" + County + " Co.)"
            Layer4 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT" , "Prepared by Date") [0]
            Layer4.text = "Prepared " + Month + " " + Year + " by:"
            arcpy.RefreshActiveView()
            #mxd.saveACopy(OutputLoc + SiteName +" - Aerial.mxd")
            mxd.saveACopy(Fullpath + "_Location.mxd")
            print "Saving PDF"
            #arcpy.mapping.ExportToPDF(mxd, OutputLoc + SiteName + " - Aerial.pdf", "Page_Layout", 640, 480, DPI)
            arcpy.mapping.ExportToPDF(mxd, Fullpath + "_Location.pdf", "Page_Layout", 640, 480, DPI)
            del Layer; del Layer3; del Layer4; del mxd;
            arcpy.Delete_management(OutLayer)
            arcpy.Delete_management(OutLayerA)
            print time.time()
    del shp
0 Kudos
SepheFox
Frequent Contributor

Hi Aicam, you can have any layers you want in your project, including a raster image, and they will all remain visible on every pdf.

AicamLaacouri
New Contributor III

Hi Sephe

Do you know if DDP would work on two data frames for the same layout simultaneously?

Thanks

0 Kudos