Skip To Content

Web map printing with arcpy.mp

A common arcpy.mp workflow used in Portal for ArcGIS is web map printing where Python, ArcGIS API for JavaScript, and Web AppBuilder for ArcGIS all work together to create web apps that produce high-quality cartographic output.

ConvertWebMapToArcGISProject

The ConvertWebMapToArcGISProject function converts a web map that you intend to print or export to an ArcGIS Pro project. Once the web map is converted, the full state of the web map exists in the project. The project can then be further modified before being printed or exported to a common format such as PDF. The ConvertWebMapToArcGISProject function is commonly used when printing a map from a web GIS app using ArcGIS API for JavaScript or Web AppBuilder for ArcGIS.

Advantages of arcpy.mp in web map printing

The ConvertWebMapToArcGISProject function is intended for workflows where a web map needs to be modified or exported using arcpy.mp functions. Some example workflows that can be met using the ConvertWebMapToArcGISProject function are as follows:

  • Swapping out service layers for local vector data—In arcpy.mp scripts, service layers can be identified and swapped out for layers that point to local data. This is commonly used when a vector output is preferred rather than service layers. Some advantages to vector output are as follows:
    • Vector PDF output supports embedding feature attributes in PDF viewing applications. Switching layer visibility and viewing map coordinates are also supported but do not require vector.
    • Dynamic tables and charts can be associated with vector layers in staged layout templates. They react to changes in the map extent so that only data visible in the map is shown.
    • For high-quality cartographic output, vector data may be preferable to cached map services.
    One way to accomplish swapping service layers for vector data is to stage layout templates that contain vector equivalents of all the possible service layers. After executing the ConvertWebMapToArcGISProject function, loop through all the layers in the output map, and remove all layers except the vector layers that correspond to the service layers in the web map. This workflow can be used when swapping your own services with the corresponding vector data that you already have. For a code sample, see example 3 in the ConvertWebMapToArcGISProject topic.
  • Creating map books—A map book can be generated if Map Series is enabled on the staged layout template. Moreover, the output layout can be exported as a PDF file and inserted into other PDF files (for example, a title page or report) using the PDFDocument class to create a complete map book. For code samples, see examples 5 and 6 in the ConvertWebMapToArcGISProject topic.
  • Exporting using advanced options—All of the arcpy.mp export functions have many advanced options. For example, the ExportToPDF method on the Layout and MapView classes have parameters for controlling raster and vector compression, defining colorspace, embedding fonts, and so on. For a code sample, see example 2 in the ConvertWebMapToArcGISProject topic.
Note:

ArcGIS Server also includes a geoprocessing service called PrintingTools. The PrintingTools service can be used in a web app to generate a high-cartographic-quality printable image. For more information regarding the PrintingTools service, see Printing in web applications.

The output file (for example, PDF, PNG, and so on) of the Python script can be a layout from the optional template_pagx parameter and can include page layout surrounds (for example, title, legends, scale bar, overview map frames, grids, graticules, tables, charts, and so on). The output can also be a MapView, which would not include any page layout surrounds.

Share your script as a web tool

Once you have a Python script that prepares the map for printing, you can encapsulate it in a script tool. You can then publish the script tool as a web tool. ArcGIS API for JavaScript and Web AppBuilder for ArcGIS have a Print task and a Print widget, respectively, that you can use in your web GIS app. Both the Print task and Print widget have a URL property that points to the REST URL of the web tool you created.

Script tool parameters

When using ConvertWebMapToArcGISProject in a web tool in ArcGIS API for JavaScript or Web AppBuilder for ArcGIS, the parameter names of the script tool must match the Print task or Print widget parameters described in the following table:

Script tool parameter nameData typeTypeDescription
Web_Map_as_JSON

String

Required

A (JavaScript Object Notation (JSON) representation of the state of the map to be exported as it appears in the web app. JSON is the format of the web map. It contains the full state of the web map (for example, layers, coordinate system, extent, scale, and so on). ArcGIS API for JavaScript and Web AppBuilder for ArcGIS allow you to get this JSON string from the web app.

Output_File

File

Optional

The output file name. The extension of the file depends on the Format parameter.

Format

String

Optional

The format in which the map image for printing will be delivered. The following strings are accepted: PDF, PNG, PNG8, PNG32, JPG, GIF, EPS, SVG, and SVGZ.

Layout_Template

String

Required

Either a name of a template from the list or the keyword MAP_ONLY. When MAP_ONLY is chosen or an empty string is passed in, the output map does not contain any page layout surroundings (for example, title, legends, scale bar, and so on).

The following screen capture shows a sample script tool's parameters:

Sample script tool parameters

Tip:

When working with ArcGIS API for JavaScript, only the Web_Map_as_JSON and Output_File script tool parameters are needed by the Print task. When working with Web AppBuilder for ArcGIS, all four script tool parameters are needed by the Print widget.

Tip:

When working with ArcGIS API for JavaScript, any number of additional user-defined parameters can also be added. The ability to pass extra parameters into a custom Print task is useful, as it allows you to collect any number of extra parameters from the web app and pass them into the Python script. For example, your web app may have a control that allows users to choose whether to embed georeferencing information in the output PDF. For an example of collecting extra parameters from the web app, see example 3 in the ConvertWebMapToArcGISProject topic.

For more information regarding setting script tool parameters, see Setting script tool parameters.

Understand web map JSON

When you use the ArcGIS API for JavaScript or Web AppBuilder for ArcGIS Print task or Print widget, respectively, you don't need to create the web map JSON; the APIs take care of it for you. However, before the script can be published and used in the web APIs, it must be run locally in ArcGIS Pro. Any valid web map JSON string can be used when running the script locally. A JSON string similar to what your web app will be returning may be required for your script to run successfully. See ExportWebMap specification to understand how this text should be formatted. The following is a sample string:

{
    "layoutOptions": {
        "titleText": "Simple WebMap JSON example"
    },
    "operationalLayers": [
        {
            "url": "http://maps1.arcgisonline.com/ArcGIS/rest/services/USA_Federal_Lands/MapServer",
            "visibility": true
        }
    ],
    "exportOptions": {
        "outputSize": [
            1500,
            1500
        ]
    },
    "mapOptions": {
        "extent": {
            "xmin": -13077000,
            "ymin": 4031000,
            "xmax": -13023000,
            "ymax": 4053000
        }
    },
    "version": "1.4"
}
Tip:

When running the script tool, the JSON string can be copied and pasted into the Web_Map_as_JSON input parameter. However, the line breaks must be removed for the string to be valid input. The following is a sample JSON string with line breaks removed:

{"layoutOptions": {"titleText": "Simple WebMap JSON example"},"operationalLayers": [{"url": "http://maps1.arcgisonline.com/ArcGIS/rest/services/USA_Federal_Lands/MapServer","visibility": true}],"exportOptions": {"outputSize": [1500,1500]},"mapOptions": {"extent": {"xmin": -13077000,"ymin": 4031000,"xmax": -13023000,"ymax": 4053000}},"version": "1.4"}
Tip:

Alternatively, the Python script can be authored in such a way to allow for empty Web_Map_as_JSON input when running from ArcGIS Pro prior to publishing. There are several ways in which this can be accomplished. The code example below demonstrates one way of doing this. Once the script has been shared as a web tool, it can be further tested with valid JSON from the web app.

# If script is executed from within ArcGIS Pro, and WebMap_as_JSON is blank, then don't fail
prodName = arcpy.GetInstallInfo()['ProductName']
if (WebMap_as_JSON == '#'):
	if (prodName == 'ArcGISPro'):
		exit()
Tip:

As mentioned previously, the web map JSON returned from the web app contains the full state of the web map. The layoutOptions object in the web map JSON warrants extra discussion, as it will automatically update layout elements that can be staged in the template_pagx. For example, if the JSON has a titleText setting, and the template_pagx has a Layout Metadata dynamic text element with a title attribute, the dynamic text in the template page layout will be updated with the titleText value. For more information, see the layoutOptions section in the ExportWebMap specification.

Layout templates

When the Python script that uses ConvertWebMapToArcGISProject is encapsulated in a web tool, you need to ensure that ArcGIS Server can access the layout templates and data used in the web app. It is best practice to use a folder that is registered with ArcGIS Server. For more information on registering data, see About registering your data with ArcGIS Server.

In addition to creating your own layout templates, the templates that ship with the software can also be used. They are located at <installation_directory>\Templates\ExportWebMapTemplates. These templates contain map surround elements such as a legend, current date dynamic text, a scale bar, and scale text. These templates are a good starting point. However, keep in mind that they are part of the installation directory and will be removed if the software is ever uninstalled or reinstalled. These templates can be manually copied to a location that ArcGIS Server can access and further modified if required.

In certain scenarios, it may be beneficial have a separate task in the web app to get information about the available layout templates. For example, you may want to know if the end user of the web app chose a layout template with a Layout Metadata dynamic text element with a title attribute so you can prompt the user to enter their own custom title. To accomplish this, the PrintingTools service has a task called Get Layout Templates Info that returns the content of layout templates in JSON format. For more information regarding the Get Layout Templates Info task, see Printing in web applications.

Client-side graphics support

By default, notes overlays or client-side graphics from the web app are stored in an in-memory workspace. The in-memory workspace is temporary and is deleted when the app is closed. To make a permanent copy of the output project that contains notes overlays, specify a notes_gdb; then use the saveACopy method from the ArcGISProject class.

Examples custom Python script in a web app

The following are examples of using custom Python script in web apps.

Example 1: Use a custom Python script in Web AppBuilder for ArcGIS

This example shows how Python and Web AppBuilder for ArcGIS can be used together to create a web GIS app for web map printing. The end user will be able to navigate to an area of interest, choose from a list of layout templates (for example, different page sizes), and click a Print button. The output will be a printer-friendly PDF or PNG document. If the end user chooses PDF output, the file will contain vector data for service layers.

In this Python script, staged layout templates (.pagx files) that contain vector equivalents of all the possible service layers are referenced. After executing the ConvertWebMapToArcGISProject function, the script loops through all the layers in the output map, removing all the service layers from the web map JSON, leaving only the staged vector layers. The layout is then exported to either a PDF or PNG file.

import arcpy
import os
import uuid

# The template location in the server data store
templatePath = '//MyServer/MyDataStore/Templates'

# Input WebMap JSON
Web_Map_as_JSON = arcpy.GetParameterAsText(0)

# Format for output
Format = arcpy.GetParameterAsText(1)

# Input layout template
Layout_Template = arcpy.GetParameterAsText(2)

# Get the requested layout template pagx file
templatePagx = os.path.join(templatePath, Layout_Template + '.pagx')
   
# Convert the WebMap to an ArcGISProject
result = arcpy.mp.ConvertWebMapToArcGISProject(Web_Map_as_JSON, templatePagx, "Layers Map Frame")
aprx = result.ArcGISProject
layout = aprx.listLayouts()[0]

# Reference the map that contains the webmap
m = aprx.listMaps('Web Map')[0]

# Remove the service layer
# This will just leave the vector layers from the template
for lyr in m.listLayers():
    if lyr.isWebLayer:
        m.removeLayer(lyr)
        
# Use the uuid module to generate a GUID as part of the output name
# This will ensure a unique output name
output = 'WebMap_{}.{}'.format(str(uuid.uuid1()), Format)
Output_File = os.path.join(arcpy.env.scratchFolder, output)

# Export the WebMap
if Format.lower() == 'pdf':
    layout.exportToPDF(Output_File) 
elif Format.lower() == 'png':
    layout.exportToPNG(Output_File)

# Set the output parameter to be the output file of the server job
arcpy.SetParameterAsText(4, Output_File) 

# Clean up
del layout, aprx, result

After sharing the Python script tool as a web tool, the Print widget in Web AppBuilder for ArcGIS would be configured to use the REST URL of the web tool. The following screen capture shows the configuration dialog box for the Print widget:

The configuration dialog box for the Print widget.

Tip:

In the screen capture above, the values for Default format and Default layout are automatically populated from the Format and Layout_Template parameters from the web tool.

Example 2: Use a custom Python script in ArcGIS API for JavaScript

This example shows how Python and ArcGIS API for JavaScript can be used together to create a web GIS app for web map printing. The end user will be able to do the following in the web app:

  • Navigate to an area of interest.
  • Select a staged layout template.
  • Select an output format.
  • Choose whether to export georeferencing information to an output PDF file by passing in an extra parameter from the web app to the Print task.
  • Export the map to a printer-friendly format containing vector output for service layers.

In this Python script, staged layout templates (.pagx files) that contain vector equivalents of all the possible service layers are referenced. After executing the ConvertWebMapToArcGISProject function, the script loops through all the layers in the output map, removing all the service layers from the web map JSON, leaving only the staged vector layers. The output layout is then exported to either a PDF or PNG file. This example also shows how to pass extra parameters (Georef_info) from the web app to the Python script beyond the standard parameters supported by the Print task.

import arcpy
import os
import uuid

# The template location in the server data store
templatePath = '//MyServer/MyDataStore/Templates'

# Input WebMap JSON
Web_Map_as_JSON = arcpy.GetParameterAsText(0)

# Format for output
Format = arcpy.GetParameterAsText(1)

# Input layout template
Layout_Template = arcpy.GetParameterAsText(2)
    
# Extra parameter - georef_info
Georef_info = arcpy.GetParameterAsText(3)

# Convert Georef_info string to boolean
if Georef_info.lower() == 'false': 
    Georef_info_bol = False
elif Georef_info.lower() == 'true': 
    Georef_info_bol = True
else: Georef_info_bol = True

# Get the requested layout template pagx file
templatePagx = os.path.join(templatePath, Layout_Template + '.pagx')
   
# Convert the WebMap to an ArcGISProject
result = arcpy.mp.ConvertWebMapToArcGISProject(Web_Map_as_JSON, templatePagx, "Layers Map Frame")
aprx = result.ArcGISProject
layout = aprx.listLayouts()[0]

# Reference the map that contains the webmap
m = aprx.listMaps('Web Map')[0]

# Remove the service layer
# This will just leave the vector layers from the template
for lyr in m.listLayers():
    if lyr.isWebLayer:
        m.removeLayer(lyr)
        
# Use the uuid module to generate a GUID as part of the output name
# This will ensure a unique output name
output = 'WebMap_{}.{}'.format(str(uuid.uuid1()), Format)
Output_File = os.path.join(arcpy.env.scratchFolder, output)

# Export the WebMap - use Georef_info_bol to control georeferencing
if Format.lower() == 'pdf':
    layout.exportToPDF(Output_File, georef_info=Georef_info_bol) 
elif Format.lower() == 'png':
    layout.exportToPNG(Output_File, world_file=Georef_info_bol)

# Set the output parameter to be the output file of the server job
arcpy.SetParameterAsText(4, Output_File) 

# Clean up
del layout, aprx, result

The Python script tool is shared as a web tool. In the following script, the Print task in ArcGIS API for JavaScript is configured to use the REST URL of the web tool:

Tip:

The REST URL of the web tool is referenced in the script at this line:

var printServiceUrl = "https://MyServer:6443/arcgis/rest/services/MyPrintService/GPServer/MyPrintService";

The entire script is as follows:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
  <title>Austin Print WebApp</title>

  <link rel="stylesheet" href="https://js.arcgis.com/4.3/esri/css/main.css">
  <script src="https://js.arcgis.com/4.3/"></script>

  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }
    
    #layerToggle {
      top: 20px;
      right: 20px;
      position: absolute;
      z-index: 99;
      background-color: white;
      border-radius: 8px;
      padding: 10px;
      opacity: 1;
    }
  </style>

  <script>
    require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/TileLayer",
        "esri/tasks/PrintTask",
        "esri/tasks/support/PrintParameters",
        "esri/tasks/support/PrintTemplate",
        "dojo/dom",
        "dojo/on",
        "dojo/domReady!"
      ],
      function(
        Map, MapView, TileLayer, PrintTask, PrintParameters, PrintTemplate, dom, on
      ) {

        /*****************************************************************
         * Create a TileLayer instance. 
         *****************************************************************/
        var austinLyr = new TileLayer({
          url: "http://MyServer:6080/arcgis/rest/services/MyMapService/MapServer",
          id: "austin",
          opacity: 0.9
        });

        /*****************************************************************
         * Layers may be added to the map in the map's constructor
         *****************************************************************/
        var map = new Map({
          basemap: "oceans",
          layers: [austinLyr]
        });

        var view = new MapView({
          container: "viewDiv",
          map: map
        });
        
        /*****************************************************************
         * Go to extent of Austin Layer
         *****************************************************************/
        view.then(function() {
          austinLyr.then(function() {
            view.goTo(austinLyr.fullExtent);
          });
        });

        var printServiceUrl = "https://MyServer:6443/arcgis/rest/services/MyPrintService/GPServer/MyPrintService";
        
        var printMode = "async";
        
        var printTask = new PrintTask({
   			url: printServiceUrl,
   			mode: printMode
			});
		
	function myPrint() {
		// input layout template
		var layout = dom.byId("layout");
	        var index = layout.selectedIndex;
	        var selectedValue_layout = layout.options[index].value;
	        
	        // format for output
	        var format = dom.byId("format");
	        var index = format.selectedIndex;
	        var selectedValue_format = format.options[index].value;
	        
	        // Extra parameter: Georeferencing info boolean
	        var georef_info = dom.byId("georef_info");
	        var index = georef_info.selectedIndex;
	        var selectedValue_georef_info = georef_info.options[index].value;
	        
	        var template = new PrintTemplate({
			 format: selectedValue_format,
			 layout: selectedValue_layout, 
			});
	
		var params = new PrintParameters({
			 view: view,
			 template: template
			});
			
		params.extraParameters = {
          		Georef_info : selectedValue_georef_info
        		};
	        
		printTask.execute(params).then(printResult, printError);
			}
		
		function printResult(result) {
        	window.open(result.url);
     		}	
     		
     	function printError(result) {
        	alert('Error printing.')
     		}
     		
     	// Call myPrint() each time the button is clicked    
      	on(dom.byId("doBtn"), "click", myPrint);

      });
  </script>
</head>

<body>
  <div id="viewDiv"></div>
  <span id="layerToggle">
    Layout Template:
    <select id="layout" >
      <OPTION value="Austin26x28">Austin26x28</OPTION>
      <OPTION value="Austin24x36">Austin24x36</OPTION>
    </select>
    &nbsp;&nbsp;Format:
    <select id="format">
      <OPTION value="PDF">PDF</OPTION>
      <OPTION value="PNG">PNG</OPTION>
    </select>
	
    &nbsp;&nbsp;Include Georef info?
    <select id="georef_info">
      <OPTION value="True">True</OPTION>
      <OPTION value="False">False</OPTION>
    </select>
    <button id="doBtn">Print Map</button>
  </span>
</body>

</html>

updateLayerFromJSON

If your web app uses dynamic layers, the updateLayerFromJSON function from the Layer class can be used to update the properties (for example, symbology) of staged vector layers in the layout template with the layer definition of dynamic layers from the web map JSON. This is useful if your web app allows changing the symbology of dynamic layers, and you want to replace the service layers with staged vector data but still maintain the updated symbology from the web app. For an example of using updateLayerFromJSON, see example 4 in the ConvertWebMapToArcGISProject topic.