I created a script to perform some geoprocessing, then do some symbology rendering on the geoprocessing results, StreamComp_Name. I was able to change it to graduated color renderer using green_blue_3, which is my own customized graduated color from green to blue. I was wondering how I can make all the positive number as one graduated color, such as green and all the negative number as one graduated color, blue? I attempted it below by changing the setting of HSL color properties for each classBreak item, but for some reason, it didn't work. Please let me know if you have a better idea or if you see the error in my script below . Thanks for your help!
Here is my script for the symbology rendering so far:
l = m.listLayers(StreamComp_Name)[0]
sym = l.symbology
if sym.renderer.type == 'SimpleRenderer':
sym.updateRenderer('GraduatedColorsRenderer')
sym.renderer.classificationField = Comp_Field
sym.renderer.breakCount = 7
sym.renderer.colorRamp = p.listColorRamps('Green_Blue_3')[0]
for brk in sym.renderer.classBreaks:
brk.symbol.outlineColor = {'RGB' : {[0,0,0,100]}
brk.symbol.size = 6
bc=0
gc=0
for brk in sym.renderer.classBreaks:
brk.symbol.size = 6
brk.symbol.outlineColor = {'HSV' : [0, 0, 0, 0]}
if brk.upperBound<=0:
brk.symbol.color = {'HSL':[100,100,33+gc,100]}
else:
brk.symbol.color = {'HSV' : [240-bc, 100, 100, 100]}
gc +=5
bc += 40
l.symbology = sym
Solved! Go to Solution.
This was an interesting problem. I had a similar issue with a raster dataset, where I defined a custom color ramp that ranged from red (for negative values), to transparent (for zero), to blue (for positive values). I would manually set the symbology to Stretched with the Min/Max values of -X and X, so that the color ramp would be centered on zero. But this wouldn't work for grouped Graduated Colors like you are describing, and your data isn't necessarily centered around zero.
I couldn't find a clean way to extract information from a color ramp. The best I could do was make 32 class breaks (the maximum allowed) and extract the color ramp values, then reset back to 7 (or the desired number of) classes. Then we determine how many classes are on either side of 0, and distribute them across our 32 color entries (1-16 being for negative values, and 17-32 for positive values). We also find whatever break is closest to 0 and set it to 0, so no classes will cover both negative and positive values.
I haven't tested this out extensively, but I think there's potential here.
# Set ColorRamp
symTest = l.symbology
symTest.updateRenderer('GraduatedColorsRenderer')
symTest.renderer.colorRamp = p.listColorRamps('Green_Blue_3')[0]
l.symbology = symTest
# Get color ramp information from the max number of breaks (32)
symTest = l.symbology
symTest.renderer.classificationMethod = 'EqualInterval'
symTest.renderer.breakCount = 32
listColors = [b.symbol.color for b in symTest.renderer.classBreaks]
# Set back to desired number of natural breaks
sym = l.symbology
sym.renderer.classificationMethod = 'NaturalBreaks'
numBreaks = 7
sym.renderer.breakCount = numBreaks
# get break values
bvals = [brk.upperBound for brk in sym.renderer.classBreaks]
# find value closest to 0, and set to 0. This way classes can't cross 0.
setZero = min(bvals, key=lambda x:abs(x-0))
bvals = [b if b!=setZero else 0 for b in bvals]
# the number of positive/negative breaks, and the index positions in our 32 entry listColors
numNeg = len([b for b in bvals if b<=0])
numPos = len([b for b in bvals if b>0])
iNeg = 0
iPos = 15
# convert break values to index 0-15 for negatives and 16-31 for positives
for brk in sym.renderer.classBreaks:
# check for and reset closet to zero
if brk.upperBound == setZero:
brk.upperBound = 0
#increment colors along the positive / negative sides of the ramp
if brk.upperBound<=0:
brk.symbol.color = listColors[iNeg]
iNeg = int(iNeg+16/numNeg)
else:
iPos = int(iPos+16/numPos)
brk.symbol.color = listColors[iPos]
brk.label = "<"+str(brk.upperBound)
l.symbology = sym
So you want a 2 class manual break, with the breakpoint to be a value of 0? Something like this might work, if instead of using a color ramp you just defined the two RGB values you want.
blue = [59,154,178,100]
green = [116,160,137,100]
sym.renderer.breakCount = 2
sym.renderer.classBreaks[0].label = "<0"
sym.renderer.classBreaks[0].upperBound = 0
sym.renderer.classBreaks[0].symbol.color = {'RGB' : blue}
sym.renderer.classBreaks[1].label = ">0"
sym.renderer.classBreaks[1].symbol.color = {'RGB' : green}
@BrennanSmith1 Thanks for your help Brennan! I actually want more than two class breaks. However, the class breaks really vary depending on the region I am applying the symbology. What I want to do is break the graduate color (e.g. blue to green) into two groups. The positive numbers will be blue and the negative number will be green, but I also want to show the parameter trends of those groups using graduate color, instead of one solid color. If you have any questions, please let me know. Thanks for your help!
This was an interesting problem. I had a similar issue with a raster dataset, where I defined a custom color ramp that ranged from red (for negative values), to transparent (for zero), to blue (for positive values). I would manually set the symbology to Stretched with the Min/Max values of -X and X, so that the color ramp would be centered on zero. But this wouldn't work for grouped Graduated Colors like you are describing, and your data isn't necessarily centered around zero.
I couldn't find a clean way to extract information from a color ramp. The best I could do was make 32 class breaks (the maximum allowed) and extract the color ramp values, then reset back to 7 (or the desired number of) classes. Then we determine how many classes are on either side of 0, and distribute them across our 32 color entries (1-16 being for negative values, and 17-32 for positive values). We also find whatever break is closest to 0 and set it to 0, so no classes will cover both negative and positive values.
I haven't tested this out extensively, but I think there's potential here.
# Set ColorRamp
symTest = l.symbology
symTest.updateRenderer('GraduatedColorsRenderer')
symTest.renderer.colorRamp = p.listColorRamps('Green_Blue_3')[0]
l.symbology = symTest
# Get color ramp information from the max number of breaks (32)
symTest = l.symbology
symTest.renderer.classificationMethod = 'EqualInterval'
symTest.renderer.breakCount = 32
listColors = [b.symbol.color for b in symTest.renderer.classBreaks]
# Set back to desired number of natural breaks
sym = l.symbology
sym.renderer.classificationMethod = 'NaturalBreaks'
numBreaks = 7
sym.renderer.breakCount = numBreaks
# get break values
bvals = [brk.upperBound for brk in sym.renderer.classBreaks]
# find value closest to 0, and set to 0. This way classes can't cross 0.
setZero = min(bvals, key=lambda x:abs(x-0))
bvals = [b if b!=setZero else 0 for b in bvals]
# the number of positive/negative breaks, and the index positions in our 32 entry listColors
numNeg = len([b for b in bvals if b<=0])
numPos = len([b for b in bvals if b>0])
iNeg = 0
iPos = 15
# convert break values to index 0-15 for negatives and 16-31 for positives
for brk in sym.renderer.classBreaks:
# check for and reset closet to zero
if brk.upperBound == setZero:
brk.upperBound = 0
#increment colors along the positive / negative sides of the ramp
if brk.upperBound<=0:
brk.symbol.color = listColors[iNeg]
iNeg = int(iNeg+16/numNeg)
else:
iPos = int(iPos+16/numPos)
brk.symbol.color = listColors[iPos]
brk.label = "<"+str(brk.upperBound)
l.symbology = sym
I combined my previous method with yours, and it works the way I wanted it to look! Thanks for your help!