How to: Style Individual Data Points

This how-to guide will show you how to create your own custom SeriesStyleProvider which will allow a chosen data point to be styled differently to all of the others.

In order to style a data point in a different way to other data points in the series you need to do the following:

  1. Create a new class which implements SeriesStyleProvider
  2. Choose a way to identify the DataPoint to style differently and choose the styling properties to apply
  3. Set the newly created SeriesStyleProvider on the Series

The DataPoints within a Series on a ShinobiChart are all typically styled in the same way, giving a uniform look to your data. The styling values which the ShinobiChart will apply to a DataPoint are provided by a SeriesSeriesStyleProvider. The default implementation of a SeriesSeriesStyleProvider will return the same SeriesStyle object for each DataPoint to be drawn. It is possible to override this behavior to have a little more control over the look and feel of your individual DataPoints.

Using a simple BarSeries representing a user’s target daily steps, let’s style up the bar representing the current day, to make it stand out from the others.

First, create a new class that implements SeriesStyleProvider.

Java

private static class TodayStylingSeriesStyleProvider implements SeriesStyleProvider<BarSeriesStyle> {
    @Override
    public <S extends Series<BarSeriesStyle>> BarSeriesStyle provide(Data<?, ?> data, int index, S series) {
        return null;
    }
}

C#

private sealed class TodayStylingSeriesStyleProvider : Java.Lang.Object, ISeriesStyleProvider {

    public Java.Lang.Object Provide(IData data, int index, Java.Lang.Object series) {
        return null;
    }
}

As you can see, this class does not do a lot. In fact, currently it is useless as its provide method returns null which certainly won’t produce a good result. Let’s fix that:

Java

private static class TodayStylingSeriesStyleProvider implements SeriesStyleProvider<BarSeriesStyle> {
    @Override
    public <S extends Series<BarSeriesStyle>> BarSeriesStyle provide(Data<?, ?> data, int index, S series) {
        SeriesStyleProvider<BarSeriesStyle> defaultSeriesStyleProvider = series.createDefaultSeriesStyleProvider();
        BarSeriesStyle providedStyle = defaultSeriesStyleProvider.provide(data, index, series);
        return providedStyle;
    }
}

C#

private sealed class TodayStylingSeriesStyleProvider : Java.Lang.Object, ISeriesStyleProvider {

    public Java.Lang.Object Provide(IData data, int index, Java.Lang.Object series) {
        ISeriesStyleProvider defaultSeriesStyleProvider = ((BarSeries)series).CreateDefaultSeriesStyleProvider();
        BarSeriesStyle providedStyle = (BarSeriesStyle)defaultSeriesStyleProvider.Provide(data, index, series);
        return providedStyle;
    }
}

This looks a little better. If we were to use our TodayStylingSeriesStyleProvider we would see our DataPoints styled using the default style properties. This is because we’re just making use of the default SeriesStyleProvider for the given series. We now need to implement the logic to identify the DataPoint which we wish to style differently to the others. As our DataPoints have a Date data type for the y value, let’s identify any DataPoint with a day value equal to that of today. This work can be handed off to a helper method:

Java

private boolean yValueIsEqualToToday(Data<?, ?> data) {
    Calendar calendar = Calendar.getInstance();
    int currentDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);

    // we know our y value is a Date so we can safely cast
    Date dataPointYValue = (Date) data.getY();
    calendar.setTime(dataPointYValue);

    return calendar.get(Calendar.DAY_OF_WEEK) == currentDayOfWeek;
}

C#

private bool YValueIsEqualToToday(IData data)
{
    // we know our y value is a Date so we can safely cast
    DateTime dataPointYValue = DateUtils.ConvertToDateTime((Date)data.GetY());
    DayOfWeek today = DateTime.Now.DayOfWeek;
    return today == dataPointYValue.DayOfWeek;
}

As you can see, this helper method takes the y value of the Data object and casts it to a Date. It is safe to do this as we already know the data types of our x and y values. Using a Calendar object we can compare the weekday value of our DataPoint’s y value to that of the current day, returning true if they match. For Xamarin.Android, we convert the (Java) Date to a (.NET) DateTime using our DateUtils class and compare the DayOfWeek values.

By using this helper inside our provide method we can take a different course of action if our DataPoint’s y value weekday is equal to today:

Java

@Override
public <S extends Series<BarSeriesStyle>> BarSeriesStyle provide(Data<?, ?> data, int index, S series) {
    SeriesStyleProvider<BarSeriesStyle> defaultSeriesStyleProvider = series.createDefaultSeriesStyleProvider();
    BarSeriesStyle providedStyle = defaultSeriesStyleProvider.provide(data, index, series);
    if (yValueIsEqualToToday(data)) {
        providedStyle = new BarSeriesStyle(providedStyle);
        providedStyle.setAreaColor(Color.CYAN);
    }
    return providedStyle;
}

C#

public Java.Lang.Object Provide(IData data, int index, Java.Lang.Object series)
{
    ISeriesStyleProvider defaultSeriesStyleProvider = ((BarSeries)series).CreateDefaultSeriesStyleProvider();
    BarSeriesStyle providedStyle = (BarSeriesStyle)defaultSeriesStyleProvider.Provide(data, index, series);
    if (YValueIsEqualToToday(data)) {
        providedStyle = new BarSeriesStyle(providedStyle);
        providedStyle.AreaColor = Color.Cyan;
    }
    return providedStyle;
}

Note: In this how-to for simplicity we have hard-coded the color for the bar representing today. As you will see in the related code sample we extract the color from the Android resources and inject it into our SeriesStyleProvider.

It is very important to remember here that when styling the today DataPoint we first create a new instance of the BarSeriesStyle, then set our desired style properties on that. If instead we directly modify the style returned by the default SeriesStyleProvider, other DataPoint’s in the Series will have these style properties applied to them as well.

The final step is to set our new SeriesStyleProvider on our Series, which can be done with very little code:

Java

barSeries.setSeriesStyleProvider(new TodayStylingSeriesStyleProvider());

C#

barSeries.SeriesStyleProvider = new TodayStylingSeriesStyleProvider();

It’s as simple as that! Now when you load your chart, you should see the bar representing the same day as today is styled differently to all of the others.

Individual point styling in a BarSeries

One thing to note is that allocations and computationally expensive operations performed within the provide method will increase render time. Therefore, for very large data sets and/or performance-critical applications, you may find it beneficial to create any required SeriesStyle objects in advance where possible. However, in most simple cases the difference in performance should be negligible.

See related code sample: Individual Point Styling Sample, in the samples/individual-point-styling folder of your product download (Xamarin.Android/samples/IndividualPointStyling if you’re using Xamarin.Android).