Unique Values and Subtypes [C#]

4845
6
07-31-2012 07:47 AM
AkhilParujanwala
New Contributor III
I am trying to colour subtypes for an empty featureclass by unique values.

I can do this manually by doing the following, this is a Point Layer.
Layer Properties > Symbology > Categories > Unique values > Value Field = SUBTYPE > click on Add All Values > 8 Subtypes will appear with random colours. Then I would manually change each Subtype marker symbol to a square with a colour that I want.

Once again, this is an empty featureclass.

I would like to perform the above actions using C# ArcObjects.

I have already tried SimpleMarkerSymbol code that would attempt to assign colours using a custom colour ramp, but this did not work because the code required the layer to have data in it. My featureclass will not data in it, but I need to assign colour to each subtype manually, and yes hardcode it in ArcObjects.

Please let me know if this is possible and how, thanks!
0 Kudos
6 Replies
sameerpuppal
Occasional Contributor
Hi,

I am not sure if my suggestion to your problem will work out, but you can surely give it a try.

Try using UniqueValueRenderer

http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//0001000000t8000000
This might work as you have fix no. of values (Types) you can assign them colour accordingly by replacing 'pEnumColors.Next();' with say a array of color objects which you define/hardcode at the top. I have not tried if it works with empty Layer (which seems to me is a catch here!). Do try and reply if it works!

Best of Luck,

Cheers,
Sameer
0 Kudos
AkhilParujanwala
New Contributor III
Hi Sameer,

Thanks for the link. I have been trying to modify and use that code, but I am unable to make it work.

I am goign to outline what I need, to increase clarity:
1) I have a featureclass with 8 Subtypes.
2) The featureclass is empty and is in my Map Document using the default rendering, but only shows one item in the table of contents.
3) The featureclass is a point layer.
4) I would then manually do the following: Layer Properties > Symbology > Categories > Unique values > Value Field = SUBTYPE > click on Add All Values > 8 Subtypes will appear with random colours.
5) Manually assign a specific colour to each item in the table of contents.

The code sample provided in the following link, seems to only work if there are features in the featureclass, whereas my featureclass is empty. http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//0001000000t8000000

The following code fails to execute correctly because I don't have any features in the featureclass.
[PHP]
while (pFeature != null)
    {
        ISimpleFillSymbol pClassSymbol = new SimpleFillSymbolClass();
        pClassSymbol.Style = esriSimpleFillStyle.esriSFSSolid;
        pClassSymbol.Outline.Width = 0.4;

        string classValue;
        classValue = pFeature.get_Value(fieldIndex)as string;

        //Test to see if this value was added to the renderer. If not, add it.
        ValFound = false;
        for (int i = 0; i <= pUniqueValueRenderer.ValueCount - 1; i++)

[/PHP]

In particular: This will obviously not work since I do not have any features.
[PHP]while (pFeature != null)
[/PHP]

Then another problem would arise: Since there are no features, the value count is always zero and not work correctly.
[PHP]for (int i = 0; i <= pUniqueValueRenderer.ValueCount - 1; i++)
[/PHP]

Kindly advise, thanks!
0 Kudos
AkhilParujanwala
New Contributor III
I am getting much closer to what I want. Here is the code:

[PHP]
        void UniqueValueRenderer(IGeoFeatureLayer pGeoFeatureLayer, string fieldName)
        {
            // Creates the symbol, black (default), sqaure, with the size of 4 and no outline.
            ISimpleMarkerSymbol pSimpleMarkerSymbol = new SimpleMarkerSymbol();
            pSimpleMarkerSymbol.Size = 4;
            pSimpleMarkerSymbol.Style = esriSimpleMarkerStyle.esriSMSSquare;
            pSimpleMarkerSymbol.Outline = false;

            // QI to allow rendering on the layer.
            IUniqueValueRenderer pUniqueValueRenderer = pGeoFeatureLayer.Renderer as IUniqueValueRenderer;
          
            // Loop through all classes and set the symbol to be a black sqaure as defined above.
            // Unique values already exists because of predefined subtypes.
            // Can put a switch block to have a specific colour for each class.
            // Note: The featurelayer is empty.
            for (int i = 0; i <= pUniqueValueRenderer.ValueCount - 1; i++)
            {
                string value = pUniqueValueRenderer.get_Value(i);
                pUniqueValueRenderer.set_Symbol(value, pSimpleMarkerSymbol as ISymbol);
            }
        
            // Applies the rendering to the layer.
            pGeoFeatureLayer.Renderer = pUniqueValueRenderer as IFeatureRenderer;
        }
[/PHP]

I am working on the rest of the business logic.

How do I uncheck <all other values> symbol in the Layer Properties > Symbology section.
I only want to show my subtypes/classes, not the <all other values> symbol in the table of contents (TOC).

Thanks!
0 Kudos
AkhilParujanwala
New Contributor III
Great news everyone, I have gotten very close to what I wanted.

1) I have removed the default <all other value> by using the following code:
[PHP]
pUniqueValueRenderer.UseDefaultSymbol = false;
[/PHP]

2) I was getting a problem where all my classes were becoming the same color, for example blue. But I solved this problem by moving the declaration of the SimpleMarkerSymbol inside the loop, rather than being outside the loop.

3) Below is the near perfect solution to creating custom colors for a fixed number of classes using UniqueValueRenderer. The cases were changed for this post.

[PHP]
public static void TestSymbol(IGeoFeatureLayer pGeoFeatureLayer)
        {
            IUniqueValueRenderer pUniqueValueRenderer = pGeoFeatureLayer.Renderer as IUniqueValueRenderer;
            pUniqueValueRenderer.UseDefaultSymbol = false;

            for (int i = 0; i <= pUniqueValueRenderer.ValueCount - 1; i++)
            {
                ISimpleMarkerSymbol pSimpleMarkerSymbol = new SimpleMarkerSymbol();
                pSimpleMarkerSymbol.Size = 4;
                pSimpleMarkerSymbol.Style = esriSimpleMarkerStyle.esriSMSSquare;
                pSimpleMarkerSymbol.Outline = false;

                string value = pUniqueValueRenderer.get_Value(i);
                string description = pUniqueValueRenderer.get_Label(value);

                switch (description)
                {
                    case "T1":
                        pSimpleMarkerSymbol.Color = Utilities.CreateRGBColor(204, 204, 204);                        
                        break;
                    case "T2":
                        pSimpleMarkerSymbol.Color = Utilities.CreateRGBColor(115, 76, 0);                       
                        break;
                    case "T3":
                        pSimpleMarkerSymbol.Color = Utilities.CreateRGBColor(0, 0, 0);                       
                        break;
                    case "T4":
                        pSimpleMarkerSymbol.Color = Utilities.CreateRGBColor(0, 112, 225);                       
                        break;
                    case "T5":
                        pSimpleMarkerSymbol.Color = Utilities.CreateRGBColor(132, 0, 168);                       
                        break;
                    case "T6":
                        pSimpleMarkerSymbol.Color = Utilities.CreateRGBColor(255, 0, 0);                       
                        break;
                    case "T7":
                        pSimpleMarkerSymbol.Color = Utilities.CreateRGBColor(255, 170, 0);                       
                        break;
                    case "T8":
                        pSimpleMarkerSymbol.Color = Utilities.CreateRGBColor(255, 255, 0);                       
                        break;
                    case "T9":
                        pSimpleMarkerSymbol.Color = Utilities.CreateRGBColor(38, 115, 0);                    
                        break;
                }

                pUniqueValueRenderer.set_Symbol(value, pSimpleMarkerSymbol as ISymbol);               
            }

            pGeoFeatureLayer.Renderer = pUniqueValueRenderer as IFeatureRenderer;
        }
[/PHP]

4) My next issue is the order in which the classes appear in the table of contents.
I want them to appear in a specific order.
When I add the layer to the map, the classes appear in alphabetical order or seamingly random.
Existing List (Order of classes in TOC):

    T2
    T5
    T6
    T9
    T1
    T4
    T3
    T7
    T8


This example shows how I would like the list of classes to appear in the table of contents (TOC).
Desired List (Order of classes in TOC):

    T1
    T2
    T3
    T4
    T5
    T6
    T7
    T8
    T9

Any suggestions on how to re-arrange the classes?
Should I remove all values, and then add them manually one by one in the correct order instead?

Kindly advise, thanks!
0 Kudos
AkhilParujanwala
New Contributor III
I am now trying to find the object that can perform "Reverse Sorting" in the symbology.
If you go to a layer's properties > Symbology > Unique Values > right click under the heading Value > the Reverse Sorting function appears.

I would like to have that method using ArcObjects, if it is possible.

I am using a featureclass that already has unique values applied to it, the next step is for me to do is perform the Reverse Sort method.

Can anyone shed some light on how to get that method?


Thanks in advance.
0 Kudos
AlexanderBrown1
New Contributor II
Akhil,

I know this response is really late--did not find this board until yesterday.  However, for any up and coming developers (such as myself) it is great to have some type of solution posted on these boards.

You need to utilize the IQueryFilterDefinition interface.  This allows you to set a post fix clause to order by a field value.  In your case, this would be SUBTYPE.  Forgive me if my C# is rusty, as I mostly deal in VB.NET

IQueryFilter pQueryFilter = default(IQueryFilter);
pQueryFilter = new QueryFilter();
pQueryFilter.SubFields = "SUBTYPE";
//Here is the field you want to sort by
pQueryFilter.WhereClause = null;

IQueryFilterDefinition2 pQueryDefFilter = default(IQueryFilterDefinition2);
pQueryDefFilter = pQueryFilter;
 //Here you call the subfield in the query filter
pQueryDefFilter.PostfixClause = "ORDER BY SUBTYPE";

IFeatureCursor pFCursor = default(IFeatureCursor);
pFCursor = pFeatureClass.Search(pQueryFilter, true);


Apply this before you render using unique values.
0 Kudos