Hello,
My goal is to achieve this:
However what I'm currently getting is this:
The issue is that I cannot find any information on how to apply unique value classes into the render.
Currently I'm just making a ramp and applying it, but that doesnt group values and includes <all other values> (of which there are none).
CIMUniqueValueClass[] landcoverClasses = new CIMUniqueValueClass[] {
new CIMUniqueValueClass { Values = new []{new CIMUniqueValue { FieldValues = new []{ "0" } } }, Label = "Cleared" },
new CIMUniqueValueClass { Values = new []{new CIMUniqueValue { FieldValues = new []{ "1" } } }, Label = "Low Vegetation" },
new CIMUniqueValueClass { Values = new []{new CIMUniqueValue { FieldValues = new []{ "2", "3" } } }, Label = "River, Waterway" },
new CIMUniqueValueClass { Values = new []{new CIMUniqueValue { FieldValues = new []{ "1" } } }, Label = "Forested" },
new CIMUniqueValueClass { Values = new []{new CIMUniqueValue { FieldValues = new []{ "2" } } }, Label = "Road" },
new CIMUniqueValueClass { Values = new []{new CIMUniqueValue { FieldValues = new []{ "1" } } }, Label = "Medium Vegetation" },
new CIMUniqueValueClass { Values = new []{new CIMUniqueValue { FieldValues = new []{ "2" } } }, Label = "Swamp" },
};
....
var colorRamp = new CIMFixedColorRamp();
var colors = new List<CIMColor>();
foreach (var cls in landcoverClasses)
switch (cls.Label) {
case "Cleared": //0
colors.Add(CIMColor.CreateRGBColor(255, 0, 0)); break;
case "Low Vegetation": //1
colors.Add(CIMColor.CreateRGBColor(76, 230, 0)); break;
case "River, Waterway": //2,3
colors.Add(CIMColor.CreateRGBColor(0, 92, 230)); break;
case "Forested": //4
colors.Add(CIMColor.CreateRGBColor(255, 170, 0)); break;
case "Road": // 5
colors.Add(CIMColor.CreateRGBColor(110, 110, 110)); break;
case "Medium Vegetation": //6
colors.Add(CIMColor.CreateRGBColor(0, 115, 76)); break;
case "Swamp": //7
colors.Add(CIMColor.CreateRGBColor(115, 223, 255)); break;
default:
colors.Add(CIMColor.CreateGrayColor(130, 100)); break;
}
colorRamp.Colors = colors.ToArray();
UniqueValueRendererDefinition uvr =
new UniqueValueRendererDefinition() {
ValueFields = new string[] { "LANDCOVERTYPE" },
ColorRamp = colorRamp
};
var cimRenderer = featureLayer.CreateRenderer(uvr);
featureLayer.SetRenderer(cimRenderer);
Any help would be appreciated. Thank you.
Try this.
var renderer = layer.CreateRenderer(uvr_def) as CIMUniqueValueRenderer;
foreach (var group in renderer.Groups)
{
foreach(var valueClass in group.Classes)
{
var symbol = valueClass.Symbol.Symbol as CIMPolygonSymbol;
foreach (var symLayer in symbol.SymbolLayers.OfType<CIMSolidFill>())
{
((CIMSolidFill)symLayer).Color.Values[3] = 0;//set the alpha channel to 0
}
}
}
layer.SetRenderer(renderer);
Thanks Charles, that makes the symbol fill transparent. How can I group unique values together so that they share symbology?
When I'm trying to figure out a CIM thing like this I like to replicate the action (if I can) in the UI and then look at the resulting XML in the debugger.
var def = renderer.ToXml(); like so.
You can even copy/paste the xml into an xml editor with colorization if the debugger xml viewer is not adequate. From the xml I look at what changed to tell me what to replicate in the code. Try fiddling with the renderer, for example, and examining the change in the debugger.
There is also a utility here: https://github.com/Esri/arcgis-pro-sdk-cim-viewer that allows you to do just that.
Anyway, the bit you really care about 😉
CIMUniqueValueRenderer renderer = ....;
foreach (var group in renderer.Groups)
{
//let's make half the number of classes...
List<CIMUniqueValueClass> classes = group.Classes.ToList();
List<CIMUniqueValueClass> groupedClasses = new List<CIMUniqueValueClass>();
CIMUniqueValueClass currentClass = null;
var count = 0;
while (count < classes.Count)
{
//even or odd?
if ((count % 2) == 0) {
currentClass = classes[count++];
}
else {
var odd_class = classes[count++];
currentClass.Label = $"{currentClass.Label};{odd_class.Label}";
//this is the key bit - consolidate the array of unique values for the class
var values = currentClass.Values.ToList();
values.AddRange(odd_class.Values);
currentClass.Values = values.ToArray();
groupedClasses.Add(currentClass);
currentClass = null;
}
}
//one left over?
if (currentClass != null)
groupedClasses.Add(currentClass);
//re-assign
group.Classes = groupedClasses.ToArray();
}
layer.SetRenderer(renderer);