I am using ILNumerics to generate a surface plot.
I want to use a flat shaded color map (i.e. color ranges) instead of a smooth shaded color map (i.e. each pixel has it's own color).
Is this possible with ILNumerics?
Example of Flat-Shaded surface plot and color bar legend:
Example of Smooth-Shaded surface plot and color bar legend:
You can create a colormap which exposes a flat shading behavior. Just duplicate the keypoints existing in a common colormap in order to model a range of color data getting the same color assigned.
According to the documentation the keypoints for colormaps consist out of 5 columns: a "position" and 4 color values (RGBA). In order to model a 'flat' shaded colormap, place two keypoints 'almost' exactly on top of each other, giving the first one the color of the next lower range and the second one the color of the next higher range. A color range therefore is modeled by two keypoints having the same color assigned.
I wrote 'almost' in the above paragraph, because I thought you have to leave at least a tiny gap between the edges of two ranges - hoping no actual color data value will ever hit that gap. But it seems, there is no gap needed at all and one can give both keypoints exactly the same value. But you will have to be careful while sorting: don't mix the colors up (the quicksort in ILMath.sort() is not stable!)
In the following example a flat shaded colormap is created from Colormaps.Jet
:
Keypoints for Colormaps.Jet (original, interpolating)
<Single> [6,5]
[0]: 0 0 0 0,5625 1
[1]: 0,1094 0 0 0,9375 1
[2]: 0,3594 0 0,9375 1 1
[3]: 0,6094 0,9375 1 0,0625 1
[4]: 0,8594 1 0,0625 0 1
[5]: 1 0,5000 0 0 1
The flat shading version derived from it:
Colormaps.Jet - flat shading version
<Single> [11,5]
[0]: 0 0 0 0,5625 1
[1]: 0,1094 0 0 0,5625 1
[2]: 0,1094 0 0 0,9375 1
[3]: 0,3594 0 0 0,9375 1
[4]: 0,3594 0 0,9375 1 1
[5]: 0,6094 0 0,9375 1 1
[6]: 0,6094 0,9375 1 0,0625 1
[7]: 0,8594 0,9375 1 0,0625 1
[8]: 0,8594 1 0,0625 0 1
[9]: 1,0000 1 0,0625 0 1
[10]: 1 0,5000 0 0 1
As you can easily see, I made a mistake in CreateFlatShadedColormap()
: The last keypoint with (0.5,0,0,1) will never be used. I'll leave it as an exercise to fix that... ;)
private void ilPanel1_Load(object sender, EventArgs e) {
ILArray<float> A = ILMath.tosingle(ILSpecialData.terrain["0:400;0:400"]);
// derive a 'flat shaded' colormap from Jet colormap
var cm = new ILColormap(Colormaps.Jet);
ILArray<float> cmData = cm.Data;
cmData.a = Computation.CreateFlatShadedColormap(cmData);
cm.SetData(cmData);
// display interpolating colormap
ilPanel1.Scene.Add(new ILPlotCube() {
Plots = {
new ILSurface(A, colormap: Colormaps.Jet) {
Children = { new ILColorbar() },
Wireframe = { Visible = false }
}
},
ScreenRect = new RectangleF(0,-0.05f,1,0.6f)
});
// display flat shading colormap
ilPanel1.Scene.Add(new ILPlotCube() {
Plots = {
new ILSurface(A, colormap: cm) {
Children = { new ILColorbar() },
Wireframe = { Visible = false }
}
},
ScreenRect = new RectangleF(0, 0.40f, 1, 0.6f)
});
}
private class Computation : ILMath {
public static ILRetArray<float> CreateFlatShadedColormap(ILInArray<float> cm) {
using (ILScope.Enter(cm)) {
// create array large enough to hold new colormap
ILArray<float> ret = zeros<float>(cm.S[0] * 2 - 1, cm.S[1]);
// copy the original
ret[r(0, cm.S[0] - 1), full] = cm;
// double original keypoints, give small offset (may not even be needed?)
ret[r(cm.S[0], end), 0] = cm[r(1, end), 0] - epsf;
ret[r(cm.S[0], end), r(1, end)] = cm[r(0, end - 1), r(1, end)];
// reorder to sort keypoints in ascending order
ILArray<int> I = 1;
sort(ret[full, 0], Indices: I);
return ret[I, full];
}
}