1

I am trying to gather some information on how to create maps based on an existing base map I have. The basemap has all the data loaded. So the user will enter data into a form and the would do a save as, query data in the map, create the map and export to PDF.

I know python is for automation of workflows, but what I need is a way to have my users enter information into a form and have the map created automatically based on a save as of an existing map, some inputs, queries and data in my basemap. I see lots of examples for automating workflows, but I am looking to deploy a solution that non-GIS users could create maps quickly based on some information in arcmap.

Would I do this with ArcObjects or can it in fact be done with Python? Has anyone tried automating the entire map process?

I just need to know which method I would use to create this project? And if I can complete with Python and/or ArcObjects?

12
  • 2
    I would expect that your requirements can be met using ArcPy but as it stands your question seems too broad for our focussed Q&A format. I recommend starting to write some code snippets to do each step of your map automation and if you get stuck then research/ask here about each separately.
    – PolyGeo
    Commented May 29, 2015 at 21:28
  • 1
    I am not looking for exactly how to do this, obviously it would be intensive. I am just wondering which method I could use to do this (Python/ArcObjects) and any info (links) that could help me during this gathering stage. I would be hiring developers for this project, I am just trying to obtain info as of now on the structure of this project.
    – Robert C
    Commented May 29, 2015 at 21:30
  • 2
    Hey Myque - arcpy.mapping offers a great deal of control over the map automation functions it exposes. However, I'd say the central factor preventing a pure Python/ArcPy route is the fact that arcpy.mapping generally cannot create map documents and associated map elements, it can only manipulate existing elements. So, the requirement to create a map document and call outs etc. cannot be met with just ArcPy, see This Example
    – Jim
    Commented May 29, 2015 at 21:38
  • 1
    It will also depend on what application your users will be working with. Will they be using ArcMap? Or will they be entering information into a web form or some other custom application?
    – Mintx
    Commented May 29, 2015 at 21:44
  • 2
    Now that we have had this discussion in comments I think it should be possible for you to edit your question into a form more suited to focussed Q&A around a single requirement, and then to research/ask about any others of concern separately.
    – PolyGeo
    Commented May 29, 2015 at 22:39

2 Answers 2

5

What you are asking can be done using arcpy/python. Below is a script that I compiled to create an mxd and update map element with user inputs. Feel free to use the script, I never took it further than making an mxd.

The script relies on having an mxd already set up as a template. Additionally, in order for the script to work, you need to assign the map elements (text boxes, legends, North Arrows etc)a unique name. e.g. If you open the properties of a text box and click the Size and Position tab, there should be a field called Element Name. Enter the unique name of the element there. See image below.

enter image description here

In the code below, arcpy.GetParameterAsText(0) to (4) are used to compile the file name for the mxd. The other arcpy.GetParameterAsText(*) are the users inputs to add to the map elements. The line "for txtElement in txtElements:" is where the code starts assigning the users inputs to the map elements. Hope this makes sense.

import arcpy, sys, traceback, datetime, os, shutil, getpass
from arcpy.mapping import *

groupDesigLetter = arcpy.GetParameterAsText(0)
#    Designates map is generated by the certain team (e.g. G = Geospatial)

mapNumber = arcpy.GetParameterAsText(1)
#    The next map in sequence.

workingOrSubmittal = arcpy.GetParameterAsText(2)
#    If it is a working document or final document.

projectNumber = arcpy.GetParameterAsText(3)
#    This is the project number.

versionNo = arcpy.GetParameterAsText(4)
#    v1. One digit sub-version number. 0 or blank denotes a map that has been issued.
#    “1,2,3…” denotes internal, intermediate revisions of map before releasing the      map
#    to an external party.

mapDescription = arcpy.GetParameterAsText(5)
#    Description of the map and contents should include page size, orientation, title etc

mapFormat = arcpy.GetParameterAsText(6)
#    This is the size and orientation of the map.

mapTitle = arcpy.GetParameterAsText(7)
#    This is the tile of the map

mapSubTitle = arcpy.GetParameterAsText(8)
#    This is the sub title of the map

figureNumber = arcpy.GetParameterAsText(9)
#    This is the figure number of the map.

mapProjection = arcpy.GetParameterAsText(10)

saveMXD = arcpy.GetParameterAsText(11)
#    This is the location where the new mxd is saved

newMXDFileName = "{}{}_{}_{}_v{}_{}_{}.mxd".format(groupDesigLetter, mapNumber, workingOrSubmittal, projectNumber, versionNo, mapDescription, mapFormat[:2])
#    New file name for the .mxd

newMXDFullPath = os.path.join(saveMXD, newMXDFileName)
#    Variable to store the full directory path to the new mxd.

mxdLocation = os.path.join("D:\Templates", mapFormat +".mxd")
#    Location of the mxd template

mxdAuthor = getpass.getuser()
#    Gets the current user name

mxdTitle = "{} - {}".format(mapTitle,mapSubTitle)
#    Compiles the mxd title

mxdCredits = "XXXXXXXXX {}".format(datetime.date.today().year)

try:

    arcpy.AddMessage("...Creating Copy of Template...")
    #    Prints message to screen.

    shutil.copy(mxdLocation, saveMXD)
    #    Copies template .mxd to the save location.

    arcpy.AddMessage("...Renaming Copied MXD...")
    #    Prints message to screen.

    rename = os.rename(os.path.join(saveMXD, mapFormat + ".mxd"), os.path.join(saveMXD, newMXDFileName))
    #    Renames the copies .mxd to the new file name

    mxd = MapDocument(newMXDFullPath)
    #    Variable to store the location to the working map document.

    mxd.author = mxdAuthor
    #    Assigns the current user as the author

    mxd.title = mxdTitle
    #    Assigns the attribute for the mxds title property

    mxd.description = mapDescription
    #    Assigns the attribute for the mxds description property

    mxd.relativePaths = True
    #    Sets the relative path to true.

    mxd.credits = mxdCredits

    dataFrame = ListDataFrames(mxd, "Layers")[0]

    dataFrame.spatialReference = mapProjection

    txtElements = ListLayoutElements(mxd,'TEXT_ELEMENT')
    #    variable to store the list of text elements within the working map document.

    for txtElement in txtElements:
        #    Loop for the text elements within the working map document.

        if txtElement.name == 'Title_Block':
            #    if statement to select the title block map element

            txtElement.text = "{}\r\n {}".format(mapTitle.upper(), mapSubTitle)
            #    Populates the tilte block's text properties

        elif txtElement.name == 'Project_Number':
            #    If statement to select the project number map element.

            txtElement.text = projectNumber
            #    Populates the project number text properties.

        elif txtElement.name == 'Version_Number':
            #    If statement to select the version number map element.

            txtElement.text = "v{}".format(versionNo)
            #    Populates the version number text properties.

        elif txtElement.name == 'Figure_Number':
            #    If statement to select the figure number map element.

        txtElement.text = '<FNT name = "Arial Narrow" size = "12">Map</FNT>\r\n{}'.format(figureNumber)
        #     Populates the figure number text properties.

    elif txtElement.name == 'Projection':
        #    If statement to select the figure number map element.

        if mapProjection[8:25] == "XXXXXX":

            txtElement.text = 'XXXXXXX {}'.format(mapProjection[26:28])
            #     Populates the figure number text properties.

        elif mapProjection[8:20] == "XXXXXXX":

            txtElement.text = "XXXXXXX"

        else:

            txtElement.text = "Unknown"

    else:

        continue
        #    Continues with the loop

    arcpy.AddMessage(mapProjection)

    arcpy.AddMessage(mapProjection[8:20])

    arcpy.AddMessage("...Saving MXD...")
    #    Prints message to screen.

    mxd.save()
    #    Save the above changes to the new mxd

    arcpy.AddMessage("...Finished Creating Map...")
    #    Prints message to screen.


except:


    tb = sys.exc_info()[2]
    tbinfo = traceback.format_tb(tb)[0]
    pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n     " +        str(sys.exc_type) + ": " + str(sys.exc_value) + "\n"
    msgs = "ARCPY ERRORS:\n" + arcpy.GetMessages(2) + "\n"

    arcpy.AddError(msgs)
    arcpy.AddError(pymsg)

    print msgs
    print pymsg

   arcpy.AddMessage(arcpy.GetMessages(1))
   print arcpy.GetMessages(1)
2

I would offer a hybrid solution.. Write your python to be executed from the command line then create a form that collects the required information and executes the python.

The difficult part of the python is the lack of forms; ArcObjects could do this but the code would be easily ten times as long.. I would suggest it's easier to use a quick form for what it's good for and a python script for what that's good for.

I have used this method for C++ tools, I wrote the tools for console (command line) and newer users (younger users) are scared of command line so I put together a quick form in Visual Studio that compiles a batch file then executes it - saved a lot of time rewriting existing (working, debugged) tools in C# or MFC.

Distribute your tool with the python script then use the tool location to call the python file with arguments.

Not the answer you're looking for? Browse other questions tagged or ask your own question.