Wednesday, 7 March 2018

arcgis desktop - Saving a ArcMap layers RGB values into the attribute table


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?



Answer



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


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...