Unique value renderers

621
3
11-09-2017 08:31 AM
DrewD
by
New Contributor III

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.

0 Kudos
3 Replies
CharlesMacleod
Esri Regular Contributor

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); 
0 Kudos
DrewD
by
New Contributor III

Thanks Charles, that makes the symbol fill transparent. How can I group unique values together so that they share symbology?

0 Kudos
CharlesMacleod
Esri Regular Contributor

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);