Creating Unique value colorizer for raster

409
13
Jump to solution
07-16-2019 06:51 AM
Highlighted
Regular Contributor

Hi,

I am trying to create raster layer from grid and apply unique value colorizer on the same button click. I have tried different techniques from samples with feature layers, from geonet question https://community.esri.com/thread/235510-applysymbologyfromlayer-geoprocessing-tool (part about Classify colorizer) but can't get results as I expected. Sometimes I see correct legend but no raster on map, otherwise bad legend and bad colorized raster on map. I modified ChangeColorizerForRasterLayer project from sdk samples to load my raster and added color ramp to

SetToUniqueValueColorizer method. My code:

public static async Task SetToUniqueValueColorizer(BasicRasterLayer basicRasterLayer)

{

// Creates a new UV Colorizer Definition using the default constructor.

string fieldName = "Value";

string colorRampName = "Muted pastels";

string colorRampStyle = "ArcGIS Colors";

// Sets the newly created colorizer on the layer.

await QueuedTask.Run(async() =>

{

IList<ColorRampStyleItem> rampList = GetColorRampsFromStyleAsync(Project.Current, colorRampStyle, colorRampName);

CIMColorRamp colorRamp = rampList[0].ColorRamp;

UniqueValueColorizerDefinition UVColorizerDef = new UniqueValueColorizerDefinition(fieldName, colorRamp);

// Creates a new UV colorizer using the colorizer definition created above.

CIMRasterUniqueValueColorizer newColorizer = await basicRasterLayer.CreateColorizerAsync(UVColorizerDef) as CIMRasterUniqueValueColorizer;

basicRasterLayer.SetColorizer(newColorizer);

});

}

@Uma Harano could you please help me again. I can attach my raster.

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Esri Regular Contributor

Hi Gintautas

The issue is that the CreateColorizer does not systematically assign colors from the associated color ramp. We are looking into addressing it in the future.

In the meantime, here is some code that can help solve this issue.

internal class SetColorizer : Button
{
protected async override void OnClick()
{
var raster = MapView.Active.Map.GetLayersAsFlattenedList().OfType<RasterLayer>().FirstOrDefault();
if (raster == null)
return;

await QueuedTask.Run(async () =>
{
string colorBrewerSchemesName = "ArcGIS Colors";
var colorRampNames = new List<string>() { "Green Blues", "Bathymetry #1", "Bathymetry #3",
"Cyan to Purple", "Inferno", "Aspect"};
var color_index = new Random().Next(0, colorRampNames.Count - 1);
string fieldName = "Value";
var colorizer = await CreateUniqueValueColorizerAsync(
raster, colorBrewerSchemesName, colorRampNames[color_index], fieldName);
raster.SetColorizer(RecalculateColorizer(colorizer));
});
}

public CIMRasterColorizer RecalculateColorizer(CIMRasterColorizer colorizer)
{
if (colorizer is CIMRasterUniqueValueColorizer uvrColorizer)
{
var colorRamp = uvrColorizer.ColorRamp;
if (colorRamp == null)
throw new InvalidOperationException("Colorizer must have a color ramp");

//get the total number of colors to be assigned
var total_colors = uvrColorizer.Groups.Select(g => g.Classes.Count()).Sum();
var colors = ColorFactory.Instance.GenerateColorsFromColorRamp(colorRamp, total_colors);
var c = 0;
foreach(var uvr_group in uvrColorizer.Groups)
{
foreach (var uvr_class in uvr_group.Classes)
{
//assign the generated colors to each class in turn
uvr_class.Color = colors[c++];
}
}
}
else if (colorizer is CIMRasterClassifyColorizer classColorizer)
{
var colorRamp = classColorizer.ColorRamp;
if (colorRamp == null)
throw new InvalidOperationException("Colorizer must have a color ramp");

var total_colors = classColorizer.ClassBreaks.Count();
var colors = ColorFactory.Instance.GenerateColorsFromColorRamp(colorRamp, total_colors);
var c = 0;
foreach(var cbreak in classColorizer.ClassBreaks)
{
//assign the generated colors to each class break in turn
cbreak.Color = colors[c++];
}
}
return colorizer;
}

public static Task<CIMRasterColorizer> CreateUniqueValueColorizerAsync(
BasicRasterLayer basicRasterLayer, string styleName, string colorRampName, string fieldName)
{
return QueuedTask.Run(async () =>
{
//we just assume that all of this works and doesn't return null anywhere.. 😉
var style = Project.Current.GetItems<StyleProjectItem>().First(s => s.Name == styleName);
var ramps = style.SearchColorRamps(colorRampName);
var colorizerDef = new UniqueValueColorizerDefinition(fieldName, ramps[0].ColorRamp);
return await basicRasterLayer.CreateColorizerAsync(colorizerDef);
});
}
}
}

View solution in original post

13 Replies
Highlighted
Esri Regular Contributor

Hi Gintautas Kmieliauskas

Please do attach your raster and I can check it out.

Thanks

Uma

0 Kudos
Highlighted
Regular Contributor

Hi Uma,

I send you raster for testing.

Thanks

0 Kudos
Highlighted
Esri Regular Contributor

Hi Gintautas,

I used your methods and sample raster dataset and it seemed to work for me.  Only thing I added to my code was GetColorRampsFromStyleAsync method.Since it was async, I awaited it (line 29 in the snippet below)and it created the correct Colorizer in Pro.

 private static async Task<IList<ColorRampStyleItem>> GetColorRampsFromStyleAsync()
{
string colorRampName = "Muted pastels";

//string colorRampStyle = "ArcGIS Colors";
string colorBrewerSchemesName = "ArcGIS Colors";
StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().First(s => s.Name == colorBrewerSchemesName);
IList<ColorRampStyleItem> colorRampList = await QueuedTask.Run(() =>
{
return style.SearchColorRamps(colorRampName);
});

return colorRampList;
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍

public static async Task SetToUniqueValueColorizer(BasicRasterLayer basicRasterLayer)

{
// Creates a new UV Colorizer Definition using the default constructor.

string fieldName = "Value";

// Sets the newly created colorizer on the layer.

await QueuedTask.Run(async () =>

{

IList<ColorRampStyleItem> rampList = await GetColorRampsFromStyleAsync();

CIMColorRamp colorRamp = rampList[0].ColorRamp;

UniqueValueColorizerDefinition UVColorizerDef = new UniqueValueColorizerDefinition(fieldName, colorRamp);

// Creates a new UV colorizer using the colorizer definition created above.

CIMRasterUniqueValueColorizer newColorizer = await basicRasterLayer.CreateColorizerAsync(UVColorizerDef) as CIMRasterUniqueValueColorizer;

basicRasterLayer.SetColorizer(newColorizer);

});

}

Can you please this?

Thanks

Uma

0 Kudos
Highlighted
Regular Contributor

Hi Uma,

Thanks for reply.

I have copied your code inside my test project. No changes.

Result with your code

Must be (result of the same color ramp from Symbology pane)

When raster contains only one value (with your code):

0 Kudos
Highlighted
Esri Regular Contributor

Hi Gintautas,

When you use the code, is the issue that the 3 colors chosen by the code doesn't match the colors chosen by the same action accomplished by the Symbology dockpane UI?

I need to confirm this, but that might be how the code behaves - It randomly picks 3 colors which are different than what the Pro UI does.

Thanks

Uma

0 Kudos
Highlighted
Regular Contributor

Hi Uma,

I have changed color ramp to show that code does not work. I have used color ramp “Green Blues”.

Below images before applying unique value colorizer and after

Before:

After:

There is another one problem with unique value colorizer. My raster has two fields “Value” and “SLabel”(text).

If I choose Field for colorizer “Value” I get no image on map at all. The color ramp is not what I choose too.

Thanks

Gintautas

0 Kudos
Highlighted
Esri Regular Contributor

Hi Gintautas

The issue is that the CreateColorizer does not systematically assign colors from the associated color ramp. We are looking into addressing it in the future.

In the meantime, here is some code that can help solve this issue.

internal class SetColorizer : Button
{
protected async override void OnClick()
{
var raster = MapView.Active.Map.GetLayersAsFlattenedList().OfType<RasterLayer>().FirstOrDefault();
if (raster == null)
return;

await QueuedTask.Run(async () =>
{
string colorBrewerSchemesName = "ArcGIS Colors";
var colorRampNames = new List<string>() { "Green Blues", "Bathymetry #1", "Bathymetry #3",
"Cyan to Purple", "Inferno", "Aspect"};
var color_index = new Random().Next(0, colorRampNames.Count - 1);
string fieldName = "Value";
var colorizer = await CreateUniqueValueColorizerAsync(
raster, colorBrewerSchemesName, colorRampNames[color_index], fieldName);
raster.SetColorizer(RecalculateColorizer(colorizer));
});
}

public CIMRasterColorizer RecalculateColorizer(CIMRasterColorizer colorizer)
{
if (colorizer is CIMRasterUniqueValueColorizer uvrColorizer)
{
var colorRamp = uvrColorizer.ColorRamp;
if (colorRamp == null)
throw new InvalidOperationException("Colorizer must have a color ramp");

//get the total number of colors to be assigned
var total_colors = uvrColorizer.Groups.Select(g => g.Classes.Count()).Sum();
var colors = ColorFactory.Instance.GenerateColorsFromColorRamp(colorRamp, total_colors);
var c = 0;
foreach(var uvr_group in uvrColorizer.Groups)
{
foreach (var uvr_class in uvr_group.Classes)
{
//assign the generated colors to each class in turn
uvr_class.Color = colors[c++];
}
}
}
else if (colorizer is CIMRasterClassifyColorizer classColorizer)
{
var colorRamp = classColorizer.ColorRamp;
if (colorRamp == null)
throw new InvalidOperationException("Colorizer must have a color ramp");

var total_colors = classColorizer.ClassBreaks.Count();
var colors = ColorFactory.Instance.GenerateColorsFromColorRamp(colorRamp, total_colors);
var c = 0;
foreach(var cbreak in classColorizer.ClassBreaks)
{
//assign the generated colors to each class break in turn
cbreak.Color = colors[c++];
}
}
return colorizer;
}

public static Task<CIMRasterColorizer> CreateUniqueValueColorizerAsync(
BasicRasterLayer basicRasterLayer, string styleName, string colorRampName, string fieldName)
{
return QueuedTask.Run(async () =>
{
//we just assume that all of this works and doesn't return null anywhere.. 😉
var style = Project.Current.GetItems<StyleProjectItem>().First(s => s.Name == styleName);
var ramps = style.SearchColorRamps(colorRampName);
var colorizerDef = new UniqueValueColorizerDefinition(fieldName, ramps[0].ColorRamp);
return await basicRasterLayer.CreateColorizerAsync(colorizerDef);
});
}
}
}

View solution in original post

Highlighted
Regular Contributor

Hi Uma,

Thank you for your efforts.

Now it works with my text field, but doesn’t work with “Value” field. There is no view of the layer as in my picture in previous answer.

The same things with recalculating colorizer we do in ArcObjects. So nothing changes ☺

It is strange that unique value rendering works fine on featureclasses without recalculating values.

Thanks again.

0 Kudos
Highlighted
Esri Regular Contributor

Hi Gintautas,

Not sure what is happening here - I tried with the raster dataset you shared previously that had the "Value" field and this code works for me.

The Colorizer method has an issue with assigning colors in the specified ramp - This is an issue that we hope to fix in the next release.  Renderers that use color ramps do not have this issue.

Thanks

Uma

0 Kudos