Ever wanted to create sexy charts/graphs for Android ?

Well, here is a nice find called DroidCharts available at: http://code.google.com/p/droidcharts/

Compare with the Javascript/HTML approach in my other page: https://w2davids.wordpress.com/android-charts-the-html5-and-javascript-way/

Chart Types include:

  • Line
  • Pie
  • XY
  • Bar
  • Category Bar

I have made available a JAR library for download: http://www.filefactory.com/file/b3e83db/n/DroidCharts.jar

Hope you guys find it useful!

Some notes:

Note: As you guys/gals may have noticed, the data values are hard-coded..(naughty naughty naughty). This was done to keep things simple as possible. Ideally the data would come from a data source/content provider such as SQLite or Web service. I like the Active Record approach and will provide some details in my next article on doing Active Record for Android android-active-record

Screen Orientation/Rotation with DroidCharts.
Bumping my own Page/Thread – you cant get any more ridiculous than me:
Wanna do cheap tricks with your Android: Say you have a list of data values in a ListView
and upon device rotation change the view automatically changes to Landscape view with a graphical chart view plot. Passing parameters data values between Activity Views using Intent “extras” Bundles.

The Application:
XY Line chart display axis titles and chart legend.

The Code:
Main.java

import android.app.Activity;
import android.os.Bundle;

public class Main extends Activity
{
  /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState)
 {
     super.onCreate(savedInstanceState);
    setContentView(new XYLineChart(getApplicationContext()));
  }
}

XYLineChart.java

import net.droidsolutions.droidcharts.awt.Rectangle2D;
import net.droidsolutions.droidcharts.core.ChartFactory;
import net.droidsolutions.droidcharts.core.JFreeChart;
import net.droidsolutions.droidcharts.core.axis.NumberAxis;
import net.droidsolutions.droidcharts.core.data.XYDataset;
import net.droidsolutions.droidcharts.core.data.xy.XYSeries;
import net.droidsolutions.droidcharts.core.data.xy.XYSeriesCollection;
import net.droidsolutions.droidcharts.core.plot.PlotOrientation;
import net.droidsolutions.droidcharts.core.plot.XYPlot;
import net.droidsolutions.droidcharts.core.renderer.xy.XYLineAndShapeRenderer;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.view.View;

public class XYLineChart extends View
{
/** The view bounds. */
private final Rect mRect = new Rect();
/** The user interface thread handler. */
private final Handler mHandler;

/**
* Creates a new graphical view.
*
* @param context
*          the context
* @param chart
*          the chart to be drawn
*/
public XYLineChart(Context context)
{
super(context);
mHandler = new Handler();
}

@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
canvas.getClipBounds(mRect);

final XYDataset dataset = createDataset();
final JFreeChart chart = createChart(dataset);
chart.draw(canvas, new Rectangle2D.Double(0, 0, mRect.width(), mRect.height()));
Paint p = new Paint();
p.setColor(Color.RED);
}

/**
* Schedule a user interface repaint.
*/
public void repaint()
{
mHandler.post(new Runnable()
{
public void run()
{
invalidate();
}
});
}

private XYDataset createDataset()
{
final XYSeries series1 = new XYSeries("Rain");
series1.add(1.0, 1.0);
series1.add(2.0, 4.0);
series1.add(3.0, 3.0);
series1.add(4.0, 5.0);
series1.add(5.0, 5.0);
series1.add(6.0, 7.0);
series1.add(7.0, 7.0);
series1.add(8.0, 8.0);

final XYSeries series2 = new XYSeries("Sunshine");
series2.add(1.0, 5.0);
series2.add(2.0, 7.0);
series2.add(3.0, 6.0);
series2.add(4.0, 8.0);
series2.add(5.0, 4.0);
series2.add(6.0, 4.0);
series2.add(7.0, 2.0);
series2.add(8.0, 1.0);

final XYSeries series3 = new XYSeries("Apples");
series3.add(3.0, 4.0);
series3.add(4.0, 3.0);
series3.add(5.0, 2.0);
series3.add(6.0, 3.0);
series3.add(7.0, 6.0);
series3.add(8.0, 3.0);
series3.add(9.0, 4.0);
series3.add(10.0, 3.0);

final XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(series1);
dataset.addSeries(series2);
dataset.addSeries(series3);

return dataset;
}

/**
* Creates a chart.
*
* @param dataset
*          the data for the chart.
*
* @return a chart.
*/
private JFreeChart createChart(final XYDataset dataset)
{

// create the chart...
final JFreeChart chart = ChartFactory.createXYLineChart("Apple Yield", // chart
// title
"Days", // x axis label
"Growth", // y axis label
dataset, // data
PlotOrientation.VERTICAL, true, // include legend
true, // tooltips
false // urls
);

Paint white = new Paint(Paint.ANTI_ALIAS_FLAG);
white.setColor(Color.WHITE);

Paint dkGray = new Paint(Paint.ANTI_ALIAS_FLAG);
dkGray.setColor(Color.DKGRAY);

Paint lightGray = new Paint(Paint.ANTI_ALIAS_FLAG);
lightGray.setColor(Color.LTGRAY);
lightGray.setStrokeWidth(10);

chart.setBackgroundPaint(white);

final XYPlot plot = chart.getXYPlot();
plot.setBackgroundPaint(dkGray);
plot.setDomainGridlinePaint(lightGray);
plot.setRangeGridlinePaint(lightGray);

final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
plot.setRenderer(renderer);

// change the auto tick unit selection to integer units only...
final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

return chart;
}
}

Some extra code:
For passing in the graph parameters, I use a ContentValues object.

/** Called when the activity is first created. */
		@Override
		public void onCreate(Bundle savedInstanceState)
			{
				Log.d(tag, "Creating View");
				super.onCreate(savedInstanceState);

				// DataSet Description
				ContentValues datasetDescription = new ContentValues();
				datasetDescription.put("chart_title", "Journal Overview");
				datasetDescription.put("x_axis", "Day");
				datasetDescription.put("y_axis", "Severity");
				datasetDescription.put("include_legend", true);
				datasetDescription.put("include_tooltips", true);
				datasetDescription.put("include_urls", false);

                                XYLineChartView mView = new XYLineChartView(this, 
                                                               datasetDescription, createDataset(allJournalEntries));
			       setContentView(mView);
                       }

private XYDataset createDataset(List<JournalEntry> data)
			{
				final XYSeriesCollection dataset = new XYSeriesCollection();
				final XYSeries series1 = new XYSeries("Symptoms");
				final XYSeries series2 = new XYSeries("Reactions");

				int counter = 0;
			        
                                // POPULATE YOUR OWN DATA SERIES WITH ACTUAL DATA
                                  
                                // ADD DATA SERIES TO DATA SET
				dataset.addSeries(series1);
				dataset.addSeries(series2);
				return dataset;
			}

For modifying the axis orientation, label colors etc. here is some code:

	/**
		 * Creates a chart.
		 * 
		 * @param dataset
		 *          the data for the chart.
		 * 
		 * @return a chart.
		 */
		private JFreeChart createChart(final XYDataset dataset)
			{
				String chartTitle = datasetDescription.getAsString("chart_title");
				String XAxisLabel = datasetDescription.getAsString("x_axis");
				String YAxisLabel = datasetDescription.getAsString("y_axis");
				boolean includeLegend = datasetDescription.getAsBoolean("include_legend");
				boolean includeToolTips = datasetDescription.getAsBoolean("include_tooltips");
				boolean includeURLs = datasetDescription.getAsBoolean("include_urls");

				// Create Empty Chart
				chart = ChartFactory.createXYLineChart(chartTitle, XAxisLabel, YAxisLabel, dataset, PlotOrientation.VERTICAL, includeLegend, includeToolTips, includeURLs);

				Paint black = new Paint(Paint.ANTI_ALIAS_FLAG);
				black.setColor(Color.BLACK);

				Paint dkGray = new Paint(Paint.ANTI_ALIAS_FLAG);
				dkGray.setColor(Color.DKGRAY);

				Paint lightGray = new Paint(Paint.ANTI_ALIAS_FLAG);
				lightGray.setColor(Color.LTGRAY);
				lightGray.setStrokeWidth(10);

				Paint white = new Paint(Paint.ANTI_ALIAS_FLAG);
				white.setColor(Color.WHITE);

				// Set chart background
				setChartBackground(black);

				final XYPlot plot = chart.getXYPlot();
				plot.setBackgroundPaint(dkGray);
				plot.setDomainGridlinePaint(lightGray);
				plot.setRangeGridlinePaint(lightGray);
				plot.setDomainGridlinePaint(white);
				plot.setRangeGridlinePaint(white);

				final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
				renderer.setSeriesLinesVisible(0, true);
				renderer.setItemLabelPaint(white);
				plot.setRenderer(renderer);

				//Range axis: White labels, white ticks, label at 270 deg orientation (upright)
				final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
				rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
				rangeAxis.setLabelPaint(white);
				rangeAxis.setTickLabelPaint(white);
				rangeAxis.setLabelAngle(270.0);
				
				// Domain axis: White labels and white ticks
				final NumberAxis domainAxis = (NumberAxis) plot.getDomainAxis();
				domainAxis.setLabelPaint(white);
				domainAxis.setTickLabelPaint(white);
				
				return chart;
			}