How to: Use Series Hiding and Animation

This how-to guide shows you how to make use of the built-in animations and series hiding, to achieve attention-grabbing effects in your charts.

Series hiding

Where multiple series are displayed on a chart, there are often cases where specific information can best be conveyed by temporarily hiding one or more series, making the remaining series stand out more clearly. While it’s possible to do this by removing and re-adding the series, this is not ideal, as the chart loses all knowledge of the series and incurs the expense of relaying the series data when it is re-added.

Starting with V1.6, shinobicharts supports the concept of hiding a series. A hidden series has the following attributes:

  • Neither it nor any associated labels are visible.
  • It takes up no space within a stack of series.
  • It does not respond to selection gestures.
  • It does appear in a chart legend.

Series visibility is controlled by methods (a property in C#) on the Series class.

Java

public void setHidden(boolean hidden);
public boolean isHidden();

C#

public bool Hidden { get; set; }

Setting the hidden state on an existing series has an immediate effect, the is no need to redraw the chart explicitly.

Data ranges with hidden series

The concept of a hidden series introduces some complexity into the notion of data range for an axis. To help with this we’ve added a new visible range property to the axis, making the following list:

  • Current displayed range is the actual range currently displayed on the visible area of the chart.
  • Data range is the total data range across all series (including hidden ones) on this axis, taking into account only the actual data values.
  • Default range is a range you can set that will be displayed when data is loaded into the chart.
  • Visible range is the range within which all the visible (non-hidden) series on this axis will be displayed, taking into account baselines, bar/column widths etc.

When you hide or show a series, the default behavior is for the axis range to change immediately to take account of the change in visible range. This is not always desirable, and you can prevent it by using the CurrentDisplayedRangePreservedOnUpdate control on the axis.

All of this is controlled by methods on the Axis class (properties in C#, on the concrete NumberAxis and DateTimeAxis classes).

Java

public final Range<T> getCurrentDisplayedRange();
public final Range<T> getDataRange();
public final Range<T> getDefaultRange();
public final void setDefaultRange(Range<T> defaultRange);
public final Range<T> getVisibleRange();
public final boolean isCurrentDisplayedRangePreservedOnUpdate();
public final void setCurrentDisplayedRangePreservedOnUpdate(boolean preserved);

C# (NumberAxis - DateTimeAxis is similar)

public NumberRange CurrentDisplayedRange { get; }
public NumberRange DataRange { get; }
public NumberRange DefaultRange { get; set; }
public NumberRange VisibleRange { get; }
public bool CurrentDisplayedRangePreservedOnUpdate { get; set; }

Entry and exit animations

Showing and hiding series is all very nice, but the visual effect can appear rather abrupt. You can ease this, and produce some eye-catching effects, by using series animations. There are two kinds of series animation:

  • Entry animations occur when the chart is first shown, a new series is added, or an existing series is ‘unhidden’.
  • Exit animations occur when a series is hidden or removed from the chart.

Each series has an associated entry animation and an associated exit animation, with appropriate defaults for each series type. These are disabled by default, so that animations must be explicitly switched on. You can replace these animations with your own (though they may not be null) or you can customize them, but this is not generally necessary, as the SeriesAnimation class provides factory methods for a set of standard animations.

Series animations are purely visual effects (they do not alter data) and control scaling in the X and Y directions and the alpha colour component.

The following methods (properties in C#) on the Series class control series animations:

Java

public void enableAnimation(boolean enabled);
public boolean isAnimationEnabled();
public SeriesAnimation getEntryAnimation();
public void setEntryAnimation(SeriesAnimation seriesAnimation)
public SeriesAnimation getExitAnimation();
public void setExitAnimation(SeriesAnimation seriesAnimation)
public boolean isAnimating();

C# (NumberAxis - DateTimeAxis is similar)

public bool AnimationEnabled { get; set; }
public SeriesAnimation EntryAnimation { get; set; }
public SeriesAnimation ExitAnimation { get; set; }
public bool Animating { get; }

Animation notifications

The exit animations introduce a tricky little point, which is that if you (for instance) remove a series with an animation the series is still present and visible for the duration of the animation. The series is not actually removed until the animation completes.

To make this situation easier to handle in an application, you can query the series as to whether an animation is in progress, or you can add a listener to the chart so that you can be notified when an animation completes.

Java

public void setOnSeriesAnimationListener(ShinobiChart.OnSeriesAnimationListener listener);

C# (NumberAxis - DateTimeAxis is similar)

public void SetOnSeriesAnimationListener (IShinobiChartOnSeriesAnimationListener p0)

Putting it all together

To demonstrate this, were going to modify the Quick Start app. This app shows two sine waves overlaid one on top of the other. We’re going to make it show one of these, initially animated in with a vertical bounce animation, and then make the app perform a cross-fade between the two series in response to a tap gesture.

The first thing to do is to enable animations on both series before adding them to the chart. If you enable animations after adding them, the initial animation won’t take place, as it wasn’t enabled in time. The series will use the default animations for their type, growing vertically with a bounce.

Then hide the second series, again before adding it to the chart.

Now change both series entry and exit animation types to a fade animation. Do this after adding the series, so it will take effect on the next animation. The series creation/addition code now looks like this - refactor series1 and series2 to be class fields rather than local variables, we’ll need them later:

Java

series1 = new LineSeries();
series1.setDataAdapter(dataAdapter1);
series1.enableAnimation(true);
shinobiChart.addSeries(series1);
series1.setEntryAnimation(SeriesAnimation.createFadeAnimation());
series1.setExitAnimation(SeriesAnimation.createFadeAnimation());

series2 = new LineSeries();
series2.setDataAdapter(dataAdapter2);
series2.setHidden(true);
series2.enableAnimation(true);
shinobiChart.addSeries(series2);
series2.setEntryAnimation(SeriesAnimation.createFadeAnimation());
series2.setExitAnimation(SeriesAnimation.createFadeAnimation());

C#

series1 = new LineSeries();
series1.DataAdapter = dataAdapter1;
series1.AnimationEnabled = true;
shinobiChart.AddSeries(series1);
series1.EntryAnimation = SeriesAnimation.CreateFadeAnimation();
series1.ExitAnimation = SeriesAnimation.CreateFadeAnimation();

series2 = new LineSeries();
series2.DataAdapter = dataAdapter2;
series2.Hidden = true;
series2.AnimationEnabled = true;
shinobiChart.AddSeries(series2);
series2.EntryAnimation = SeriesAnimation.CreateFadeAnimation();
series2.ExitAnimation = SeriesAnimation.CreateFadeAnimation();

Next we’re going to set a listener for user gestures:

Java

public class MainActivity extends Activity implements ShinobiChart.OnGestureListener {

C#

public class MainActivity : Activity, IShinobiChartOnGestureListener

Java

shinobiChart.setOnGestureListener(this);

C#

shinobiChart.SetOnGestureListener(this);

and provide an implementation of the onSingleTouchDown method that swaps the hidden state of both series. Note that we also make a simple check that the last cross-fade has completed before starting a new one.

Java

@Override
public void onSingleTouchDown(ShinobiChart arg0, PointF arg1) {
    if ((series1.isAnimating() == false) && (series2.isAnimating() == false)) {
        if (series1.isHidden()) {
            series1.setHidden(false);
            series2.setHidden(true);
        }
        else {
            series1.setHidden(true);
            series2.setHidden(false);
        }
    }
}

C#

public void OnSingleTouchDown (IShinobiChart chart, PointF position)
{
    if ((series1.IsAnimating == false) && (series2.IsAnimating == false)) {
        if (series1.Hidden) {
            series1.Hidden = false;
            series2.Hidden = true;
        }
        else {
            series1.Hidden = true;
            series2.Hidden = false;
        }
    }
}

It would be nice to be notified when the series animations have finished. To achieve this we will implement the onSeriesAnimationFinished method of the ShinobiChart.OnSeriesAnimationListener interface.

Java

@Override
public void onSeriesAnimationFinished(Series<?> series) {
    if (series == series1 && series.isHidden()) {
        Toast.makeText(this, "Series 1 is now hidden", Toast.LENGTH_SHORT).show();
    }
    else if (series == series2 && series.isHidden()) {
        Toast.makeText(this, "Series 2 is now hidden", Toast.LENGTH_SHORT).show();
    }
}

C#

public void OnSeriesAnimationFinished(Series series)
{
    if (series == series1 && series.Hidden) {
       Toast.MakeText(this, "Series 1 is now hidden", ToastLength.Short).Show();
    } else if (series == series2 && series.Hidden) {
       Toast.MakeText(this, "Series 2 is now hidden", ToastLength.Short).Show();
    }
}

Finally we must set this listener on the chart.

Java

shinobiChart.setOnSeriesAnimationListener(this);

C#

shinobiChart.SetOnSeriesAnimationListener(this);

That’s all you need to know for simple animations. Please refer to the API documentation if you want to do more complex customizations, such as defining your own animation curves.

See related code sample: Series Hiding And Animation Sample, in the samples/series-hiding-animation folder of your product download (Xamarin.Android/samples/SeriesHidingAnimation if you’re using Xamarin.Android).