JustAMartin
JustAMartin

Reputation: 13733

Charting on Android - problems with androidplot and achartengine

I want to integrate a simple XY line chart in my Activity. While looking for free charting with customization (customizable backgrounds, colors, axis labels), I found two candidates: Achartengine and Adnroidplot. There were some other libraries, but they were not customizable or available only as separate Intents.

I need also support for older Android API (at least 1.6 must be supported).

I tried Achartengine but it failed when I integrated it in a ScrollView. When I was scrolling, the chart became somehow corrupted, it got squeezed and some background elements seemed to drift away.

Then I tried Adnroidplot. At first it did not start on 1.6 because of a Pair class. But I found a fix for the problem on Adnroidplot forum. Everything seemed to work fine, also dynamic updates though custom Observers worked fine. It was a bit hard to customize X axis labels (I needed custom Strings there and not numbers), but with a custom formatter I finally did it.

But then I tried it with real data from a client's database. There were some series of points with equal values. And I was shocked to see that Adnroidplot is not able to draw a horizontal line, it hangs or completely messes up the chart!

Here is the test case, I borrowed it from Adnroidplot Quickstart and did a small modification to make one series with equal values:

pricesPlot = (XYPlot) findViewById(R.id.mySimpleXYPlot);

// Create array of y-values to plot:
Number[] series1Numbers = {7, 7}; // horizontal line expected, got nothing or hang

// Turn the above arrays into XYSeries:
XYSeries series1 = new SimpleXYSeries(
    Arrays.asList(series1Numbers),          // SimpleXYSeries takes a List so turn our array into a List
    ArrayFormat.Y_VALS_ONLY, // Y_VALS_ONLY means use the element index as the x value
            "Series1");                             // Set the display title of the series

// Create a formatter to use for drawing a series using LineAndPointRenderer:
LineAndPointFormatter series1Format = new LineAndPointFormatter(
            Color.rgb(0, 200, 0),                   // line color
            Color.rgb(0, 100, 0),                   // point color
            null);              // fill color (optional) <- my app hangs if I add it for a horizontal line

// Add series1 to the xyplot:
pricesPlot.addSeries(series1, series1Format);

// Reduce the number of range labels
pricesPlot.setTicksPerRangeLabel(3);

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

I already posted on Adnroidplot forums, but I am not sure how fast they will answer and when the issue will be fixed.

So I hope maybe someone at StackOverflow might know some workaround for it?

Upvotes: 3

Views: 2728

Answers (3)

codelame
codelame

Reputation: 537

For those who googled for chart squeezing problems inside ScrollView with AChartEngine this is solution to your problem:

renderer.setInScroll(true);

Upvotes: 1

whyoz
whyoz

Reputation: 5246

I came up with an easy workaround to make sure horizontal lines are shown.

Basically, just graph a 3 point clear Y_VALS_ONLY series before you load your first real plot.

Assuming you have a colors.xml res file, you can create a clear series like this:

Declare this:

Number[] yClear = {0, 1, 0};
LineAndPointFormatter clearFormat; 
SimpleXYSeries clear= null;

In your onCreate() or onViewCreated():

clearFormat = new LineAndPointFormatter(getResources().getColor(R.color.transparent), getResources().getColor(R.color.transparent), 0, null);

Then after you set up your plot, just add the clear plot to the graph;

clear = new SimpleXYSeries( Arrays.asList(yClear), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Clear");
yourPlot.addSeries(clear, clearFormat);

I spent hours trying to debug this issue, and it came down to just making life easy and doing it this way.

Upvotes: 1

JustAMartin
JustAMartin

Reputation: 13733

Thanks to the developers on Androidplot forums, I now got the solution. The following code is a fragment of my Activity.java file. Unfortunately the final code was later refactored and some pieces moved to a custom datasource and custom XYSeries which I don't have permissions to publish here.

This code worked for Androidplot-core-0.4.4-release.jar, and I'm not sure if it will work with later versions.

// for chart
private XYPlot pricesPlot;

/** Called when the activity is first created. */   
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ... other initialisation code omitted for brevity ...

    pricesPlot = (XYPlot) findViewById(R.id.mySimpleXYPlot);

    // the following code was added as a debug code to test that it works.
    // later many things were changed, so take it "as is" - this was the core of the solution

    PriceDatesFormat ppf = new PriceDatesFormat();
    ppf.Labels = new String[]{
                "2011-01",
                "2011-05",              
                "2011-07",
                "2011-11",
                "2011-07",
                "2011-07"                       
        }; 

    pricesPlot.getGraphWidget().setDomainValueFormat(ppf);       

    // Create two arrays of y-values to plot:
    Float [] seriesNumbers = new Float[]{118f, 185f};

   Float min = Collections.min(Arrays.asList(seriesNumbers));
   Float max = Collections.max(Arrays.asList(seriesNumbers));  

   pricesPlot.setRangeBoundaries(min - 0.1*min, max + 0.1*max, BoundaryMode.AUTO);// make them a bit wider out of min/max values

Upvotes: 3

Related Questions