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??
Solved! Go to Solution.
I think you have two options:
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
I think you have two options:
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
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!
Feel free to message me if you’d like to see my script - you may be able to copy and paste quite a bit
@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.
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()
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()
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.