Select to view content in your preferred language

Integrating a report and map series

1340
7
Jump to solution
10-04-2023 09:40 AM
clt_cabq
Occasional Contributor III

I have a report that lists properties grouped by an administrative boundary. I also have a map series that uses the administrative boundary as the index for each page. I can't seem to figure out how to integrate these two documents. What I'd like is to have the group for one administration to be followed by a map of that same area. I've tried using the supplemental page but it seems to disregard the map series and prints a single map page showing all the data. 

Any thoughts how this might be possible to accomplish??

1 Solution

Accepted Solutions
JamesTurner2
New Contributor III

I think you have two options:

  1. Insert a table on the map layout which displays all the information from the report.
    1. Table size is going to be limited by page size and it will truncate your data if it overruns
  2. Use arcpy.mp to generate a map book
    1. Loop through each administrative boundary to create the map and the report. Then combine the documents inside the script

If you have some experience with Python, the arcpy route is 100% the way to go. There is some good tutorials out there and ESRI has put out some sample code that is easy to understand and modify. I recommend looking at the two panel map and the thematic map series scripts. I combined parts of both to do something similar to what you are doing. You'll also need to reference the arcpy report class documentation

 

View solution in original post

7 Replies
JamesTurner2
New Contributor III

I think you have two options:

  1. Insert a table on the map layout which displays all the information from the report.
    1. Table size is going to be limited by page size and it will truncate your data if it overruns
  2. Use arcpy.mp to generate a map book
    1. Loop through each administrative boundary to create the map and the report. Then combine the documents inside the script

If you have some experience with Python, the arcpy route is 100% the way to go. There is some good tutorials out there and ESRI has put out some sample code that is easy to understand and modify. I recommend looking at the two panel map and the thematic map series scripts. I combined parts of both to do something similar to what you are doing. You'll also need to reference the arcpy report class documentation

 

clt_cabq
Occasional Contributor III

Thanks @JamesTurner2 your second suggestion is the route I'd need to go, I suspected there isn't anything 'built in' to do this, which is a shame but then ESRI's reporting capabilities always have seemed to be pretty lackluster. Appreciate the links!

0 Kudos
JamesTurner2
New Contributor III

Feel free to message me if you’d like to see my script - you may be able to copy and paste quite a bit

0 Kudos
clt_cabq
Occasional Contributor III

@JamesTurner2 thanks for the offer - I have it mostly sorted out, turns out this is pretty simple. I'll post my code when its finished, might be worth comparing notes. 

0 Kudos
clt_cabq
Occasional Contributor III

here's my solution, two modules that will be part of a larger set of modules called into a main script that updates some data on a monthly basis and then result in the report and map series being generated. This is pretty simple right now, each report has only 7 pages (one per admin boundary area) and 7 maps to match. 

Module 1 simply exports the report and map series to separate .pdf documents:

# creates pdfs from a report and map series in an aprx  
import arcpy,os 
proj_path = r'filepathname.aprx'
out_path = r'filepath\ReportsMaps\Output'
# get report and map objects
aprx = arcpy.mp.ArcGISProject(proj_path)
lyout = aprx.listLayouts("MapSeriesName")[0] # gets the correct layout from the aprx
rpt = aprx.listReports("Reportname")[0] # gets the correct report from the aprx
maps = lyout.mapSeries
# exports each document type to a pdf file
maps.exportToPDF(os.path.join(out_path, f"{lyout.name}"))
rpt.exportToPDF(os.path.join(out_path, f"{rpt.name}"))

 

Module 2 merges the two pdfs created in Module 1, such that report page 1 is followed by map page 1, etc. This is pretty 'brute force' and eventually I want to make it a bit more intelligent and flexible but this works for the time being.

# merges two together so that a report page is followed by a map page for corresponding administrative areas.
import datetime, os
from pypdf import PdfWriter
# creates a year/month timestamp for the final report name
today = datetime.datetime.today()
yearmonth = f"{today.year}_{today.month}"
# initializes folders and objects to work with 
in_folder = r'filepathname\ReportsMaps\Output'
rpt_doc = 'RptDoc.pdf'
map_doc = 'MapDoc.pdf'
in_rpt = open(f"{in_folder}\{rpt_doc}","rb")
in_maps = open(f"{in_folder}\{map_doc}","rb")
merge_doc = PdfWriter()
merge_doc.append(fileobj=in_rpt) # creates new document containing report pages
# next lines merge pages from the map series into their correct spot rpt pg 1 followed by map pg 1, etc.
merge_doc.merge(position=1,fileobj=in_maps,pages=(0,1))
merge_doc.merge(position=3,fileobj=in_maps,pages=(1,2))
merge_doc.merge(position=5,fileobj=in_maps,pages=(2,3))
merge_doc.merge(position=7,fileobj=in_maps,pages=(3,4))
merge_doc.merge(position=9,fileobj=in_maps,pages=(4,5))
merge_doc.merge(position=11,fileobj=in_maps,pages=(5,6))
outname = f"MonthyRptMaps_{yearmonth}.pdf" # creates name for final merged report including year/month date stamp
out_doc = open(os.path.join(in_folder, f"{outname}"),"wb")
merge_doc.write(out_doc)
merge_doc.close()
out_doc.close()

 

0 Kudos
JamesTurner2
New Contributor III

I went about it a little different, but it suited my workflow better. I used 2 layouts and a report to create a 3 page map book for each index feature.

Instead of creating the entire map series at once and exporting it, I used a loop to create all 3 items and append them to one pdf inside the loop. Below is an example of how you can create create and append pdfs using OS instead of importing PDFwriter. This code block would be inside of a loop. It's a little confusing, but then again so is my workflow and I haven't worked on it in a while. I went this route because it was used in the ESRI examples and I found it easy to expand on for multiple pages. I believe the example I followed was done before the mapSeries objects was created, so you had to use a loop to export layouts one by one and then append them into one PDF to make a series.

Per usual, the right answer is the one that works and makes sense to you.

#Create a new PDF that pages will be appended into
#First, remove the file if it already exists
if os.path.exists(os.path.join(outputFolder, pdfFileName)):
   os.remove(os.path.join(outputFolder, pdfFileName))
pdf = arcpy.mp.PDFDocumentCreate(os.path.join(outputFolder, pdfFileName))

lyt.exportToPDF(os.path.join(outputFolder, pageName +  '.pdf'))
pdf.appendPages(os.path.join(outputFolder, pageName +  '.pdf'))

#Remove the single, exported page after appended into final PDF
os.remove(os.path.join(outputFolder, pageName + '.pdf'))

rpt.exportToPDF(os.path.join(outputFolder, pageName +  '.pdf'))
pdf.appendPages(os.path.join(outputFolder, pageName +  '.pdf'))

#Remove the single, exported page after appended into final PDF
os.remove(os.path.join(outputFolder, pageName + '.pdf'))

#Complete the creation of the PDF and commit to file
pdf.saveAndClose()

 

0 Kudos
clt_cabq
Occasional Contributor III

excellent, thanks for the example - just adds to the tools available. I had considered this approach, sort of building the merged set in piecemeal fashion. I think there may be some advantages to this workflow especially if report sections start to become longer than a single page.

0 Kudos