Drawing a Chart in Android

Tutorials concerning the OpenGL® ES cross-platform API for full-function 2D and 3D graphics on the Google-Android platform.

Drawing a Chart in Android

Postby Maxood » Tue Feb 16, 2010 1:17 pm

I want to draw charts like pie charts to display stats in my Android app. As Android doesn't support Swing and AWT, i wonder how can i draw charts in Android? Please note that i don't want to use a third party tool.

This is something i have come up with after looking into API Demos:

Code: Select all

package com.examples.piechart;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.View;

public class PieChart extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new SampleView(this));
    }
   
    private static class SampleView extends View{
       
        private Paint[] mPaints;
         private Paint mFramePaint;
         private boolean[] mUseCenters;
         private RectF[] mOvals;
         private RectF mBigOval;
         private float mStart;
         private float mSweep;
         private int mBigIndex;
         
         private static final float SWEEP_INC = 2;
         private static final float START_INC = 30;
         
         public SampleView(Context context) {
             super(context);
             
             mPaints = new Paint[4];
             mUseCenters = new boolean[4];
             mOvals = new RectF[4];
     
             mPaints[0] = new Paint();
             mPaints[0].setAntiAlias(true);
             mPaints[0].setStyle(Paint.Style.FILL);
             mPaints[0].setColor(0x88FF0000);
             mUseCenters[0] = false;
             
             mPaints[1] = new Paint(mPaints[0]);
             mPaints[1].setColor(0x8800FF00);
             mUseCenters[1] = true;
             
             mPaints[2] = new Paint(mPaints[0]);
             mPaints[2].setStyle(Paint.Style.STROKE);
             mPaints[2].setStrokeWidth(4);
             mPaints[2].setColor(0x880000FF);
             mUseCenters[2] = false;

             mPaints[3] = new Paint(mPaints[2]);
             mPaints[3].setColor(0x88888888);
             mUseCenters[3] = true;
             
             mBigOval = new RectF(40, 10, 280, 250);
             
             //mOvals[0] = new RectF( 10, 270,  70, 330);
             mOvals[1] = new RectF( 90, 270, 150, 330);
             mOvals[2] = new RectF(170, 270, 230, 330);
             mOvals[3] = new RectF(250, 270, 310, 330);
             
             mFramePaint = new Paint();
             mFramePaint.setAntiAlias(true);
             mFramePaint.setStyle(Paint.Style.STROKE);
             mFramePaint.setStrokeWidth(0);
         }
         
         private void drawArcs(Canvas canvas, RectF oval, boolean useCenter,
                               Paint paint) {
             canvas.drawRect(oval, mFramePaint);
             canvas.drawArc(oval, mStart, mSweep, useCenter, paint);
             
         }
         
         @Override protected void onDraw(Canvas canvas) {
             canvas.drawColor(Color.WHITE);
             
             drawArcs(canvas, mBigOval, mUseCenters[1],
                      mPaints[1]);
            /*
             for (int i = 0; i < 2; i++) {
                 drawArcs(canvas, mOvals[i], mUseCenters[i], mPaints[i]);
                 drawArcs(canvas, mOvals[1], mUseCenters[1], mPaints[1]);
                 }
             */
             
             drawArcs(canvas, mOvals[1], mUseCenters[1], mPaints[1]);
             mSweep += SWEEP_INC;
             if (mSweep > 360) {
                 mSweep -= 360;
                 mStart += START_INC;
                 if (mStart >= 360) {
                     mStart -= 360;
                 }
                 mBigIndex = (mBigIndex + 1) % mOvals.length;
             }
             invalidate();
         }
     }
       
       
    };




Wonder if someone can improve it further.
Maxood

"Life is an endless journey to achieve perfection"
Maxood
Developer
Developer
 
Posts: 34
Joined: Sun Aug 02, 2009 1:37 pm
Location: Karachi, Pakistan

Top

Postby MichaelEGR » Tue Feb 16, 2010 3:21 pm

You are on the right track using the Android 2D API (Canvas et al).

Consider rendering your charts/graphs into a bitmap then render that bitmap as necessary in the onDraw method of the component displaying the chart/graph.

To render to a Bitmap simply do the following (this example renders a solid color into the bitmap!):

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
  3.  
  4. Canvas canvas = new Canvas(bitmap);
  5.  
  6. Paint paint = new Paint();
  7.  
  8. paint.setStyle(Paint.Style.FILL);
  9.  
  10. paint.setColor(Color.RED);
  11.  
  12. canvas.drawRect(0, 0, width, height, paint);
  13.  
  14.  
Parsed in 0.037 seconds, using GeSHi 1.0.8.4
Founder & Principal Architect; EGR Software LLC
http://www.typhonrt.org
http://www.egrsoftware.com
User avatar
MichaelEGR
Senior Developer
Senior Developer
 
Posts: 147
Joined: Thu Jan 21, 2010 5:30 am
Location: San Francisco, CA

Done but one issue still pending

Postby Maxood » Wed Feb 17, 2010 4:13 pm

Done! But there is one thing that i have to write along with displaying the chart i.e. the percentage(eg. 90% , 40%, etc.). Problem is that i cannot take TextView in my setContentView().


Here is my code:
Code: Select all
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.myapps.piechart;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.TextView;

class GraphicsActivity extends Activity {
   

   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
   
       
    }

    public void setContentView(View view) {
        if (false) { // set to true to test Picture
            ViewGroup vg = new PictureLayout(this);
            vg.addView(view);
            view = vg;
           
           
        }
       
        super.setContentView(view);
    }


 


}




Code: Select all
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.myapps.piechart;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ComposePathEffect;
import android.graphics.CornerPathEffect;
import android.graphics.DiscretePathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.ArcShape;
import android.graphics.drawable.shapes.OvalShape;
import android.graphics.drawable.shapes.PathShape;
import android.graphics.drawable.shapes.RectShape;
import android.graphics.drawable.shapes.RoundRectShape;
import android.graphics.drawable.shapes.Shape;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class ShapeDrawable1 extends GraphicsActivity {


   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
       
        setContentView(new SampleView(this));
       
       
    }
   
   
   
    private static class SampleView extends View {
        private ShapeDrawable[] mDrawables;
       
        private static Shader makeSweep() {
            return new SweepGradient(150, 50,
                new int[] { 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0xFFFF0000 },
                null);
        }
       
        private static Shader makeLinear() {
            return new LinearGradient(0, 0, 50, 50,
                              new int[] { 0xFFFF0000, 0xFF00FF00, 0xFF0000FF },
                              null, Shader.TileMode.MIRROR);
        }
       
        private static Shader makeTiling() {
            int[] pixels = new int[] { 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0};
            Bitmap bm = Bitmap.createBitmap(pixels, 2, 2,
                                            Bitmap.Config.ARGB_8888);
           
            return new BitmapShader(bm, Shader.TileMode.REPEAT,
                                        Shader.TileMode.REPEAT);
        }
       
        private static class MyShapeDrawable extends ShapeDrawable {
            private Paint mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
           
            public MyShapeDrawable(Shape s) {
                super(s);
                mStrokePaint.setStyle(Paint.Style.STROKE);
            }
           
            public Paint getStrokePaint() {
                return mStrokePaint;
            }
           
            @Override protected void onDraw(Shape s, Canvas c, Paint p) {
                s.draw(c, p);
                s.draw(c, mStrokePaint);
            }
           
          private void setText(String s)
          {
            this.setText(s); 
          }
           
          private String getText()
          { 
             return this.getText();
          }

        }
       
        public SampleView(Context context) {
            super(context);
            setFocusable(true);

            float[] outerR = new float[] { 12, 12, 12, 12, 0, 0, 0, 0 };
            RectF   inset = new RectF(6, 6, 6, 6);
            float[] innerR = new float[] { 12, 12, 0, 0, 12, 12, 0, 0 };
           
            Path path = new Path();
            path.moveTo(50, 0);
            path.lineTo(0, 50);
            path.lineTo(50, 100);
            path.lineTo(100, 50);
            path.close();
           
            mDrawables = new ShapeDrawable[8];
            mDrawables[0] = new ShapeDrawable(new RectShape());
            mDrawables[1] = new ShapeDrawable(new OvalShape());
            mDrawables[2] = new ShapeDrawable(new RoundRectShape(outerR, null,
                                                                 null));
            mDrawables[3] = new ShapeDrawable(new RoundRectShape(outerR, inset,
                                                                 null));
            mDrawables[4] = new ShapeDrawable(new RoundRectShape(outerR, inset,
                                                                 innerR));
            mDrawables[5] = new ShapeDrawable(new PathShape(path, 100, 100));
           
            //Complete circle
            mDrawables[6] = new MyShapeDrawable(new ArcShape(0, -365));
           
            //Setting percentage
            mDrawables[7] = new MyShapeDrawable(new ArcShape(0, -90));
           
           
            mDrawables[0].getPaint().setColor(0xFFFF0000);
            mDrawables[1].getPaint().setColor(0xFF00FF00);
            mDrawables[2].getPaint().setColor(0xFF0000FF);
            mDrawables[3].getPaint().setShader(makeSweep());
            mDrawables[4].getPaint().setShader(makeLinear());
            mDrawables[5].getPaint().setShader(makeTiling());
            mDrawables[6].getPaint().setColor(0xFF0000FF);
            mDrawables[7].getPaint().setColor(0xFF00FF00);
           
            PathEffect pe = new DiscretePathEffect(10, 4);
            PathEffect pe2 = new CornerPathEffect(4);
            mDrawables[3].getPaint().setPathEffect(new ComposePathEffect(pe2, pe));
       
            MyShapeDrawable msd = (MyShapeDrawable)mDrawables[6];
            msd.getStrokePaint().setStrokeWidth(4);
           
           
        }
       
        @Override protected void onDraw(Canvas canvas) {
           
            int x = 10;
            int y = 10;
            int width = 300;
            int height = 300;
           
           /* for (Drawable dr : mDrawables) {
                dr.setBounds(x, y, x + width, y + height);
                dr.draw(canvas);               
                y += height + 5;
            }*/
           
           
            /*
            mDrawables[7] = new MyShapeDrawable(new ArcShape(0, -300));
            mDrawables[7].getPaint().setColor(0xFF00FF00);
            mDrawables[7].setBounds(x, y, 150, 150);
            mDrawables[7].draw(canvas);
            y += height + 5;
            */
           
            //setting width and height and location of Pie Chart
           
            mDrawables[6].setBounds(x, 100, 200, 270);
            mDrawables[6].draw(canvas);
            y += height + 5;
           
           
            mDrawables[7].setBounds(x, 100, 200, 270);
            mDrawables[7].draw(canvas);
            y += height + 5;
           
           
           
           
         
        }
    }
}






Code: Select all

/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.myapps.piechart;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Picture;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;


public class PictureLayout extends ViewGroup {
    private final Picture mPicture = new Picture();

    public PictureLayout(Context context) {
        super(context);
    }

    public PictureLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }   

    @Override
    public void addView(View child) {
        if (getChildCount() > 1) {
            throw new IllegalStateException("PictureLayout can host only one direct child");
        }

        super.addView(child);
    }

    @Override
    public void addView(View child, int index) {
        if (getChildCount() > 1) {
            throw new IllegalStateException("PictureLayout can host only one direct child");
        }

        super.addView(child, index);
    }

    @Override
    public void addView(View child, LayoutParams params) {
        if (getChildCount() > 1) {
            throw new IllegalStateException("PictureLayout can host only one direct child");
        }

        super.addView(child, params);
    }

    @Override
    public void addView(View child, int index, LayoutParams params) {
        if (getChildCount() > 1) {
            throw new IllegalStateException("PictureLayout can host only one direct child");
        }

        super.addView(child, index, params);
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int count = getChildCount();

        int maxHeight = 0;
        int maxWidth = 0;

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                measureChild(child, widthMeasureSpec, heightMeasureSpec);
            }
        }

        maxWidth += getPaddingLeft() + getPaddingRight();
        maxHeight += getPaddingTop() + getPaddingBottom();

        Drawable drawable = getBackground();
        if (drawable != null) {
            //maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
            //maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
           maxHeight=200;
           maxWidth=100;
        }

        setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
                resolveSize(maxHeight, heightMeasureSpec));
    }
   
    private void drawPict(Canvas canvas, int x, int y, int w, int h,
                          float sx, float sy) {
        canvas.save();
        canvas.translate(x, y);
        canvas.clipRect(0, 0, w, h);
        canvas.scale(0.5f, 0.5f);
        canvas.scale(sx, sy, w, h);
        canvas.drawPicture(mPicture);
        canvas.restore();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight()));
        mPicture.endRecording();
       
        int x = getWidth()/2;
        int y = getHeight()/2;
       
        if (false) {
            canvas.drawPicture(mPicture);
        } else {
            drawPict(canvas, 0, 0, x, y,  1,  1);
            drawPict(canvas, x, 0, x, y, -1,  1);
            drawPict(canvas, 0, y, x, y,  1, -1);
            drawPict(canvas, x, y, x, y, -1, -1);
        }
    }

    @Override
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
        location[0] = getLeft();
        location[1] = getTop();
        dirty.set(0, 0, getWidth(), getHeight());
        return getParent();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int count = super.getChildCount();

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final int childLeft = getPaddingLeft();
                final int childTop = getPaddingTop();
                child.layout(childLeft, childTop,
                        childLeft + child.getMeasuredWidth(),
                        childTop + child.getMeasuredHeight());

            }
        }
    }
}

Maxood

"Life is an endless journey to achieve perfection"
Maxood
Developer
Developer
 
Posts: 34
Joined: Sun Aug 02, 2009 1:37 pm
Location: Karachi, Pakistan

Re: Drawing a Chart in Android

Postby Avw » Sat Oct 30, 2010 7:22 am

hi i followed ur code..but im getting a blank screen...Pls help me to resolve it
Avw
Freshman
Freshman
 
Posts: 4
Joined: Tue Oct 12, 2010 8:20 am

Re: Drawing a Chart in Android

Postby Avw » Wed Nov 03, 2010 1:31 pm

Hi all....I hav drawn pie-chart and
I followed AChartEngine to draw it :)
Avw
Freshman
Freshman
 
Posts: 4
Joined: Tue Oct 12, 2010 8:20 am

Re: Drawing a Chart in Android

Postby Emy87aa » Thu Jun 16, 2011 11:50 am

hii all ..
I wrote this code in eclipse but when I try to run the emulator give me a message say "the application has stopped unexpectedly, please try again"

what I should do in this case ???
Emy87aa
Once Poster
Once Poster
 
Posts: 1
Joined: Thu Jun 16, 2011 11:46 am

Top

Re: Drawing a Chart in Android

Postby herwadeshirish » Fri Sep 30, 2011 7:38 am

hi... I tried this code. I am getting the following exception:


09-30 11:53:25.333: ERROR/AndroidRuntime(44): *** FATAL EXCEPTION IN SYSTEM PROCESS: ThrottleService
09-30 11:53:25.333: ERROR/AndroidRuntime(44): java.lang.NullPointerException
09-30 11:53:25.333: ERROR/AndroidRuntime(44): at com.android.server.ThrottleService$DataRecorder.checkAndDeleteLRUDataFile(ThrottleService.java:924)
09-30 11:53:25.333: ERROR/AndroidRuntime(44): at com.android.server.ThrottleService$DataRecorder.getDataFile(ThrottleService.java:904)
09-30 11:53:25.333: ERROR/AndroidRuntime(44): at com.android.server.ThrottleService$DataRecorder.record(ThrottleService.java:988)
09-30 11:53:25.333: ERROR/AndroidRuntime(44): at com.android.server.ThrottleService$DataRecorder.addData(ThrottleService.java:886)
09-30 11:53:25.333: ERROR/AndroidRuntime(44): at com.android.server.ThrottleService$MyHandler.onPollAlarm(ThrottleService.java:484)
09-30 11:53:25.333: ERROR/AndroidRuntime(44): at com.android.server.ThrottleService$MyHandler.handleMessage(ThrottleService.java:363)
09-30 11:53:25.333: ERROR/AndroidRuntime(44): at android.os.Handler.dispatchMessage(Handler.java:99)
09-30 11:53:25.333: ERROR/AndroidRuntime(44): at android.os.Looper.loop(Looper.java:130)
09-30 11:53:25.333: ERROR/AndroidRuntime(44): at android.os.HandlerThread.run(HandlerThread.java:60)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): Can't write: system_server_crash
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): java.io.FileNotFoundException: /data/system/dropbox/drop43.tmp (Too many open files)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at org.apache.harmony.luni.platform.OSFileSystem.open(Native Method)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at dalvik.system.BlockGuard$WrappedFileSystem.open(BlockGuard.java:232)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at java.io.FileOutputStream.<init>(FileOutputStream.java:94)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at java.io.FileOutputStream.<init>(FileOutputStream.java:66)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at com.android.server.DropBoxManagerService.add(DropBoxManagerService.java:187)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at android.os.DropBoxManager.addText(DropBoxManager.java:243)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at com.android.server.am.ActivityManagerService$11.run(ActivityManagerService.java:6840)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at com.android.server.am.ActivityManagerService.addErrorToDropBox(ActivityManagerService.java:6845)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at com.android.server.am.ActivityManagerService.handleApplicationCrash(ActivityManagerService.java:6492)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:76)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:854)
09-30 11:53:25.354: ERROR/DropBoxManagerService(44): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:851)
herwadeshirish
Once Poster
Once Poster
 
Posts: 1
Joined: Fri Sep 30, 2011 7:33 am

Re: Drawing a Chart in Android

Postby roopa » Wed Oct 19, 2011 11:14 am

I really appreciate of your self for the helpful information you have shared. I find this information very useful and it has considerably saved my time.
roopa
Developer
Developer
 
Posts: 27
Joined: Wed Sep 14, 2011 6:46 am

Re: Drawing a Chart in Android

Postby Jhenna » Wed Feb 22, 2012 12:41 pm

I was also having the same problem and i thought i was not possible.
jura impressa c5
Android Rocks!~
Jhenna
Once Poster
Once Poster
 
Posts: 1
Joined: Wed Feb 08, 2012 6:15 pm

Re: Drawing a Chart in Android

Postby hath88 » Thu Mar 15, 2012 10:18 am

hath88
Senior Developer
Senior Developer
 
Posts: 169
Joined: Thu Mar 01, 2012 5:21 am

Top

Return to Android 2D/3D Graphics - OpenGL Tutorials

Who is online

Users browsing this forum: No registered users and 4 guests