0

I have a lot of output land cover raster files in .tif and want to only select the .tif files and change color map of all of them by taking a script that has attributes for Red, Green, Blue and LC Type. I have a list of raster values for colors and the associated land cover type; however, I know I am supposed to take the proportion of each RGB value out of 255 to properly assign the new color. I want to loop through each .tif file create the fields (Red, Green, Blue, and LC Type) and assign the appropriate value using a dictionary in ArcPy.

filepath = 'C:/directory'
env.workspace =filepath
for filename in os.listdir(filepath):
  if filename.endswith('.tif')


dictionary = {
    1: [255,0,0 'water'],
    2: [209, 255, 115 'Evergreen Needleleaf Forest'],
    3: [85,255,0 'Evergreen Broadleaf Forest'],
    4: [112,168,0 'Deciduous Needleleaf Forest'],
    5: [190,255,232 'Deciduous Broadleaf Forest'],
    6: [255,211,127 'Mixed Forest'],
    7: [0,255,0'Woodland'],
    8: [0,99,0 'Wooded Grassland'],
    9: [214,157,188 'Closed Shrubland'],
    10: [197, 0, 255'Open Shrubland'],
    11: [0,77,168 'Grassland'],
    12: [0,132,168 'Cropland'],
    13: [190,210,255 'Bare Ground'],
    14: [255,170,0 'Urban and Built-up'],
    17: [255,170,0 'Urban and Built-up']}
#create the four attributes, R,G,B, and LC
#create an update cursor
#loop through each .tif file create fields and assign values to records
PolyGeo
  • 65,136
  • 29
  • 109
  • 338
Joe Ir
  • 1
  • Related : https://gis.stackexchange.com/questions/123606/symbolizing-using-rgb-values-from-excel-in-arcgis-desktop/123612#123612 however there is a process of applying a color table http://desktop.arcgis.com/en/arcmap/10.3/manage-data/raster-and-images/creating-a-color-map-clr-file.htm that might help with what you're trying to do. – Michael Stimson Oct 22 '19 at 00:55
  • I am aware that is an option, but that won't really work given number of raster files I have and would be more efficient if I could just loop through the ones in my folder and apply it in this tabular format where I can later add more attributes – Joe Ir Oct 22 '19 at 10:29

1 Answers1

1

I really think a colour table is what you're after, it's just a text file with the same base name as the TIFF image with '.clr' as the extension, when loaded into ArcMap the symbology is automatically imported from the colour file.. From your existing code I have extended to create a color file, build the raster attribute table and then apply the dictionary values to the RAT.

import os, sys, arcpy
filepath            = 'C:/directory'
arcpy.env.workspace = filepath

# note that you need more commas in your dictionary def
# to separate LC code from the blue value
dictionary = {
    1: [255,0,0,'water'],
    2: [209, 255, 115,'Evergreen Needleleaf Forest'],
    3: [85,255,0,'Evergreen Broadleaf Forest'],
    4: [112,168,0,'Deciduous Needleleaf Forest'],
    5: [190,255,232,'Deciduous Broadleaf Forest'],
    6: [255,211,127,'Mixed Forest'],
    7: [0,255,0,'Woodland'],
    8: [0,99,0,'Wooded Grassland'],
    9: [214,157,188,'Closed Shrubland'],
    10: [197, 0, 255,'Open Shrubland'],
    11: [0,77,168,'Grassland'],
    12: [0,132,168,'Cropland'],
    13: [190,210,255,'Bare Ground'],
    14: [255,170,0,'Urban and Built-up'],
    17: [255,170,0,'Urban and Built-up']}

for filename in os.listdir(filepath):
    fN,fE = os.path.splitext(filename)                       # break the name and extension
    if fE.lower == '.tif':                                   # more reliable than endswith
        if arcpy.Describe(filename).isInteger:               # can't build RAT on non-integer rasters
            arcpy.AddMessage('Bulding for {}'.format(filename))

            # add a new RAT and required attributes
            arcpy.BuildRasterAttributeTable_management(filename,'OVERWRITE') 
            arcpy.AddField_management(filename,'R','SHORT')      # add the R,G and B fields
            arcpy.AddField_management(filename,'G','SHORT')      # as data type 'short' which
            arcpy.AddField_management(filename,'B','SHORT')      # is the smallest int type
            arcpy.AddField_management(filename,'LC_Type','TEXT') # Land cover type as text, field names can't have spaces


            # build a colour file to symbolize
            CLRfilename = os.path.join(filepath,fN + '.clr')
            with open (CLRfilename, 'w') as CLR:
                for Detail in dictionary.iterkeys():
                    R,G,B,LC = dictionary[Detail] #unpack this element in the dictionary
                    CLR.write('{} {} {} {}\n'.format(Detail,R,G,B))
            arcpy.AddMessage('Created or overwritten colour file')

            # Iterate the rows in the raster attribute table
            with arcpy.da.UpdateCursor(filename,['value','R','G','B','LC_Type']) as UCur:
                for URow in UCur:
                    ThisIndex = URow[0]                    # the value for this pixel
                    if ThisIndex in dictionary:            # only use values that exist in the dictionary
                        R,G,B,LC = dictionary[ThisIndex]   # unpack this element in the dictionary
                        URow[1]   = R 
                        URow[2]   = G 
                        URow[3]   = B 
                        URow[4]   = LC
                        UCur.updateRow(URow)
        else:
            arcpy.AddWarning("Cannot do {}, it's not an integer type".format(filename))

Then if you need to export any changes to your R,G,B values in your raster dataset you can reexport the colour table like this:

desc  = arcpy.Describe(yourRaster)
cPath = desc.catalogPath # the full path your your raster dataset
CLRfilename = fN + '.clr'# fN already contains the path

with (CLRfilename, 'w') as CLR:
    with arcpy.da.SearchCursor(InRas,['value','R','G','B']) as SCur:
        for SRow in SCur:
            CLR.write('{} {} {} {}\n'.format(SRow[0],SRow[1],SRow[2],SRow[3]))
Michael Stimson
  • 25,566
  • 2
  • 35
  • 74