Jesse A. Green / notebook

MPAndroidChart User Guide

Generated June 2026 from PhilJay/MPAndroidChart at 9c7275a

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

MPAndroidChart is a powerful, easy-to-use charting library for Android. It draws line, bar, pie, scatter, bubble, candlestick, radar, and combined charts as native Android Views, complete with touch gestures (drag, pinch-zoom, highlighting), animations, and extensive styling. You add a chart to your layout, hand it your data, and call one method to render it.

This guide is organized around the chart types you can draw. Each chart type has a self-contained, copy-paste recipe: the XML view tag, the data shape it expects, and the code that turns your numbers into a rendered chart. A shared Common Configuration section covers axes, legend, animations, and interaction — the settings that work the same way across every chart.

Note

MPAndroidChart is a view-based library. Every chart is a subclass of Android's View, so it lives inside your XML layouts and Java/Kotlin code exactly like a TextView or Button would. There is no separate canvas or web component to manage.


Table of Contents

  1. Quick Start
  2. Installation
  3. The Core Workflow
  4. Line Chart
  5. Bar Chart & Horizontal Bar Chart
  6. Pie Chart
  7. Scatter, Bubble & Candlestick Charts
  8. Radar & Combined Charts
  9. Common Configuration (All Charts)
  10. Interaction: Gestures, Highlighting & Markers
  11. Animations
  12. Saving a Chart as an Image
  13. Troubleshooting
  14. FAQ
  15. Quick Reference

1. Quick Start

Get a line chart on screen in three steps.

Step 1 — Add the dependency (see Installation for full details):

dependencies {
    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
}

Step 2 — Add the chart to your layout (res/layout/activity_main.xml):

<com.github.mikephil.charting.charts.LineChart
    android:id="@+id/chart"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Step 3 — Feed it data (in your Activity):

LineChart chart = findViewById(R.id.chart);

List<Entry> entries = new ArrayList<>();
entries.add(new Entry(0f, 4f));
entries.add(new Entry(1f, 7f));
entries.add(new Entry(2f, 2f));
entries.add(new Entry(3f, 9f));

LineDataSet dataSet = new LineDataSet(entries, "Sales");  // "Sales" appears in the legend
LineData lineData = new LineData(dataSet);

chart.setData(lineData);
chart.invalidate();   // refresh / draw the chart

That's the entire pattern: build entries → wrap them in a DataSet → wrap that in a chart-data object → setData() → invalidate(). Every chart type follows it.

Tip

invalidate() triggers a redraw. Call it whenever you change data or styling after the chart is already on screen. If you call animateX() / animateY() instead, you don't need invalidate() — the animation refreshes the chart for you.


2. Installation

MPAndroidChart is distributed through JitPack, not Maven Central, so you must add the JitPack repository in addition to the dependency.

Requirements

Requirement Value
Minimum Android API 14 (Android 4.0 Ice Cream Sandwich)
Animations require API 11+ (always satisfied at minSdk 14)
Language Java or Kotlin
License Apache License 2.0
Latest release 3.1.0

Add the JitPack repository

In Gradle 6 / older project layouts, add this to your project-level build.gradle:

allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }   // required for MPAndroidChart
    }
}

In newer projects using settings.gradle with dependencyResolutionManagement, add it there instead:

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}

Add the dependency

In your module-level build.gradle (e.g. app/build.gradle):

Gradle (Groovy)

dependencies {
    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
}

Gradle (Kotlin DSL)

dependencies {
    implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
}

Maven

<repository>
    <id>jitpack.io</id>
    <url>https://jitpack.io</url>
</repository>

<dependency>
    <groupId>com.github.PhilJay</groupId>
    <artifactId>MPAndroidChart</artifactId>
    <version>v3.1.0</version>
</dependency>

Warning

The version tag is v3.1.0 — with the leading v. The single most common setup error is Failed to resolve: com.github.PhilJay:MPAndroidChart:v3.1.0, which almost always means the JitPack repository line is missing from your build configuration. See Troubleshooting.

Important

This library uses AndroidX. Your project must have AndroidX enabled (android.useAndroidX=true in gradle.properties). New Android Studio projects have this on by default.


3. The Core Workflow

Every chart in MPAndroidChart is assembled from the same four building blocks. Understanding them once means you understand all nine chart types.

Block What it is Example
Entry One data point. The subclass depends on the chart. new Entry(0f, 4f)
DataSet A styled series of entries (one line, one set of bars, …). Carries color, label, line width, etc. new LineDataSet(entries, "Sales")
ChartData A container holding one or more DataSets. new LineData(dataSet)
Chart (View) The on-screen view that renders the data. LineChart in your layout
Entry, Entry, Entry  ──►  DataSet  ──►  ChartData  ──►  chart.setData(...)  ──►  invalidate()
   (your numbers)        (one series)   (all series)

Each chart type uses matching subclasses of these blocks. The table below is the master key to the whole library — pick your chart type and use the classes on that row.

Chart type View class Entry class (constructor) DataSet class ChartData class
Line LineChart Entry(x, y) LineDataSet LineData
Bar BarChart BarEntry(x, y) BarDataSet BarData
Horizontal bar HorizontalBarChart BarEntry(x, y) BarDataSet BarData
Pie PieChart PieEntry(value, label) PieDataSet PieData
Scatter ScatterChart Entry(x, y) ScatterDataSet ScatterData
Bubble BubbleChart BubbleEntry(x, y, size) BubbleDataSet BubbleData
Candlestick CandleStickChart CandleEntry(x, high, low, open, close) CandleDataSet CandleData
Radar RadarChart RadarEntry(value) RadarDataSet RadarData
Combined CombinedChart (any of the above) (any of the above) CombinedData

Note

Add multiple DataSets to one chart to draw multiple series (e.g. two lines). Most ChartData constructors accept either a single DataSet or a list: new LineData(setA, setB). Pie charts are the exception — a PieChart displays exactly one PieDataSet.


4. Line Chart

Use case: trends over time or any continuous X axis — sales per month, sensor readings, stock prices.

Data shape: Entry(float x, float y).

Complete recipe

LineChart chart = findViewById(R.id.chart);

List<Entry> entries = new ArrayList<>();
entries.add(new Entry(0f, 4f));
entries.add(new Entry(1f, 7f));
entries.add(new Entry(2f, 5f));
entries.add(new Entry(3f, 9f));
entries.add(new Entry(4f, 6f));

LineDataSet set = new LineDataSet(entries, "Revenue");
set.setColor(Color.BLUE);          // line color
set.setLineWidth(2.5f);            // line thickness in dp (0.2–10)
set.setCircleColor(Color.BLUE);    // color of the point markers
set.setCircleRadius(4f);           // point marker size
set.setDrawValues(true);           // draw the y-value above each point
set.setValueTextSize(10f);

chart.setData(new LineData(set));
chart.invalidate();

Line drawing modes

The most distinctive line setting is the drawing mode, which controls how points are connected:

set.setMode(LineDataSet.Mode.CUBIC_BEZIER);
Mode Effect
LINEAR Straight segments between points (default).
STEPPED Right-angle "staircase" steps.
CUBIC_BEZIER Smooth, rounded curve through points.
HORIZONTAL_BEZIER Smooth curve with horizontal control handles.

For cubic modes, tune the curve tightness with set.setCubicIntensity(0.2f) (range 0.05–1.0; default 0.2).

Filled lines (area chart)

Turn a line chart into an area chart by enabling fill:

set.setDrawFilled(true);
set.setFillColor(Color.BLUE);
set.setFillAlpha(85);              // 0–255 transparency (default 85)

On API 18+ you can fill with a gradient drawable instead: set.setFillDrawable(myDrawable).

Dashed lines and point styling

set.enableDashedLine(10f, 5f, 0f); // lineLength, spaceLength, phase
set.setDrawCircles(false);         // hide the point markers entirely
set.setDrawCircleHole(true);       // draw a hole in each circle
set.setCircleHoleColor(Color.WHITE);

Caution

Dashed lines (enableDashedLine) only render when hardware acceleration is turned off for the view. Hardware acceleration is on by default and boosts performance, so disabling it is a real trade-off — call chart.setHardwareAccelerationEnabled(false) only if you need dashes. See Troubleshooting.

Multiple lines

LineDataSet revenue = new LineDataSet(revenueEntries, "Revenue");
revenue.setColor(Color.BLUE);

LineDataSet cost = new LineDataSet(costEntries, "Cost");
cost.setColor(Color.RED);

chart.setData(new LineData(revenue, cost));  // two lines, one chart
chart.invalidate();

5. Bar Chart & Horizontal Bar Chart

Use case: comparing discrete categories — counts per category, votes per option. HorizontalBarChart is the same chart rotated 90°, ideal when category labels are long.

Data shape: BarEntry(float x, float y), or BarEntry(float x, float[] stackValues) for stacked bars.

Complete recipe

BarChart chart = findViewById(R.id.chart);

List<BarEntry> entries = new ArrayList<>();
entries.add(new BarEntry(0f, 30f));
entries.add(new BarEntry(1f, 80f));
entries.add(new BarEntry(2f, 60f));
entries.add(new BarEntry(3f, 50f));

BarDataSet set = new BarDataSet(entries, "Quarterly Units");
set.setColors(ColorTemplate.MATERIAL_COLORS);  // a built-in color palette

BarData data = new BarData(set);
data.setBarWidth(0.9f);          // bar width in x-axis units (default 0.85)

chart.setData(data);
chart.setFitBars(true);          // pad the x-axis so edge bars aren't clipped
chart.invalidate();

HorizontalBarChart uses the exact same code — only the view class in your XML changes:

<com.github.mikephil.charting.charts.HorizontalBarChart ... />

Bar-specific options

chart.setDrawValueAboveBar(true);  // values above bars instead of inside (default true)
chart.setDrawBarShadow(true);      // grey "max value" backdrop behind each bar
set.setBarBorderWidth(1f);
set.setBarBorderColor(Color.BLACK);

Warning

setDrawBarShadow(true) reduces rendering performance by roughly 50%. Use it sparingly on large datasets.

Stacked bars

Pass an array of values to BarEntry and label each segment:

BarEntry stacked = new BarEntry(0f, new float[]{ 10f, 20f, 30f });
BarDataSet set = new BarDataSet(Collections.singletonList(stacked), "Breakdown");
set.setStackLabels(new String[]{ "Online", "Retail", "Wholesale" });
set.setColors(Color.RED, Color.GREEN, Color.BLUE);  // one color per stack segment

Grouped bars (multiple datasets side by side)

BarDataSet set2020 = new BarDataSet(entries2020, "2020");
BarDataSet set2021 = new BarDataSet(entries2021, "2021");
set2020.setColor(Color.BLUE);
set2021.setColor(Color.GREEN);

BarData data = new BarData(set2020, set2021);
float barWidth = 0.3f, barSpace = 0.05f, groupSpace = 0.3f;
data.setBarWidth(barWidth);
chart.setData(data);

chart.groupBars(0f, groupSpace, barSpace);  // fromX, groupSpace, barSpace
chart.invalidate();

Important

groupBars() overwrites the x-values of your entries to position the groups, and calls notifyDataSetChanged() for you. Set your data on the chart before calling it, and ensure groupSpace + barCount × (barWidth + barSpace) sums correctly to one x-unit per group.


6. Pie Chart

Use case: parts of a whole — market share, budget breakdown, poll results.

Data shape: PieEntry(float value, String label). Pie entries have no x-value — they are inherently unordered slices.

Complete recipe

PieChart chart = findViewById(R.id.chart);

List<PieEntry> entries = new ArrayList<>();
entries.add(new PieEntry(40f, "Android"));
entries.add(new PieEntry(30f, "iOS"));
entries.add(new PieEntry(20f, "Web"));
entries.add(new PieEntry(10f, "Other"));

PieDataSet set = new PieDataSet(entries, "Platforms");
set.setColors(ColorTemplate.COLORFUL_COLORS);
set.setValueTextSize(14f);
set.setSliceSpace(2f);             // gap between slices in dp (0–20)

PieData data = new PieData(set);
chart.setData(data);

chart.setUsePercentValues(true);   // show 40% instead of 40
chart.setCenterText("Platforms");
chart.setEntryLabelColor(Color.BLACK);
chart.invalidate();

Pie-specific options

chart.setDrawHoleEnabled(true);    // donut hole in the center (default true)
chart.setHoleRadius(50f);          // hole size as % of radius (default 50)
chart.setTransparentCircleRadius(55f);
chart.setDrawEntryLabels(true);    // slice labels (default true)
chart.setDrawCenterText(true);
chart.setCenterTextSize(18f);
chart.setMaxAngle(360f);           // 180 = half-pie (range 90–360)
chart.setRotationEnabled(true);    // let the user spin the pie by touch

Move value labels outside the slices with connector lines:

set.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
set.setXValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
set.setValueLineColor(Color.BLACK);

Tip

To render percentages instead of raw values, you must call both chart.setUsePercentValues(true) and supply a PercentFormatter to the dataset: set.setValueFormatter(new PercentFormatter(chart)). The first converts the geometry; the formatter appends the % sign.


7. Scatter, Bubble & Candlestick Charts

These three share the X/Y-axis chart base (so they support the same drag/zoom gestures and dual Y-axes as line and bar charts), but each expects a different entry shape.

Scatter Chart

Use case: correlation between two variables; plotting individual unconnected points.

Data shape: Entry(float x, float y).

ScatterChart chart = findViewById(R.id.chart);

List<Entry> entries = new ArrayList<>();
entries.add(new Entry(1f, 3.5f));
entries.add(new Entry(2f, 1.2f));
entries.add(new Entry(3f, 4.8f));

ScatterDataSet set = new ScatterDataSet(entries, "Samples");
set.setScatterShape(ScatterChart.ScatterShape.CIRCLE);
set.setScatterShapeSize(12f);
set.setColor(Color.MAGENTA);

chart.setData(new ScatterData(set));
chart.invalidate();

Available shapes (ScatterChart.ScatterShape): SQUARE, CIRCLE, TRIANGLE, CROSS, X, CHEVRON_UP, CHEVRON_DOWN.

Tip

CIRCLE and SQUARE render fastest; TRIANGLE is the slowest. For large scatter plots, prefer circles or squares.

Bubble Chart

Use case: three dimensions of data at once — X, Y, and a size that encodes a third value.

Data shape: BubbleEntry(float x, float y, float size). The area of the bubble (not its radius) represents the size value.

BubbleChart chart = findViewById(R.id.chart);

List<BubbleEntry> entries = new ArrayList<>();
entries.add(new BubbleEntry(1f, 20f, 8f));
entries.add(new BubbleEntry(2f, 30f, 14f));
entries.add(new BubbleEntry(3f, 15f, 5f));

BubbleDataSet set = new BubbleDataSet(entries, "Markets");
set.setColors(ColorTemplate.VORDIPLOM_COLORS);

chart.setData(new BubbleData(set));
chart.invalidate();

Candlestick Chart

Use case: financial OHLC (open-high-low-close) data — stock and currency charts.

Data shape: CandleEntry(float x, float high, float low, float open, float close).

CandleStickChart chart = findViewById(R.id.chart);

List<CandleEntry> entries = new ArrayList<>();
//                         x   high  low  open  close
entries.add(new CandleEntry(0f, 12f,  6f,  10f,  8f));
entries.add(new CandleEntry(1f, 15f,  9f,  9f,   14f));

CandleDataSet set = new CandleDataSet(entries, "AAPL");
set.setColor(Color.rgb(80, 80, 80));
set.setShadowColor(Color.DKGRAY);
set.setDecreasingColor(Color.RED);
set.setIncreasingColor(Color.GREEN);
set.setNeutralColor(Color.BLUE);

chart.setData(new CandleData(set));
chart.invalidate();

8. Radar & Combined Charts

Radar Chart

Use case: comparing several quantitative variables on one figure — skill ratings, product comparisons. Works best with 5–10 entries per dataset.

Data shape: RadarEntry(float value). Like pie entries, radar entries have no x-value; their position is the angular slot.

RadarChart chart = findViewById(R.id.chart);

List<RadarEntry> entries = new ArrayList<>();
entries.add(new RadarEntry(80f));
entries.add(new RadarEntry(60f));
entries.add(new RadarEntry(95f));
entries.add(new RadarEntry(40f));
entries.add(new RadarEntry(70f));

RadarDataSet set = new RadarDataSet(entries, "Player A");
set.setColor(Color.RED);
set.setFillColor(Color.RED);
set.setDrawFilled(true);

chart.setData(new RadarData(set));

// the "web" (spider net) styling:
chart.setWebColor(Color.LTGRAY);
chart.setWebLineWidth(1f);
chart.setWebColorInner(Color.LTGRAY);
chart.setWebAlpha(150);
chart.invalidate();

Combined Chart

Use case: overlaying multiple chart types in one plot — bars with a trend line, candles with a moving average.

Data shape: a CombinedData object that holds several typed data objects (LineData, BarData, ScatterData, CandleData, BubbleData).

CombinedChart chart = findViewById(R.id.chart);

CombinedData data = new CombinedData();
data.setData(myLineData);   // a LineData object
data.setData(myBarData);    // a BarData object

chart.setData(data);

// control which layer draws on top:
chart.setDrawOrder(new CombinedChart.DrawOrder[]{
    CombinedChart.DrawOrder.BAR,
    CombinedChart.DrawOrder.LINE   // line drawn on top of bars
});
chart.invalidate();

Available draw-order tokens: BAR, BUBBLE, LINE, CANDLE, SCATTER. Items earlier in the array are drawn further in the background.


9. Common Configuration (All Charts)

These settings are available on every chart (or every X/Y-axis chart). Configure them once and reuse the patterns across chart types.

Axes

X/Y-axis charts (line, bar, scatter, bubble, candlestick, combined) expose three axis objects. Pie and radar charts do not use X/Y axes (a PieChart.getXAxis() call throws an exception by design).

XAxis xAxis = chart.getXAxis();
YAxis leftAxis = chart.getAxisLeft();
YAxis rightAxis = chart.getAxisRight();

X-axis:

xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);  // TOP, BOTTOM, BOTH_SIDED, TOP_INSIDE, BOTTOM_INSIDE
xAxis.setGranularity(1f);            // minimum interval between labels
xAxis.setLabelCount(6, false);       // desired number of labels
xAxis.setLabelRotationAngle(45f);
xAxis.setDrawGridLines(true);
xAxis.setValueFormatter(new IndexAxisValueFormatter(new String[]{"Jan","Feb","Mar"}));

Y-axis:

leftAxis.setAxisMinimum(0f);         // pin the bottom of the scale
leftAxis.setAxisMaximum(100f);
leftAxis.setGranularity(10f);
leftAxis.setInverted(false);         // flip the axis direction
rightAxis.setEnabled(false);         // hide the right axis (very common)

Assign a dataset to a specific Y-axis with dataSet.setAxisDependency(YAxis.AxisDependency.RIGHT).

Tip

To show text labels (month names, categories) on the x-axis instead of numbers, use IndexAxisValueFormatter with xAxis.setGranularity(1f). Don't try to put strings into entries — entries are always numeric (x, y) pairs; the formatter maps numbers to labels at draw time.

Limit lines

Draw threshold lines across the chart (a goal value, a safety limit):

LimitLine ll = new LimitLine(75f, "Target");
ll.setLineWidth(2f);
ll.setLineColor(Color.RED);
ll.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_TOP);
ll.enableDashedLine(10f, 10f, 0f);
leftAxis.addLimitLine(ll);

Legend

Legend legend = chart.getLegend();
legend.setEnabled(true);
legend.setForm(Legend.LegendForm.CIRCLE);            // NONE, EMPTY, DEFAULT, SQUARE, CIRCLE, LINE
legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);
legend.setTextSize(12f);
legend.setWordWrapEnabled(true);

The legend is generated automatically from your DataSet labels and colors. The label you pass to each DataSet constructor is what appears here.

Description

The small caption in the bottom-right corner:

chart.getDescription().setText("Q1 2025 Performance");
chart.getDescription().setTextSize(12f);
// or hide it:
chart.getDescription().setEnabled(false);

Value formatting and global value styling

chart.getData().setValueTextSize(11f);
chart.getData().setValueTextColor(Color.BLACK);
chart.getData().setDrawValues(true);
chart.getData().setValueFormatter(new LargeValueFormatter());  // 1.2k, 3.4m, ...

Built-in formatters include LargeValueFormatter, PercentFormatter, IndexAxisValueFormatter, and StackedValueFormatter. Implement IValueFormatter or IAxisValueFormatter for custom formatting.

"No data" placeholder

chart.setNoDataText("No data available yet.");
chart.setNoDataTextColor(Color.GRAY);

10. Interaction: Gestures, Highlighting & Markers

Touch gestures (X/Y-axis charts)

chart.setTouchEnabled(true);       // master switch for all gestures
chart.setDragEnabled(true);        // pan with one finger
chart.setScaleEnabled(true);       // zoom with pinch
chart.setPinchZoom(true);          // pinch zooms both axes together
chart.setDoubleTapToZoomEnabled(true);
chart.setDragDecelerationEnabled(true);    // inertia after fling
chart.setDragDecelerationFrictionCoef(0.9f);

Programmatic zoom and navigation:

chart.zoomIn();
chart.zoomOut();
chart.fitScreen();                            // reset zoom/pan
chart.setVisibleXRangeMaximum(10f);           // show at most 10 x-units at once
chart.moveViewToX(20f);                        // scroll so x=20 is at the left edge

Pie and radar charts use rotation instead of pan/zoom:

pieOrRadarChart.setRotationEnabled(true);

Highlighting and selection callbacks

Listen for taps on data points:

chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
    @Override
    public void onValueSelected(Entry e, Highlight h) {
        Log.d("Chart", "Selected y=" + e.getY() + " at x=" + e.getX());
    }
    @Override
    public void onNothingSelected() { }
});

Highlight a value programmatically:

chart.highlightValue(2f, 0);   // x-value 2 in dataset index 0
chart.highlightValue(null);    // clear all highlights

Disable tap-to-highlight per dataset with dataSet.setHighlightEnabled(false), or globally with chart.setHighlightPerTapEnabled(false).

Marker views (tooltips)

A MarkerView is a custom popup shown over the selected value. Provide a layout and subclass MarkerView:

public class MyMarker extends MarkerView {
    private final TextView tv;
    public MyMarker(Context context, int layoutResource) {
        super(context, layoutResource);
        tv = findViewById(R.id.tvContent);
    }
    @Override
    public void refreshContent(Entry e, Highlight highlight) {
        tv.setText("Value: " + e.getY());
        super.refreshContent(e, highlight);
    }
}
MyMarker marker = new MyMarker(this, R.layout.custom_marker);
marker.setChartView(chart);
chart.setMarker(marker);

11. Animations

Animate the chart's appearance. Animations require API 11+ (always available at this library's minSdk of 14).

chart.animateX(1000);                       // sweep in along x over 1000 ms
chart.animateY(1000);                       // grow along y
chart.animateXY(1000, 1000);                // both axes
chart.animateY(1500, Easing.EaseInOutQuad); // with an easing curve

The Easing class provides over 30 predefined functions, including: Linear, EaseInQuad, EaseOutQuad, EaseInOutQuad, EaseInCubic, EaseInOutCubic, EaseInQuart, EaseInSine, EaseInExpo, EaseInCirc, EaseInElastic, EaseInBack, EaseInBounce, EaseOutBounce, EaseInOutBounce, and their In/Out/InOut variants.

Note

When you call an animate*() method, you do not need to call invalidate() — the animation drives the redraw itself.

Pie and radar charts can also spin:

pieChart.spin(2000, 0f, 360f, Easing.EaseInOutCubic);

12. Saving a Chart as an Image

Export the rendered chart to the device gallery or a file:

boolean saved = chart.saveToGallery("my_chart", 90);   // filename, JPEG quality 0–100

Or save to a specific path on external storage:

chart.saveToPath("my_chart", "/charts");

Caution

Saving requires the WRITE_EXTERNAL_STORAGE permission. Declare it in your manifest and, on Android 6.0+ (API 23+), request it at runtime before calling saveToGallery():

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

You can also grab the chart as a Bitmap for your own handling:

Bitmap bmp = chart.getChartBitmap();

13. Troubleshooting

Error: Failed to resolve: com.github.PhilJay:MPAndroidChart:v3.1.0

Cause: The JitPack repository is not declared, or the version string is wrong. This is the most-reported issue in the project's tracker.

Solution:

  1. Add maven { url 'https://jitpack.io' } to your repositories (in build.gradle or settings.gradle, depending on your project layout — see Installation).
  2. Confirm the version is exactly v3.1.0 (with the leading v).
  3. Sync Gradle again.

Prevention: Always add the JitPack repo when pulling any com.github.* dependency.

Error: Gradle fails to download MPAndroidChart with 401 (or a transient build/database error)

Cause: JitPack builds artifacts on first request. A 401 or "establishing a database connection" message is usually a transient JitPack-side condition while it builds or caches the artifact.

Solution: Wait a minute and re-sync. If it persists, clear the Gradle cache (./gradlew --refresh-dependencies) and retry.

Prevention: Pin a released version tag (v3.1.0) rather than a commit hash or -SNAPSHOT, so JitPack serves a cached build.

Error: BarChartView must extend android.view.View (class inflation error in XML)

Cause: The chart's class name in your layout XML is misspelled or not fully qualified.

Solution: Use the exact, fully-qualified class path. For a bar chart that is:

<com.github.mikephil.charting.charts.BarChart ... />

Check the chart class table for the correct path of each chart type.

Prevention: Copy class names from this guide rather than typing them.

Error: Dashed lines do not appear

Cause: Dashed line effects (enableDashedLine) are not honored while hardware acceleration is enabled, which it is by default.

Solution: Disable hardware acceleration for the chart:

chart.setHardwareAccelerationEnabled(false);

Prevention: Be aware this reduces rendering performance; only disable it when dashes are essential.

Error: Bars are clipped at the left/right edges

Cause: The x-axis range exactly matches the first and last bar centers, so half of each edge bar falls outside the content area.

Solution: Call chart.setFitBars(true) to pad the axis by half a bar width.

Prevention: Always set setFitBars(true) for simple (non-grouped) bar charts.

Error: Large or high-precision values render incorrectly

Cause: MPAndroidChart stores all values as 32-bit float. Very large numbers, or values needing many significant digits (currency in cents, timestamps in milliseconds), lose precision.

Solution: Scale your data into a friendly range before plotting (e.g. divide milliseconds to seconds, or amounts to thousands) and use a ValueFormatter to display the real magnitude. The library does not support double or BigDecimal entries.

Prevention: Normalize large datasets to a reasonable numeric range up front.

Problem: Chart is laggy or runs out of memory with many points

Cause: Drawing tens of thousands of points, value labels, bar shadows, or markers every frame is expensive.

Solution:

  • chart.setVisibleXRangeMaximum(n) to render a window of points rather than all at once.
  • dataSet.setDrawValues(false) to skip per-point value text.
  • Avoid setDrawBarShadow(true) on large bar datasets.
  • chart.setUnbindEnabled(true) helps release drawables when the view detaches.
  • Call chart.clear() when you no longer need the data.

Prevention: For real-time or very large datasets, keep only a visible window of data on screen.


14. FAQ

Q: Does MPAndroidChart support Jetpack Compose? There is no native Compose API in this version. Embed any chart in Compose with an AndroidView wrapper:

AndroidView(factory = { context -> LineChart(context).apply { /* configure */ } })

Q: How do I show month names or categories on the X-axis? Use IndexAxisValueFormatter with your label array and set xAxis.setGranularity(1f). Entries themselves are always numeric — the formatter maps the numeric x-values to your text labels.

Q: How do I add data points dynamically (e.g. live data)? Add an entry to the data object, then notify and refresh:

data.addEntry(new Entry(x, y), 0);  // dataset index 0
data.notifyDataChanged();
chart.notifyDataSetChanged();
chart.invalidate();

Q: Why does my pie chart only show one dataset? A PieChart displays exactly one PieDataSet — that's a deliberate constraint of the chart type. Use multiple slices within the single dataset.

Q: How do I use a second (right) Y-axis? Enable chart.getAxisRight() and assign datasets to it with dataSet.setAxisDependency(YAxis.AxisDependency.RIGHT). Each axis scales independently.

Q: Can I show values as percentages? Yes, for pie charts: call chart.setUsePercentValues(true) and set a PercentFormatter on the dataset.

Q: Is there an iOS equivalent? Yes — the sibling library Charts (by Daniel Gindi) mirrors this API in Swift/Objective-C.

Q: How do I disable the description text and right axis (the most common "clean" setup)?

chart.getDescription().setEnabled(false);
chart.getAxisRight().setEnabled(false);

Q: Where can I find the full API documentation? The project links to the official documentation site and to generated Javadocs for each release; this guide covers the practical surface of version 3.1.0.


15. Quick Reference

Per-chart cheat sheet

Chart View class Entry constructor DataSet
Line LineChart Entry(x, y) LineDataSet
Bar BarChart BarEntry(x, y) / BarEntry(x, float[]) BarDataSet
Horizontal bar HorizontalBarChart BarEntry(x, y) BarDataSet
Pie PieChart PieEntry(value, label) PieDataSet
Scatter ScatterChart Entry(x, y) ScatterDataSet
Bubble BubbleChart BubbleEntry(x, y, size) BubbleDataSet
Candlestick CandleStickChart CandleEntry(x, high, low, open, close) CandleDataSet
Radar RadarChart RadarEntry(value) RadarDataSet
Combined CombinedChart mixed CombinedData

Most-used methods

Goal Call
Render / refresh chart.setData(data); chart.invalidate();
Animate chart.animateY(1000)
Hide right axis chart.getAxisRight().setEnabled(false)
Hide description chart.getDescription().setEnabled(false)
Single line color dataSet.setColor(Color.BLUE)
Palette dataSet.setColors(ColorTemplate.MATERIAL_COLORS)
Hide value labels dataSet.setDrawValues(false)
Set Y range chart.getAxisLeft().setAxisMinimum(0f)
Limit visible points chart.setVisibleXRangeMaximum(10f)
Selection callback chart.setOnChartValueSelectedListener(...)
Save image chart.saveToGallery("name", 90)

Enums at a glance

Enum Values
LineDataSet.Mode LINEAR, STEPPED, CUBIC_BEZIER, HORIZONTAL_BEZIER
ScatterChart.ScatterShape SQUARE, CIRCLE, TRIANGLE, CROSS, X, CHEVRON_UP, CHEVRON_DOWN
XAxis.XAxisPosition TOP, BOTTOM, BOTH_SIDED, TOP_INSIDE, BOTTOM_INSIDE
YAxis.AxisDependency LEFT, RIGHT
Legend.LegendForm NONE, EMPTY, DEFAULT, SQUARE, CIRCLE, LINE
PieDataSet.ValuePosition INSIDE_SLICE, OUTSIDE_SLICE
CombinedChart.DrawOrder BAR, BUBBLE, LINE, CANDLE, SCATTER