How to Plot Against Time


How to Plot Against Time

[doc_header] [last_updated_for version=0.3c]

Overview

This is an example of how to draw an XY time series using AndroidPlot. The easiest way to plot a timestamp, and the way we will show you here, is to use epoch time. Epoch time is a period of time that has ellapsed since another well defined point in time (the epoch). On most computers this epoch often referred to as "The Epoch" is January 1st, 1970. When you call System.currentTimeMillis() within Java, you are retrieving the number of milliseconds since the Epoch. If you want to know more, Wikipedia has a good article. For our exmaple, all you need to know is that this is the epoch we will be using. Moving onto how one plots these timestamps in AndroidPlot, it's important to note a couple things. The first is that the most common way to represent timestamps in Java is milliseconds since the epoch, which requires a primitive of type long to safely store. The second is that AndroidPlot uses doubles to represent values. This means that if one were to pass timestamps with long precision to AndroidPlot, they would get truncated and wouldnt make sense when they were drawn. The two-part solution to the problem is to:
  1. Divide your values down to a size that will safely fit inside of a double, storing the divisor
  2. Create a custom Format object which uses the divisor from step1 to "reinflate" the timestamp value. How exactly that is done will be explained a little later on in Example #3.

Example #1: Using a custom Format to print timestamps

layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <com.androidplot.xy.XYPlot
    android:id="@+id/mySimpleXYPlot"
    android:layout_width="fill_parent"
    android:layout_height="200px"
    android:layout_marginTop="10px"
    android:layout_marginLeft="0px"
    android:layout_marginRight="0px"
    title="Yearly UFO Sightings"
    />
</LinearLayout>

MyActivity.java

import android.app.Activity;
import android.graphics.*;
import android.os.Bundle;
import com.androidplot.Plot;
import com.androidplot.xy.SimpleXYSeries;
import com.androidplot.series.XYSeries;
import com.androidplot.xy.*;

import java.text.*;
import java.util.Arrays;
import java.util.Date;

public class MyActivity extends Activity
{

    private XYPlot mySimpleXYPlot;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mySimpleXYPlot = (XYPlot) findViewById(R.id.mySimpleXYPlot);
        Number[] numSightings = {5, 8, 9, 2, 5};
        Number[] years = {
                978307200,  // 2001
                1009843200, // 2002
                1041379200, // 2003
                1072915200, // 2004
                1104537600  // 2005
        };
        // create our series from our array of nums:
        XYSeries series2 = new SimpleXYSeries(
                Arrays.asList(years),
                Arrays.asList(numSightings),
                "Sightings in USA");

        mySimpleXYPlot.getGraphWidget().getGridBackgroundPaint().setColor(Color.WHITE);
        mySimpleXYPlot.getGraphWidget().getGridLinePaint().setColor(Color.BLACK);
        mySimpleXYPlot.getGraphWidget().getGridLinePaint().setPathEffect(new DashPathEffect(new float[]{1,1}, 1));
        mySimpleXYPlot.getGraphWidget().getDomainOriginLinePaint().setColor(Color.BLACK);
        mySimpleXYPlot.getGraphWidget().getRangeOriginLinePaint().setColor(Color.BLACK);

        mySimpleXYPlot.setBorderStyle(Plot.BorderStyle.SQUARE, null, null);
        mySimpleXYPlot.getBorderPaint().setStrokeWidth(1);
        mySimpleXYPlot.getBorderPaint().setAntiAlias(false);
        mySimpleXYPlot.getBorderPaint().setColor(Color.WHITE);

        // Create a formatter to use for drawing a series using LineAndPointRenderer:
        LineAndPointFormatter series1Format = new LineAndPointFormatter(
                Color.rgb(0, 100, 0),                   // line color
                Color.rgb(0, 100, 0),                   // point color
                Color.rgb(100, 200, 0));                // fill color

        // setup our line fill paint to be a slightly transparent gradient:
        Paint lineFill = new Paint();
        lineFill.setAlpha(200);
        lineFill.setShader(new LinearGradient(0, 0, 0, 250, Color.WHITE, Color.GREEN, Shader.TileMode.MIRROR));

        LineAndPointFormatter formatter  = new LineAndPointFormatter(Color.rgb(0, 0,0), Color.BLUE, Color.RED);
        formatter.setFillPaint(lineFill);
        mySimpleXYPlot.getGraphWidget().setPaddingRight(2);
        mySimpleXYPlot.addSeries(series2, formatter);

        // draw a domain tick for each year:
        mySimpleXYPlot.setDomainStep(XYStepMode.SUBDIVIDE, years.length);

        // customize our domain/range labels
        mySimpleXYPlot.setDomainLabel("Year");
        mySimpleXYPlot.setRangeLabel("# of Sightings");

        // get rid of decimal points in our range labels:
        mySimpleXYPlot.setRangeValueFormat(new DecimalFormat("0"));

        mySimpleXYPlot.setDomainValueFormat(new Format() {

            // create a simple date format that draws on the year portion of our timestamp.
            // see http://download.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html
            // for a full description of SimpleDateFormat.
            private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy");

            @Override
            public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {

                // because our timestamps are in seconds and SimpleDateFormat expects milliseconds
                // we multiply our timestamp by 1000:
                long timestamp = ((Number) obj).longValue() * 1000;
                Date date = new Date(timestamp);
                return dateFormat.format(date, toAppendTo, pos);
            }

            @Override
            public Object parseObject(String source, ParsePosition pos) {
                return null;

            }
        });

        // by default, AndroidPlot displays developer guides to aid in laying out your plot.
        // To get rid of them call disableAllMarkup():
        mySimpleXYPlot.disableAllMarkup();
    }
}

Example #2: Converting Stringified timestamps to Epoch timesamps

TODO

Example #3: Using millisecond precision and greater timestamps with AndroidPlot

TODO