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 aTextVieworButtonwould. There is no separate canvas or web component to manage.
Table of Contents
- Quick Start
- Installation
- The Core Workflow
- Line Chart
- Bar Chart & Horizontal Bar Chart
- Pie Chart
- Scatter, Bubble & Candlestick Charts
- Radar & Combined Charts
- Common Configuration (All Charts)
- Interaction: Gestures, Highlighting & Markers
- Animations
- Saving a Chart as an Image
- Troubleshooting
- FAQ
- 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 callanimateX()/animateY()instead, you don't needinvalidate()— 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 leadingv. The single most common setup error isFailed 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=trueingradle.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
ChartDataconstructors accept either a single DataSet or a list:new LineData(setA, setB). Pie charts are the exception — aPieChartdisplays exactly onePieDataSet.
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 — callchart.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 callsnotifyDataSetChanged()for you. Set your data on the chart before calling it, and ensuregroupSpace + 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 aPercentFormatterto 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
CIRCLEandSQUARErender fastest;TRIANGLEis 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
IndexAxisValueFormatterwithxAxis.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 callinvalidate()— 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_STORAGEpermission. Declare it in your manifest and, on Android 6.0+ (API 23+), request it at runtime before callingsaveToGallery():<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:
- Add
maven { url 'https://jitpack.io' }to your repositories (inbuild.gradleorsettings.gradle, depending on your project layout — see Installation). - Confirm the version is exactly
v3.1.0(with the leadingv). - 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 |