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
arcobjects.InitStandalone()
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
Required:
pApp -- open mxd instance, must be of type esriArcMapUI.IMxApplication
Optional:
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)
pMxDoc.UpdateContents()
pMxDoc.ActiveView.Refresh()
if autoSave in (True, 1):
pApp.SaveDocument()
return