Thresholds


#1

Is it possible to configure thresholds on a Shinobi Chart? 

If something is above or below a threshold, I’d like to be able to configure the series color based on the threshold as per the example image below:

Example Chart

Thanks in advance for your help!

Tim


#2

Hi Tim,

Thanks for getting in touch!

This isn’t a feature we support out of the box. However, It can be done if you manipulate your chart’s datasource.

First, return the number of thresholds you want in your chart in SChartDatasource method “numberOfSeriesInSChart:”.

Then style the area color of your line series depending on which threshold the series corresponds to. Here is some example code:

-(SChartSeries *)sChart:(ShinobiChart *)chart seriesAtIndex:(NSInteger)index {
    
    SChartLineSeries *lineSeries = [[SChartLineSeries alloc] init];
    lineSeries.style.showFill = YES;

    if (index == 0) {
        lineSeries.style.areaColor = [UIColor greenColor];
        lineSeries.style.areaColorLowGradient = [UIColor greenColor];
        lineSeries.style.areaLineColor = [UIColor greenColor];
    } else if (index == 1) {
        lineSeries.style.areaColor = [UIColor yellowColor];
        lineSeries.style.areaColorLowGradient = [UIColor yellowColor];
        lineSeries.style.areaLineColor = [UIColor yellowColor];
    } else {
        lineSeries.style.areaColor = [UIColor redColor];
        lineSeries.style.areaColorLowGradient = [UIColor redColor];
        lineSeries.style.areaLineColor = [UIColor redColor];
    }
    return lineSeries;
}

 The final step is in your implementation of the SChartDatasource method “sChart:dataPointAtIndex:forSeriesAtIndex:”  return the the threshold value if the datapoint’s value is greater than the threshold value. Here is some example code:

- (id<SChartData>)sChart:(ShinobiChart *)chart dataPointAtIndex:(NSInteger)dataIndex forSeriesAtIndex:(NSInteger)seriesIndex {
    
    SChartDataPoint *datapoint = [[SChartDataPoint alloc] init];
    
    float firstThreshold = 50;
    float secondThreshold = 75;
    
    double xValue = ...;
    double yValue = ...;
    datapoint.xValue = @(xValue);
    
    // compute the y-value for each series
    if (xValue > firstThreshold && seriesIndex == 0) {
       yValue = @(firstThreshold);
    } else if (xValue > secondThreshold && seriesIndex == 1) {
        yValue = @(secondThreshold);
    }

    datapoint.yValue = @(yValue);
    
    return datapoint;
}

Let me know how you get on.

Kind Regards,
Andrew Polkinghorn


#3

Hi,

May i know if the same threshold thing is supported in Android?

Thanks,

Victor


#4

Hi,

I really want to color the Shinobi graph according to different threshold value. May i know if the threshold setting is supported in Android?

Regards,

Victor


#5

Hello Victor,

Thanks for your enquiry.

Similar to the iOS product, ShinobiCharts for Android does not support thresholds out of the box. It should be possible however to achieve the threshold functionality which you require. Essentially you would need to use 3 line series’ , two of which would serve as the threshold boundaries. You would need to write a custom DataAdapter class (you could extend the DataAdapter or SimpleDataAdapter class) which would accept your data points (x and y values) but apply a custom y value to the series, dependent upon the index of the series and the y value. So assuming a y value of 125 it might set the y value of the data points of the first series, to 50, the second to 100 and the third it would leave as the actual y value passed in (in this case 125).

You would add these 3 series to your chart, and you would provide a different style object for each series, with the appropriate fill color set. 

This method would thus require the data pushing to 3 different DataAdapters - each line series has its own DataAdapter. You may wish to create a further custom DataAdapter class, to handle the repetition. So essentially you could assign your data points once, to the ‘master’ dataAdapter which could then internally assign the data points to the 3 ‘threshold’ dataAdapters. Your master dataAdapter could also be responsible for passing pack the appropriate threshold dataAdapter to the particular series. Of course how you achieve this is entirely up to you but hopefully we have given you some ideas.

I hope this answers your query, if you need any further help please do not hesitate to get back in touch. 

Thanks,

Kai.


#6

Hi Kai,

i get your ideas. When it comes to implemenation of the Custom adapter, how could i force the y value to be the threshold value in the overriden add() method? I have come out with the custom adapter, but could not change the y value. Please see the code below.

Thanks,

Victor

public class ShinobiCustomDataAdapter<Date, Double> extends DataAdapter<Date, Double> {

private int x, y;

private double threshold;

public ShinobiCustomDataAdapter( double threshold)

{

this.threshold = threshold;

}

@Override

public boolean add(Data<Date, Double> dp){

Double yD = dp.getY();

String yStr = yD.toString();

java.lang.Double.parseDouble(yStr);

 **** how to change the y value ??? ****

boolean added = super.add(dp);

return added;

}

}


#7

Hi Victor,

Thanks for your reply. 

In order to set the y value I believe you would simply need to construct a new DataPoint object based on the original x value and the new threshold y value. Once created you could pass this object into the super call to add().

I think it would look something like:

public boolean add(Data<Date, Double> dp){

//calculate if y should be threshold value or real value

double yVal = dp.getY() <= threshold ? threshold : dp.getY();

return super.add(new DataPoint(dp.getX(), yVal);

}

I notice that you extend the DataAdapter class. I would like to point out that if one extends this class then the concrete implementation must handle the work of notifying the series that it has been updated. In order to do this you could call super.fireUpdateHandler(), or you could instead subclass SimpleDataAdapter which would take care of this for you. Further guidance on this can be found in the API docs:

http://www.shinobicontrols.com/docs/ShinobiControls/ShinobiChartsAndroid/1.3.2/Premium/Normal/apidocs/docs/reference/com/shinobicontrols/charts/DataAdapter.html

http://www.shinobicontrols.com/docs/ShinobiControls/ShinobiChartsAndroid/1.3.2/Premium/Normal/apidocs/docs/reference/com/shinobicontrols/charts/SimpleDataAdapter.html

Or the user guide:

http://www.shinobicontrols.com/docs/ShinobiControls/ShinobiChartsAndroid/1.3.2/Premium/Normal/user-guide/how-to-custom-data-adapter.html

I hope this helps, please let me know if you need any further help.

Thanks and kind regards,

Kai.


#8

Hi Kai,

Thank you for your reply. I have managed to display the Shinobi threshold graph. Please see the screeshot at :

There are two problems associated with the Shinobi threshold graph:

  1. I set the top line series fill color to RED, the middle line series fill color to GREEN, the bottom line series to BLUE. However, when the graph is displayed, the color is wrong because of the overlapping line series. I adjust the Alpha value using

  style.setAreaColorBelowBaseline(Color.argb(50, 0, 205, 34));

but it is not really solving the color problem.

  1. When the data value falls below the threshold, the threshold line is not straight.

May i know how to really solve these two problems? 

Thanks,

Victor


#9

Hi Victor,

To answer your questions:

  1. Firstly, as you are placing three line series with a solid fill on top of each other I would imagine you would want the fill colour to be totally opaque otherwise you will get a “mixing” effect. So the first argument for Color.argb() would want to be 255. Obviously it depends on what you are going for!

Secondly, you are setting the area colour below the baseline - the baseline is 0 so this sets the area colour for below 0 so it won’t have any effect on the bit of the chart visible in your image. For that you would need to use style.setAreaColor(int).
2. The approach identified by Andrew and Kai certainly will get you going (and looks like it has!) but you will need to do a little more work with your data. You will have to add extra data points for where the value crosses the threshold between two data points. So, in your image, at the data point before the one on 7th Jan, you would need to insert an artifical point into the middle series so that the area extends all the way to where the top series crosses the threshold value.

There are obviously many ways you could do this but it might be an idea to have a master custom DataAdapter that you just give the actual data points to. It can then be up to this data adapter to create and populate the three data adapters for the different line series, taking into account any thresholds and inserting any extra data points as necessary. Really, it’s completely up to you - we’ve aimed to keep the library flexible rather than restrictive to enable users to achieve effects such as this.

Kind regards,

Patrick