I wrote a Python function using comtypes to access ArcObjects to programmatically change the size of layer symbols in an MXD. The function works great in the Python window of ArcMap. However, I need to do this stand alone to do this for many MXD's.

Using arcpy I can open an MXD in memory like this:

mxd = arcpy.mapping.MapDocument(r'C:\some_folder\map.mxd)

I need to figure out how to do the above using ArcObjects (except return an instance of Application/IMxApplication). In my ArcObjects function, I am starting with a reference to the current open document. However, I cannot figure out how to do this without having a map document open.

I thought I could do something like this (using my own version of snippets):

import arcobjects
import comtypes.gen.esriFramework as esriFramework
import comtypes.gen.esriArcMap as esriArcMap
app = arcobjects.NewObj(esriArcMap.Application, esriFramework.IApplication) #this isn't doing the trick

And then calling app.OpenDocument() to point to the file path to actually open the MXD. This is not working and I do not know enough about initializing things in ArcObjects to know what I'm doing wrong. I know I cannot access anything from the AppROT to get a reference to the current running application because ArcMap/Catalog are not open.

In order to be able to call my function to set the symbol sizes, I need to pass in a reference to an IApplication instance (which I normally get this interface by using GetApp() or GetCurrentApp()). I cannot seem to find code samples for this anywhere. Does anyone know how to do this stand alone in Python?

Here is what I'm using to set the symbol sizes:

def setSymbolSize(pApp, layer_names=[], pointSize=12, lineWidth=1, autoSave=True):
    """sets the size/width of simple esri Marker or Line symbols

        pApp -- open mxd instance, must be of type esriArcMapUI.IMxApplication

        layer_names -- list of layer names to set size of as they appear in TOC.
        pointSize -- size for all point layers specified.  Default is 12
        lineWidth -- width for all line layers specified.  Default is 1
        autoSave -- option to save document automatically after making changes.
            Default is True.
    import comtypes.gen.esriDisplay as esriDisplay
    import comtypes.gen.esriArcMapUI as esriArcMapUI
    import comtypes.gen.esriCarto as esriCarto

    if isinstance(layer_names, (basestring)):
        layer_names = [layer_names]

    # defaults for point (shapeType 1) is 12, default for line (shapeType 3) is 2
    defaultSymbol = {1: esriDisplay.IMarkerSymbol,
                     3: esriDisplay.ILineSymbol}

    # iterate through layer list
    for lyr in iterLayers(pApp):

        if lyr.Name in layer_names:

            # cast to esriCarto.IGeoFeatureLayer to get renderer
            flyr = CType(lyr, esriCarto.IFeatureLayer2)
            iGeo = CType(lyr, esriCarto.IGeoFeatureLayer)
            renderer = iGeo.Renderer

            # cast to simple renderer and then to simple symbol
            simple = CType(renderer, esriCarto.ISimpleRenderer).Symbol

            # cast to marker symbol interface and set size or width
            marker = CType(simple, defaultSymbol[flyr.ShapeType])
            if flyr.ShapeType == 1 and pointSize is not None:
                marker.Size = pointSize
            elif flyr.ShapeType == 3 and lineWidth is not None:
                marker.Width = lineWidth

    # refresh Map
    pDoc = pApp.Document
    pMxDoc = CType(pDoc, esriArcMapUI.IMxDocument)

    if autoSave in (True, 1):

1 Answer 1


Something like the following should work:

import comtypes.gen.esriCarto as esriCarto
pMapDocument = CreateObject(esriCarto.MapDocument, esriCarto.IMapDocument)
#Do stuff
  • Thanks! That is way too easy, I was not aware of the MapDocument class from esriCarto.
    – crmackey
    Jan 18, 2016 at 22:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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