Line Chart with Two Y-axis Using AchartEngine API

As AChartEngine is a charting library for Android applications. It currently supports the following chart types: There are more charting APIs as well but the most flexible and open source API that I found is AChartEngine.
  • Line chart
  • Area chart
  • Scatter chart
  • Time chart
  • Bar chart
  • Pie chart
  • Bubble chart
  • Doughnut chart
  • Range (high-low) bar chart
  • Dial chart / gauge
  • Combined (any combination of line, cubic line, scatter, bar, range bar, bubble) chart
  • Cubic line chart 


In this post I am going to give Line Chart example, a very common and huge used in android Charting apps. The graph has two Y-axis and one X-axis. X-axis shows time in format DAY/Month, while Y-axis the number of quantities for which graph should be populated.

My Screen GUI looks like:

Line Chart Using AchartEngine
Though the sample demos are provided by AchartEngine API demos, However they are not dynamically populated as they are for fixed ranges.So if you want to display the graph for some dynamic values you can this code.

MyCubicLineChart.java


public class MyCubicLineChart extends AbstractDemoChart {
    int cigLen = 0;
    int xLen = 0;
    int dateLen = 0;
    Date date = null;
    int day, month;
    double ratio;
    int diffInDays;
    String formatedGoalDate;
  
  public String getName() {
    return "NicoBloc Graph";
  }

  public String getDesc() {
    return "Line chart with multiple Y scales and axis";
  }

  public LinearLayout execute(Context context) {
        List<double[]> x = new ArrayList<double[]>();

        cigLen = DaoDataSource.cigList.size();
        dateLen = DaoDataSource.dateList.size();
        Calendar cal = Calendar.getInstance();
      
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date regDate = dateFormat.parse(DaoDataSource.idealDateList.get(0));
            Date goalDate = dateFormat.parse(DaoDataSource.idealDateList.get(1));
            cal.setTime(goalDate);  
            day = cal.get(Calendar.DAY_OF_MONTH);
            month = cal.get(Calendar.MONTH);
            month = month + 1;
            formatedGoalDate = day +"/"+ month;
            diffInDays = (int) ((goalDate.getTime() - regDate.getTime()) / (1000 * 60 * 60 * 24));
        } catch (ParseException e) {
            e.printStackTrace();
        }
              
        double diff = DaoDataSource.idealCigList.get(0) - DaoDataSource.idealCigList.get(1);  //20-10
        if (diffInDays == 1){
            // This is just to avoid devision by zero exception
            ratio = diff/(diffInDays);  
        }else{
            ratio = diff/(diffInDays-1);
        }
        String tmpStrDate[] = new String[cigLen];
              
        for (int i = 0; i < dateLen; i++){
            try {
                date = dateFormat.parse(DaoDataSource.dateList.get(i));
                cal.setTime(date);  
                day = cal.get(Calendar.DAY_OF_MONTH);
                month = cal.get(Calendar.MONTH);
                month = month + 1;
              
                tmpStrDate[i] = day +"/"+ month;
                //Log.v("Date", ""+ tmpStrDate[i]);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
              
        double xDays [];
        double cig [];
        double points [];
        double idealCurve [];
        String[] titles;
      
        if (cigLen <= diffInDays){
            xDays = new double [diffInDays];
            for (int i = 0; i < diffInDays; i++) {
                xDays[i] = i;
            }
              
            cig = new double [diffInDays];
            points = new double [diffInDays];
            idealCurve = new double [diffInDays];
  
            titles = new String[] { "Antal cigaretter", "MÃ¥lkurva"};
              
            for (int i = 0; i < titles.length; i++) {
              x.add(xDays);
              x.toArray();
            }
        }else{
             xDays = new double [cigLen];
             for (int i = 0; i < cigLen; i++) {
                xDays[i] = i;
             }
                  
            cig = new double [cigLen];
            points = new double [cigLen];
            idealCurve = new double [diffInDays];
  
            titles = new String[] { "Antal cigaretter", "MÃ¥lkurva"};
              
            for (int i = 0; i < titles.length; i++) {
              x.add(xDays);
              x.toArray();
           }
        }
       
        xLen = x.get(0).length;
        double initial = DaoDataSource.idealCigList.get(0);
         
        for (int i = 0; i < cigLen ; i++){
            cig [i] =  DaoDataSource.cigList.get(i);
            points [i] =  DaoDataSource.pointList.get(i);
        }
      
        for (int i = 0; i < diffInDays ; i++){
            idealCurve[i] = initial;
            initial  = initial - ratio  ;
        }
                 
        List<double[]> values = new ArrayList<double[]>();
        // Add cigars values
        values.add(cig);
        values.add(idealCurve);
        values.toArray();
      
        // Set color of lines
        int[] colors = new int[] { Color.BLUE, Color.GREEN, Color.YELLOW};
        PointStyle[] styles = new PointStyle[] { PointStyle.CIRCLE, PointStyle.POINT, PointStyle.DIAMOND};
      
        XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer(2);
        setRenderer(renderer, colors, styles);
        renderer.setPointSize(4.5f);
        int length = renderer.getSeriesRendererCount();
        for (int i = 0; i < length; i++) {
            XYSeriesRenderer r = (XYSeriesRenderer) renderer.getSeriesRendererAt(i);
            r.setLineWidth(3);
            r.setFillPoints(true);
        }
     
        //Manually setting bounds for scale 0
        renderer.setXAxisMin(0, 0);
        renderer.setXAxisMax(7, 0);
        renderer.setYAxisMin(0, 0);
        renderer.setYAxisMax(50, 0);
        //renderer.setXTitle("DD/MM");
                     
        renderer.setXLabels(7);
        renderer.setYLabels(10);
        renderer.setShowGrid(true);
        renderer.setXLabelsAlign(Align.RIGHT);
        renderer.setYLabelsAlign(Align.RIGHT);      
        renderer.setZoomButtonsVisible(true);
        renderer.setZoomRate(1.05f);
        renderer.setLabelsColor(Color.WHITE);
        renderer.setXLabelsColor(Color.GREEN);
        renderer.setYAxisMin(0, 0);
        renderer.setYAxisMax(50, 0);
    
        renderer.setYLabelsColor(0, colors[0]);
        renderer.setYLabelsColor(1, colors[2]);
      
        // Change text font and color here
        renderer.setTextTypeface("sans_serif", Typeface.BOLD);         
        renderer.setLabelsTextSize(15.0f);
        renderer.setAxisTitleTextSize(15);
        renderer.setLegendTextSize(15);
      
        //renderer.setYTitle("% Tar/Nicotine", 1);
        renderer.setYAxisAlign(Align.RIGHT, 1);
        renderer.setYLabelsAlign(Align.LEFT, 1);
        renderer.setYAxisAlign(Align.CENTER,1);
      
        // Change color of X and Y Labels
//        renderer.setXLabelsColor(Color.BLACK);
//        renderer.setYLabelsColor(0, Color.BLACK);
//        renderer.setYLabelsColor(1, Color.BLACK);
      
        //Manually setting bounds for scale 1
        renderer.setXAxisMin(0, 1);
         renderer.setXAxisMax(7, 1);
        renderer.setYAxisMin(0, 1);
        renderer.setYAxisMax(100, 1);
      
        //disable the default labels
        renderer.setXLabels(0);
        renderer.setShowCustomTextGrid(true);
        for (int i = 0; i < cigLen; i++){
            renderer.addXTextLabel(i, tmpStrDate[i]);
        }
        renderer.addXTextLabel(diffInDays-1, formatedGoalDate);
        renderer.setXLabelsAlign(Align.CENTER);
      
        XYMultipleSeriesDataset dataset = buildDataset(titles, x, values);
        values.clear();
      
        // Add Tar/Nicotine values
        values.add(points);
        values.toArray();
      
        addXYSeries(dataset, new String[] { "Andel tjära och nikotin I förhÃ¥llande till vad du rökte tidigare" }, x, values, 1);
  
        // set background color
        renderer.setApplyBackgroundColor(true);   
        renderer.setBackgroundColor(Color.GRAY);
        renderer.setMarginsColor(Color.GRAY);
      
        GraphicalView gview = ChartFactory.getCubeLineChartView(context, dataset, renderer, 0.0f);
  
        LinearLayout lnr = null;
        lnr = new LinearLayout(context);
        lnr.addView(gview);
      
        return lnr;
  }
}

6 comments:

  1. This source code has been tested and works fine. If you have any queries regarding source code feel free to add your valuable comments

    ReplyDelete
  2. Hi! Is that possible to have two x axis?

    ReplyDelete
  3. Thanks. I was searching for exact this kind of Two side y-axis. Great work

    ReplyDelete
  4. I wanted only one y-axis but at the right side. is it possible?

    ReplyDelete
  5. i want to draw with unsorted values Is it possible?

    ReplyDelete
  6. nice but we need complete souce code

    ReplyDelete