Hello all,
I am trying to add a raster layer to a map in Pro (3.1) and then update the renderer to be RasterClassifyColorizer. Once that is done, I then try to add a number breaks, update the upper bounds values of the breaks, labels and colors for the breaks. Once done the legend for the raster looks right (right number of classes, right labels and colors) but the raster values seem to be allocated to the wrong classes.
The data is a floating point raster stored in a TIFF representing wind speed in meters per second.
I am doing this via a cell in a Notebook.
The image below shows the rater added manually from the catalog, with a data range of 6.1 to 10.1
The following image shows the same raster added via the code, showing a large area under 2 meters a second wind speed, which shouldn't be possible:
Included is the code from the cell. The pathway to the TIFF is stored in the variable "rdSaWSatX"
# Access the Project and Map objects to add the layers to
p = arcpy.mp.ArcGISProject("CURRENT")
m = p.listMaps("Map")[0]
# Study Area (AOI) Wind Speed raster and
# 1. Give it a "layer name" for display in the map
# 2. Make a raster layer with name
# 3. Access the layer object
# 4. Access the symbology object
# 5. Modify the symbology breaks, lables, and colors
# 6. Apply the modified symbology
# Layer name text
lyrnSaWSatX = f"Study area Wind Speed at {fltHubHeight}m"
# Create Raster Layer
lyrSaWSatX = arcpy.MakeRasterLayer_management(rdSaWSatX, lyrnSaWSatX)
# Add raster layer to the map
m.addLayer(lyrSaWSatX[0], "TOP")
# Access the layer object in the map
lmSaWSatX = m.listLayers(lyrnSaWSatX)[0]
# Access the symbology object
symSaWSatX = lmSaWSatX.symbology
# Update the colorizer to be a classifed one
symSaWSatX.updateColorizer('RasterClassifyColorizer')
symSaWSatX.colorizer.classificationField = "Value"
# Create lists for break values, labels, and colors
lsWSBreakValues = [2,4,6,8,10,12,14,16,18,20,26]
lsWSBreakLabels = []
for ws in lsWSBreakValues:
label = "<= " + str(ws) + "m/s"
lsWSBreakLabels.append(label)
del label
lsWSBreakColours = [[190,232,255,100],
[175,245,177,100],
[171,253,102,100],
[212,243,38,100],
[241,222,0,100],
[251,185,0,100],
[255,113,0,100],
[255,19,0,100],
[255,0,88,100],
[255,0,197,100],
[168,0,132,100]]
# Create breaks in map layer
symSaWSatX.colorizer.breakCount = len(lsWSBreakValues)
symCounter = 0
# for each break get values from lists to allocate break value, label and color
for brk in symSaWSatX.colorizer.classBreaks:
brk.upperBound = lsWSBreakValues[symCounter]
brk.label = lsWSBreakLabels[symCounter]
brk.color = {'RGB' : lsWSBreakColours[symCounter]}
symCounter += 1
# Apply the updated symbology to the map layer
lmSaWSatX.symbology = symSaWSatX
and I have arcpy, os and math packages imported.
Any help would be greatly appreciated,
Nick
Solved! Go to Solution.
Doing a test on a raster, it seems to work ok for me. One thing I'd suggest is to be more explicit with the upper boundary, label, and color by using a dictionary. This method prevents a list index being off and reduces some looping.
breaks = {0: {'upper': 2, 'color': [190, 232, 255, 100]},
1: {'upper': 4, 'color': [175, 245, 177, 100]},
2: {'upper': 6, 'color': [171, 253, 102, 100]},
3: {'upper': 8, 'color': [212, 243, 38, 100]},
4: {'upper': 10, 'color': [241, 222, 0, 100]},
5: {'upper': 12, 'color': [251, 185, 0, 100]},
6: {'upper': 14, 'color': [255, 113, 0, 100]},
7: {'upper': 16, 'color': [255, 19, 0, 100]},
8: {'upper': 18, 'color': [255, 0, 88, 100]},
9: {'upper': 20, 'color': [255, 0, 197, 100]},
10: {'upper': 26, 'color': [168, 0, 132, 100]}
}
# Create breaks in map layer
symSaWSatX.colorizer.breakCount = len(breaks)
# for each break get values from lists to allocate break value, label and color
for i, brk in enumerate(symSaWSatX.colorizer.classBreaks):
brk.upperBound = breaks[i]['upper']
brk.label = label = "<= " + str(breaks[i]['upper']) + "m/s"
brk.color = {'RGB': breaks[i]['color']}
# Apply the updated symbology to the map layer
lmSaWSatX.symbology = symSaWSatX
p.save()
Doing a test on a raster, it seems to work ok for me. One thing I'd suggest is to be more explicit with the upper boundary, label, and color by using a dictionary. This method prevents a list index being off and reduces some looping.
breaks = {0: {'upper': 2, 'color': [190, 232, 255, 100]},
1: {'upper': 4, 'color': [175, 245, 177, 100]},
2: {'upper': 6, 'color': [171, 253, 102, 100]},
3: {'upper': 8, 'color': [212, 243, 38, 100]},
4: {'upper': 10, 'color': [241, 222, 0, 100]},
5: {'upper': 12, 'color': [251, 185, 0, 100]},
6: {'upper': 14, 'color': [255, 113, 0, 100]},
7: {'upper': 16, 'color': [255, 19, 0, 100]},
8: {'upper': 18, 'color': [255, 0, 88, 100]},
9: {'upper': 20, 'color': [255, 0, 197, 100]},
10: {'upper': 26, 'color': [168, 0, 132, 100]}
}
# Create breaks in map layer
symSaWSatX.colorizer.breakCount = len(breaks)
# for each break get values from lists to allocate break value, label and color
for i, brk in enumerate(symSaWSatX.colorizer.classBreaks):
brk.upperBound = breaks[i]['upper']
brk.label = label = "<= " + str(breaks[i]['upper']) + "m/s"
brk.color = {'RGB': breaks[i]['color']}
# Apply the updated symbology to the map layer
lmSaWSatX.symbology = symSaWSatX
p.save()
Many thanks Jeff. I applied your structure and had success. interestingly, I am using your structure for another script but for a GraduatedColorsRenderer on a polygon layer and I am still having issues where some classes aren't shown. I am going to this another post though as it is off topic.
Many Thanks,
Nick