Select to view content in your preferred language

How to get symbology and data source with python?

3851
6
Jump to solution
02-06-2011 02:49 PM
RyanChan
Emerging Contributor
I am wondering if it is possible for python to return the symbology and the data source information of a existing layer file? I search through gp.describe but there are no properties and methods that return symbology and data source. I simply want the value field of the symbology and the shapefile data source to be printed on the interactive window. Can anyone help?
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
BradPosthumus
Frequent Contributor
Assuming when you say layer file it means the ".lyr" type, if you have comtypes installed you can use the code below. I simplified it from existing code I had lying around so you'll need to add error-checking at some point.

http://sourceforge.net/projects/comtypes/

def openLayerFile(strLayerFile):
    objLayerFile = comtypes.client.CreateObject(esriCarto.LayerFile, interface=esriCarto.ILayerFile)
    objLayerFile.Open(strLayerFile)
    return objLayerFile

def getValueField(objLayer):
    objFeatureLayer = objLayer.QueryInterface(esriCarto.IFeatureLayer)
    objGeoFeatureLayer = objLayer.QueryInterface(esriCarto.IGeoFeatureLayer)
    objFeatureRenderer = objGeoFeatureLayer.Renderer
    try:
        objRenderer = objFeatureRenderer.QueryInterface(esriCarto.IUniqueValueRenderer)
        return objRenderer.Field(0)
    except:
        try:
            objRenderer = objFeatureRenderer.QueryInterface(esriCarto.IClassBreaksRenderer)
            return objRenderer.Field
        except:
            return ""

def getDataSource(objLayer):
    objFeatureLayer = objLayer.QueryInterface(esriCarto.IFeatureLayer)
    objDataLayer = objFeatureLayer.QueryInterface(esriCarto.IDataLayer)
    objDatasetName = objDataLayer.DataSourceName.QueryInterface(esriGeoDatabase.IDatasetName)    
    objWorkspaceName = objDatasetName.WorkspaceName
    strDataSource = os.path.join(objWorkspaceName.PathName, objDatasetName.Name)
    return strDataSource

import comtypes.client
import os
esriCarto = comtypes.client.GetModule(r'C:\Program Files\ArcGIS\com\esriCarto.olb')
esriGeoDatabase = comtypes.client.GetModule(r'C:\Program Files\ArcGIS\com\esriGeoDatabase.olb')

strLayerFile = r"C:\Temp\test.lyr"
objLayerFile = openLayerFile(strLayerFile)
objLayer = objLayerFile.Layer

print getValueField(objLayer)
print getDataSource(objLayer)

del objLayer
del objLayerFile

View solution in original post

6 Replies
NiklasNorrthon
Frequent Contributor
In ArcGIS 9.x no.

In ArcGIS 10 you can get the datasource (look up "arcpy.mapping"), but not the symbology .

There are workarounds using the win32com.client module to access ArcObject's com interface directly, but that will make your scripts complicated, and probably not worth the effert, since you can do the same thing easier in C# or VB.
0 Kudos
BradPosthumus
Frequent Contributor
Assuming when you say layer file it means the ".lyr" type, if you have comtypes installed you can use the code below. I simplified it from existing code I had lying around so you'll need to add error-checking at some point.

http://sourceforge.net/projects/comtypes/

def openLayerFile(strLayerFile):
    objLayerFile = comtypes.client.CreateObject(esriCarto.LayerFile, interface=esriCarto.ILayerFile)
    objLayerFile.Open(strLayerFile)
    return objLayerFile

def getValueField(objLayer):
    objFeatureLayer = objLayer.QueryInterface(esriCarto.IFeatureLayer)
    objGeoFeatureLayer = objLayer.QueryInterface(esriCarto.IGeoFeatureLayer)
    objFeatureRenderer = objGeoFeatureLayer.Renderer
    try:
        objRenderer = objFeatureRenderer.QueryInterface(esriCarto.IUniqueValueRenderer)
        return objRenderer.Field(0)
    except:
        try:
            objRenderer = objFeatureRenderer.QueryInterface(esriCarto.IClassBreaksRenderer)
            return objRenderer.Field
        except:
            return ""

def getDataSource(objLayer):
    objFeatureLayer = objLayer.QueryInterface(esriCarto.IFeatureLayer)
    objDataLayer = objFeatureLayer.QueryInterface(esriCarto.IDataLayer)
    objDatasetName = objDataLayer.DataSourceName.QueryInterface(esriGeoDatabase.IDatasetName)    
    objWorkspaceName = objDatasetName.WorkspaceName
    strDataSource = os.path.join(objWorkspaceName.PathName, objDatasetName.Name)
    return strDataSource

import comtypes.client
import os
esriCarto = comtypes.client.GetModule(r'C:\Program Files\ArcGIS\com\esriCarto.olb')
esriGeoDatabase = comtypes.client.GetModule(r'C:\Program Files\ArcGIS\com\esriGeoDatabase.olb')

strLayerFile = r"C:\Temp\test.lyr"
objLayerFile = openLayerFile(strLayerFile)
objLayer = objLayerFile.Layer

print getValueField(objLayer)
print getDataSource(objLayer)

del objLayer
del objLayerFile
RyanChan
Emerging Contributor
Assuming when you say layer file it means the ".lyr" type, if you have comtypes installed you can use the code below. I simplified it from existing code I had lying around so you'll need to add error-checking at some point.

http://sourceforge.net/projects/comtypes/

def openLayerFile(strLayerFile):
    objLayerFile = comtypes.client.CreateObject(esriCarto.LayerFile, interface=esriCarto.ILayerFile)
    objLayerFile.Open(strLayerFile)
    return objLayerFile

def getValueField(objLayer):
    objFeatureLayer = objLayer.QueryInterface(esriCarto.IFeatureLayer)
    objGeoFeatureLayer = objLayer.QueryInterface(esriCarto.IGeoFeatureLayer)
    objFeatureRenderer = objGeoFeatureLayer.Renderer
    try:
        objRenderer = objFeatureRenderer.QueryInterface(esriCarto.IUniqueValueRenderer)
        return objRenderer.Field(0)
    except:
        try:
            objRenderer = objFeatureRenderer.QueryInterface(esriCarto.IClassBreaksRenderer)
            return objRenderer.Field
        except:
            return ""

def getDataSource(objLayer):
    objFeatureLayer = objLayer.QueryInterface(esriCarto.IFeatureLayer)
    objDataLayer = objFeatureLayer.QueryInterface(esriCarto.IDataLayer)
    objDatasetName = objDataLayer.DataSourceName.QueryInterface(esriGeoDatabase.IDatasetName)    
    objWorkspaceName = objDatasetName.WorkspaceName
    strDataSource = os.path.join(objWorkspaceName.PathName, objDatasetName.Name)
    return strDataSource

import comtypes.client
import os
esriCarto = comtypes.client.GetModule(r'C:\Program Files\ArcGIS\com\esriCarto.olb')
esriGeoDatabase = comtypes.client.GetModule(r'C:\Program Files\ArcGIS\com\esriGeoDatabase.olb')

strLayerFile = r"C:\Temp\test.lyr"
objLayerFile = openLayerFile(strLayerFile)
objLayer = objLayerFile.Layer

print getValueField(objLayer)
print getDataSource(objLayer)

del objLayer
del objLayerFile


Thank you so much for your help. This works well with my layer files with single layer.
But I am greedy to know if its possible to read group layer files? It seems that errors occur when opening the group layer files.
BradPosthumus
Frequent Contributor
Good point about the layerfiles containing a group of layers. I've added a function that allows it to also extract all layers if it's a group layer. It's recursive so it should work with nested group layers within a group layer.

Note that it's the ICompositeLayer interface, not IGroupLayer, that allows you to extract individual layers from a group layer. IGroupLayer simply accesses the general layer properties of the group.

def openLayerFile(strLayerFile):
    objLayerFile = comtypes.client.CreateObject(esriCarto.LayerFile, interface=esriCarto.ILayerFile)
    objLayerFile.Open(strLayerFile)
    return objLayerFile

def getLayers(objLayer):
    """ Returns a list of layers from a layer file"""
    colLayerList = []
    try:
        objCompositeLayer = objLayer.QueryInterface(esriCarto.ICompositeLayer)
        for i in range(objCompositeLayer.Count):
            objCurrentLayer  = objCompositeLayer.Layer(i)
            try:
                objNestedCompositeLayer = objCurrentLayer.QueryInterface(esriCarto.ICompositeLayer)
                colLayersInGroup = getLayers(objCurrentLayer)
                colLayerList += colLayersInGroup
            except:
                colLayerList.append(objCurrentLayer)
    except:
        colLayerList.append(objLayer)
    return colLayerList
                            
def getValueField(objLayer):
    objFeatureLayer = objLayer.QueryInterface(esriCarto.IFeatureLayer)
    objGeoFeatureLayer = objLayer.QueryInterface(esriCarto.IGeoFeatureLayer)
    objFeatureRenderer = objGeoFeatureLayer.Renderer
    try:
        objRenderer = objFeatureRenderer.QueryInterface(esriCarto.IUniqueValueRenderer)
        return objRenderer.Field(0)
    except:
        try:
            objRenderer = objFeatureRenderer.QueryInterface(esriCarto.IClassBreaksRenderer)
            return objRenderer.Field
        except:
            return ""

def getDataSource(objLayer):
    objFeatureLayer = objLayer.QueryInterface(esriCarto.IFeatureLayer)
    objDataLayer = objFeatureLayer.QueryInterface(esriCarto.IDataLayer)
    objDatasetName = objDataLayer.DataSourceName.QueryInterface(esriGeoDatabase.IDatasetName)    
    objWorkspaceName = objDatasetName.WorkspaceName
    strDataSource = os.path.join(objWorkspaceName.PathName, objDatasetName.Name)
    return strDataSource

import comtypes.client
import os
esriCarto = comtypes.client.GetModule(r'C:\Program Files\ArcGIS\com\esriCarto.olb')
esriGeoDatabase = comtypes.client.GetModule(r'C:\Program Files\ArcGIS\com\esriGeoDatabase.olb')

strLayerFile = r"C:\Temp\testGroup.lyr"
objLayerFile = openLayerFile(strLayerFile)
colLayers = getLayers(objLayerFile.Layer)

for objLayer in colLayers:
    print objLayer.Name
    print getValueField(objLayer)
    print getDataSource(objLayer)

del objLayer
del objLayerFile
0 Kudos
RyanChan
Emerging Contributor
Good point about the layerfiles containing a group of layers. I've added a function that allows it to also extract all layers if it's a group layer. It's recursive so it should work with nested group layers within a group layer.

Note that it's the ICompositeLayer interface, not IGroupLayer, that allows you to extract individual layers from a group layer. IGroupLayer simply accesses the general layer properties of the group.


Thank you so much for your help Brad. This is so amazing. I really appreciate your help.
0 Kudos
George_ChandeepCorea
Occasional Contributor
Cheers,

Going along with what's been asked and commented on here - In an active Arc Map session - I want to change the symbology of a layer which is repeated multiple times in an mxd. Can I do this?

The basic code I have for getting the layers is below. This is running within ArcMap (not as a .py script)

myMXD = arcpy.mapping.MapDocument("Current")
lstDataFrames=arcpy.mapping.ListDataFrames(myMXD)
lstLayers=arcpy.mapping.ListLayers(myMXD)

hazardLayer=arcpy.mapping.ListLayers(myMXD,'*Haz*')

allFrames=arcpy.mapping.ListDataFrames(myMXD)

for dataFrame in allFrames:
...  myMXD.activeView=dataFrame
...  for mapLayer in hazardLayer:
     ...  mapLayer.visible=False



This just changes the visibility to off...can I change the color for example to some RGB value?

Thanks,
0 Kudos