Pre loader

Applying colour gradient to FastLineRenderableSeries

Welcome to the SciChart Forums!

  • Please read our Question Asking Guidelines for how to format a good question
  • Some reputation is required to post answers. Get up-voted to avoid the spam filter!
  • We welcome community answers and upvotes. Every Q&A improves SciChart for everyone

WPF Forums | JavaScript Forums | Android Forums | iOS Forums

1
0

I’m trying to find a way to apply a colour gradient to an existing FastLineRenderableSeries in the app. We want the colours in the gradient to align to specific y-axis values (see attached image)

Version
4.6.0.4885
Images
  • You must to post comments
0
0

Yes, this can be done via the PaletteProvider feature: https://www.scichart.com/documentation/android/current/articles/chart2d/PaletteProvider%20API.html

Essentially:

  • You implement a class that implements IFillPaletteProvider IStrokePaletteProvider or IPointMarkerPaletteProvider depending on your series type. For line series this would be IStrokePaletteProvider
  • You override the update() getStrokeColors() getFillColors() getPointMarkerColors methods (getStrokeColors is sufficient for line series)
  • By returning a gradient color set for getStrokeColors() based on Y-value you can achieve what you want.

In scichart.js we have a nice class called PaletteFactory that has a function called createYGradient that wraps this all up for you. Using the AI Assistant I’ve attempted porting this to Android. Please critique and if the implementation has issues, let me know and we can adjust

public class YGradientLinePaletteProvider
 implements IStrokePaletteProvider /* and others if needed */ {

 private final int[] colorMap;
 private final double yMin;
 private final double yMax;

 public YGradientLinePaletteProvider(List<GradientStop> stops,
 double yMin,
 double yMax) {
 this.colorMap = PaletteUtils.createColorMap(stops);
 this.yMin = yMin;
 this.yMax = yMax;
 }

 @Override
 public void onAttached(@NonNull IRenderableSeries renderableSeries) {
 // If you need the series, store it here
 }

 @Override
 public void onDetached() {
 // Cleanup if needed
 }

 @Override
 public int overrideStrokeArgb(int index, double xValue, double yValue) {
 // Map yValue to [0,1]
 double range = yMax - yMin;
 if (range <= 0) {
 return colorMap[0];
 }

 double t = (yValue - yMin) / range;
 if (t < 0) t = 0;
 if (t > 1) t = 1;

 int mapIndex = (int) Math.round(t * (colorMap.length - 1));
 return colorMap[mapIndex];
 }
}

PaletteUtils.createColorMap and GradientStop are defined as follows:

public class GradientStop {
 public final float offset; // 0..1
 public final int color; // ARGB

 public GradientStop(float offset, int color) {
 this.offset = offset;
 this.color = color;
 }
}


public final class PaletteUtils {

 public static final int PRECISION = 500;

 public static int[] createColorMap(List<GradientStop> stops) {
 int[] colorMap = new int[PRECISION];

 if (stops == null || stops.isEmpty()) {
 // Fallback to white
 Arrays.fill(colorMap, 0xFFFFFFFF);
 return colorMap;
 }

 // Assume stops sorted by offset
 float first = stops.get(0).offset;
 float last = stops.get(stops.size() - 1).offset;
 float diff = last - first;
 float step = diff / (PRECISION - 1);

 int count = stops.size();
 int stopIndex = 0;

 int prevColor = stops.get(0).color;
 float prevOffset = stops.get(0).offset;
 int nextColor = (count > 1) ? stops.get(1).color : prevColor;
 float nextOffset = (count > 1) ? stops.get(1).offset : prevOffset;
 float localDiff = nextOffset - prevOffset;

 for (int i = 0; i < PRECISION; i++) {
 float offset = first + i * step;

 // Move to next segment if needed
 while (offset >= nextOffset && stopIndex + 1 < count - 1) {
 stopIndex++;
 prevOffset = stops.get(stopIndex).offset;
 prevColor = stops.get(stopIndex).color;
 nextOffset = stops.get(stopIndex + 1).offset;
 nextColor = stops.get(stopIndex + 1).color;
 localDiff = nextOffset - prevOffset;
 }

 int color;
 if (prevColor == nextColor || localDiff <= 1e-10f) {
 color = nextColor;
 } else {
 float t = (offset - prevOffset) / localDiff;
 color = lerpColor(prevColor, nextColor, t);
 }

 colorMap[i] = color;
 }

 return colorMap;
 }

 private static int lerpColor(int c0, int c1, float t) {
 int a0 = (c0 >> 24) & 0xFF;
 int r0 = (c0 >> 16) & 0xFF;
 int g0 = (c0 >> 8) & 0xFF;
 int b0 = c0 & 0xFF;

 int a1 = (c1 >> 24) & 0xFF;
 int r1 = (c1 >> 16) & 0xFF;
 int g1 = (c1 >> 8) & 0xFF;
 int b1 = c1 & 0xFF;

 int a = (int) (a0 + (a1 - a0) * t);
 int r = (int) (r0 + (r1 - r0) * t);
 int g = (int) (g0 + (g1 - g0) * t);
 int b = (int) (b0 + (b1 - b0) * t);

 return (a << 24) | (r << 16) | (g << 8) | b;
 }
}

Then, apply it to a line series

// Example gradient: blue -> green -> red
List<GradientStop> stops = Arrays.asList(
 new GradientStop(0.0f, 0xFF3333FF),
 new GradientStop(0.5f, 0xFF33FFAA),
 new GradientStop(1.0f, 0xFFFF6600)
);

// Y range for gradient
double yMin = 0.0;
double yMax = 1.5;

YGradientLinePaletteProvider paletteProvider =
 new YGradientLinePaletteProvider(stops, yMin, yMax);

FastLineRenderableSeries lineSeries = new FastLineRenderableSeries();
lineSeries.setDataSeries(dataSeries);
lineSeries.setStrokeThickness(3);
lineSeries.setPaletteProvider(paletteProvider);

surface.getRenderableSeries().add(lineSeries);
  • You must to post comments
Showing 1 result
Your Answer

Please first to submit.