6

I am wanting to take a symbolized layer in an mxd, and save it's symbol color (like a polygon fill) into its attribute table as an RGB value. My goal is to use this value in MapInfo to symbolize it's features via Discover.

I can't see any obvious way of using the ArcPy mapping module to read the particular values. Has anyone had a hack at building a simple modern solution?

  • How's your .net? Access to the IColor from the UniqueValuesRenderer is available from .net (vb.net, c#). There are ways of wrapping these objects for python but that's way advanced python! – Michael Stimson Dec 4 '14 at 4:53
  • My .net is dodgy. But it is food for thought. Thank you for the key words, I will look into it. – GISI Dec 4 '14 at 5:34
  • If you've got a VBA license it might be easier. Should this be the case I could put a little bit of code together. – Michael Stimson Dec 4 '14 at 5:35
  • Alas, no we don't have a licence. But, it was very kind of you to offer. Thank you. – GISI Dec 4 '14 at 5:43
  • This is a good question but I think it is a duplicate of gis.stackexchange.com/questions/71352/… and that you appear to be asking it to meet requirements similar to these gis.stackexchange.com/questions/27807/… – PolyGeo Dec 4 '14 at 5:50
6

I only need to get RGB values for polygon features. In particular solid fill vegetation and geology. I made a rough as guts ArcPy tool that fits my purpose.

The tool gets the user to nominate their layer and symbology field in ArcMap. The tool then loops through groups of "like sybology" values exporting them as rasters and interrogating them for their RGB values. These are then placed in the attribute table.

3 parameters must be passed into a script tool, which is used in a current mxd:

  1. 0: A Folder (used for temp files including new file gdb & layer files)
  2. 1: A layer (from an open mxd)
  3. 2: The nominated layers symbolology field

Code Sample:

    import arcpy
    from arcpy import env
    arcpy.gp.overwriteOutput = True

    arcpy.AddMessage("STARTED")
    arcpy.AddMessage(" ")
    arcpy.AddMessage("======================================================================")
    ##############
    Folder = arcpy.GetParameterAsText(0)
    if Folder == '#' or not Folder:
        Folder = "C:\\Data"

    ##############
    GDB = Folder+"\\TempGDB.gdb"
    if arcpy.Exists(GDB):
        arcpy.AddMessage(GDB)
    else:
        arcpy.CreateFileGDB_management(Folder, "TempGDB")
        arcpy.AddMessage("GDB MADE")

    # MUST BE IN ARCMAP
    ##############
    InPolyLayer = arcpy.GetParameterAsText(1)
    desc = arcpy.Describe(InPolyLayer)
    LayerPath = desc.catalogPath
    arcpy.AddMessage("Path: "+ LayerPath)
    spatial_ref = arcpy.Describe(LayerPath).spatialReference
    arcpy.AddMessage("Spatial Reference: "+spatial_ref.name)
    sr = arcpy.SpatialReference(spatial_ref.factoryCode)

    # Must Be The Symbology Field From "InPolyLayer"
    ##############
    FieldName = arcpy.GetParameterAsText(2)
    arcpy.AddMessage(FieldName)

    fields = arcpy.ListFields(LayerPath)
    for field in fields:
        if field.name == FieldName:
            FType = (field.type)
            FPrecision = (field.precision)
            FScale = (field.scale)
            FLength = (field.length)
            FNull = (field.isNullable)
            arcpy.AddMessage("Type: "+str(FType))
            arcpy.AddMessage("Precision: "+str(FPrecision))
            arcpy.AddMessage("Scale: "+str(FScale))
            arcpy.AddMessage("Lenght: "+str(FLength))
            arcpy.AddMessage("Null: "+ str(FNull))

    TempTileFC = GDB+"\\TempTileFC"
    if arcpy.Exists(TempTileFC):
        arcpy.Delete_management(TempTileFC)

    ### Varibles
    # Temps
    TempFrequency = GDB+"\\TempFrequency"
    if arcpy.Exists(TempFrequency):
        arcpy.Delete_management(TempFrequency)

    TempP = GDB+"\\TempP"
    if arcpy.Exists(TempP):
        arcpy.Delete_management(TempP)

    TRaster = Folder+"\\TempRaster.tif"
    arcpy.AddMessage("TEMPS SET")

    # Layers
    mxd = arcpy.mapping.MapDocument ("CURRENT")
    df = arcpy.mapping.ListDataFrames(mxd)[0]
    TempLayerName = "TempLayer"
    FreqView = "FreqView"
    TempLayerFile = Folder+"\\TempLayerFile.lyr"
    TempLayerFileLayer = "TempLayerFileLayer"
    TempLayerCloneName = "TempLayerClone"

    #Lyr for raster
    arcpy.SaveToLayerFile_management(InPolyLayer, TempLayerFile, "ABSOLUTE")


    # Fields
    FieldNameR = str(FieldName)+"_R" #Check for, and create RGB Field
    FieldNameG = str(FieldName)+"_G" #Check for, and create RGB Field
    FieldNameB = str(FieldName)+"_B" #Check for, and create RGB Field

    if len(arcpy.ListFields(InPolyLayer,FieldNameR)) == 0:
        arcpy.AddField_management (InPolyLayer, FieldNameR, "short")
        arcpy.AddMessage(FieldNameR +" field created")
    else:
        arcpy.AddMessage(FieldNameR +" field exists")

    if len(arcpy.ListFields(InPolyLayer,FieldNameG)) == 0:
        arcpy.AddField_management (InPolyLayer, FieldNameG, "short")
        arcpy.AddMessage(FieldNameG +" field created")
    else:
        arcpy.AddMessage(FieldNameG +" field exists")

    if len(arcpy.ListFields(InPolyLayer,FieldNameB)) == 0:
        arcpy.AddField_management (InPolyLayer, FieldNameB, "short")
        arcpy.AddMessage(FieldNameB +" field created")
    else:
        arcpy.AddMessage(FieldNameB +" field exists")
    arcpy.AddMessage(" ")
    arcpy.AddMessage("======================================================================")
    arcpy.AddMessage(" ")
    arcpy.AddMessage(" * FREQUENCIES & TEMP CARTO TILES")

    arcpy.Frequency_analysis(LayerPath, TempFrequency, FieldName, "")
    arcpy.AddMessage("   - Symbology Frequency Analysis Completed")

    # Make Polygon For Layer Symbol Export
    xExtent = df.extent
    pnt1 = arcpy.Point(xExtent.XMin , xExtent.YMin)
    pnt2 = arcpy.Point(xExtent.XMax , xExtent.YMin)
    pnt3 = arcpy.Point(xExtent.XMax , xExtent.YMax)
    pnt4 = arcpy.Point(xExtent.XMin , xExtent.YMax)
    array = arcpy.Array()
    array.add(pnt1)
    array.add(pnt2)
    array.add(pnt3)
    array.add(pnt4)
    array.add(pnt1)
    SYMExtent = arcpy.Polygon(array)
    arcpy.FeatureClassToFeatureClass_conversion (SYMExtent, GDB, "TempTileFC", "", "", "")
    arcpy.AddMessage("   - Temp Tile Feature Class: "+str(TempTileFC))
    arcpy.AddField_management (TempTileFC, FieldName, FType, FPrecision, FScale, FLength, "", FNull, "", "")
    arcpy.FeatureToPoint_management (SYMExtent, TempP, "CENTROID")
    TempPCen = arcpy.Describe(TempP)
    CentroidE = TempPCen.extent
    CentroidX = CentroidE.XMin
    CentroidY = CentroidE.YMin
    arcpy.AddMessage("   - Temp Tile Feature Class Field Added:"+str(FieldName))
    arcpy.AddMessage("   - Centroid Feature Class For Raster:"+str(CentroidX)+str(CentroidY))
    sourceLayer = arcpy.mapping.Layer(TempLayerFile)


    arcpy.AddMessage(" ")
    arcpy.AddMessage("======================================================================")
    arcpy.AddMessage(" ")
    arcpy.AddMessage(" * LOOPING VALUES")

    cursor = arcpy.SearchCursor(TempFrequency)
    for row in cursor:
        arcpy.AddMessage(" ")
        arcpy.AddMessage(" --------------")
        rec = row.getValue(FieldName)
        arcpy.AddMessage("   - Frequency Field Name:"+str(FieldName))
        arcpy.AddMessage("   - Frequency Record: "+str(rec))
        TempLayerClone = TempLayerCloneName+str(rec)
        arcpy.AddMessage("   - Temp Layer:"+str(TempLayerClone))

        ### We don't need to delete the geom. just write the new value.
        FieldExp ="'"+str(rec)+"'"
        arcpy.AddMessage("   - Calculate Tile Field Expression: "+str(FieldExp))
        arcpy.AddMessage("   - Temp Tile: " +str(TempTileFC))

        arcpy.CalculateField_management(TempTileFC, FieldName, FieldExp, "PYTHON_9.3","")

        # Remove Layer Test
        for df in arcpy.mapping.ListDataFrames(mxd):
            for lyr in arcpy.mapping.ListLayers(mxd, "", df):
                if str(lyr)==TempLayerClone:
                    arcpy.mapping.RemoveLayer(df, lyr)
        if arcpy.Exists(TempLayerClone):
            arcpy.Delete_management(TempLayerClone)

        # Make Layer
        arcpy.MakeFeatureLayer_management (TempTileFC, TempLayerClone, "", "", "") #  Make Layer
        FeatureClassLayerMapping = arcpy.mapping.Layer(TempLayerClone)
        arcpy.mapping.AddLayer(df, FeatureClassLayerMapping, "TOP") # Layer At Top
        arcpy.AddMessage("   - Layer Added")

        # Update
        df2 = arcpy.mapping.ListDataFrames(mxd)[0]
        updateLayer2 = arcpy.mapping.ListLayers(mxd, TempLayerClone, df)[0]
        arcpy.mapping.UpdateLayer(df2, updateLayer2, sourceLayer, "True") # Carto Matches

        ################ NUMERIC OR TEXT
        if FType == "String":
            arcpy.AddMessage("   - IS String")
            ## 10.1
            DefQURY = (("""\"{0}"='{1}'""").format(FieldName,rec)) #TEXT FIELDS
        elif FType == "Text":
            arcpy.AddMessage("   - IS TEXT")
            ## 10.1
            DefQURY = (("""\"{0}"='{1}'""").format(FieldName,rec)) #TEXT FIELDS
        else:
            arcpy.AddMessage("   - IS NOT TEXT")
            DefQURY = (("""\"{0}"={1}""").format(FieldName,rec))   #NUMERIC FIELDS

        arcpy.AddMessage("   - Layer Updated")
        arcpy.AddMessage("   - Selection Qu:" +str(DefQURY))
        arcpy.SelectLayerByAttribute_management (updateLayer2, "NEW_SELECTION", DefQURY ) # Select & Zoom

        df.zoomToSelectedFeatures()
        arcpy.SelectLayerByAttribute_management (updateLayer2, "CLEAR_SELECTION")
        arcpy.RefreshActiveView()
        arcpy.AddMessage("   - Zoomed")

        #Raster
        if arcpy.Exists(TRaster):
            arcpy.Delete_management(TRaster)
        arcpy.mapping.ExportToTIFF(mxd, TRaster, df2,  df_export_width=600,df_export_height=600,geoTIFF_tags=True)
        arcpy.AddMessage("   - RGB Raster Exported")
        arcpy.AddMessage("   - RGB Raster: "+TRaster)

        Centroidf = ("{0} {1}".format(CentroidX,CentroidY))
        RValues = arcpy.GetCellValue_management(TRaster, Centroidf, "1")
        GValues = arcpy.GetCellValue_management(TRaster, Centroidf, "2")
        BValues = arcpy.GetCellValue_management(TRaster, Centroidf, "3")
        arcpy.AddMessage("   - R: "+str(RValues))
        arcpy.AddMessage("   - G: "+str(GValues))
        arcpy.AddMessage("   - B: "+str(BValues))

        #Selection
        arcpy.SelectLayerByAttribute_management (InPolyLayer, "NEW_SELECTION", DefQURY )
        arcpy.AddMessage("   - Selection: "+ InPolyLayer)
        arcpy.AddMessage("   - Def: "+ DefQURY)

        arcpy.CalculateField_management(InPolyLayer, FieldNameR, RValues, "PYTHON_9.3")
        arcpy.CalculateField_management(InPolyLayer, FieldNameG, GValues, "PYTHON_9.3")
        arcpy.CalculateField_management(InPolyLayer, FieldNameB, BValues, "PYTHON_9.3")
        arcpy.SelectLayerByAttribute_management (InPolyLayer, "CLEAR_SELECTION", DefQURY )
        arcpy.AddMessage("   - Calculated & Cleared")

        # Remove Layer
        for df3 in arcpy.mapping.ListDataFrames(mxd):
            for lyr in arcpy.mapping.ListLayers(mxd, "", df3):
                if str(lyr)==TempLayerClone:
                    arcpy.mapping.RemoveLayer(df3, lyr)

        del TempLayerClone
        del FeatureClassLayerMapping
        del df2, df3

        arcpy.AddMessage("   - Removed & Cleared")

    ## if current is not saved then the tool will fail
        mxd.save()

Example: enter image description here

  • 1
    I wrote the above py to be a script tool. The 3 exposed parameters plug into the toolbox tool nicely. Here's how you make a script tool: help.arcgis.com/EN/arcgisdesktop/10.0/help/index.html#/… – GISI Aug 28 '15 at 7:22
  • Can you write down some information what types of parameters did you use for Symbology field when creating a script tool. – Miha Kl Feb 6 '17 at 17:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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