# MPAndroidChart User Guide

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 `View`s, 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](#9-common-configuration-all-charts) 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](#1-quick-start)
2. [Installation](#2-installation)
3. [The Core Workflow](#3-the-core-workflow)
4. [Line Chart](#4-line-chart)
5. [Bar Chart & Horizontal Bar Chart](#5-bar-chart--horizontal-bar-chart)
6. [Pie Chart](#6-pie-chart)
7. [Scatter, Bubble & Candlestick Charts](#7-scatter-bubble--candlestick-charts)
8. [Radar & Combined Charts](#8-radar--combined-charts)
9. [Common Configuration (All Charts)](#9-common-configuration-all-charts)
10. [Interaction: Gestures, Highlighting & Markers](#10-interaction-gestures-highlighting--markers)
11. [Animations](#11-animations)
12. [Saving a Chart as an Image](#12-saving-a-chart-as-an-image)
13. [Troubleshooting](#13-troubleshooting)
14. [FAQ](#14-faq)
15. [Quick Reference](#15-quick-reference)

---

## 1. Quick Start

Get a line chart on screen in three steps.

**Step 1 — Add the dependency** (see [Installation](#2-installation) for full details):

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

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

```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`):

```java
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`:

```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:

```gradle
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)"

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

=== "Gradle (Kotlin DSL)"

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

=== "Maven"

    ```xml
    <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](#13-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 |

```text
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

```java
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:

```java
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:

```java
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

```java
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](#error-dashed-lines-do-not-appear).

### Multiple lines

```java
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

```java
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:

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

### Bar-specific options

```java
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:

```java
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)

```java
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

```java
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

```java
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:

```java
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)`.

```java
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.

```java
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)`.

```java
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.

```java
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`).

```java
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).

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

**X-axis:**

```java
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:**

```java
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):

```java
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

```java
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:

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

### Value formatting and global value styling

```java
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

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

---

## 10. Interaction: Gestures, Highlighting & Markers

### Touch gestures (X/Y-axis charts)

```java
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:

```java
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:

```java
pieOrRadarChart.setRotationEnabled(true);
```

### Highlighting and selection callbacks

Listen for taps on data points:

```java
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:

```java
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`:

```java
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);
    }
}
```

```java
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).

```java
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:

```java
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:

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

Or save to a specific path on external storage:

```java
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()`:
> ```xml
> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
> ```

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

```java
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-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:
```xml
<com.github.mikephil.charting.charts.BarChart ... />
```
Check the [chart class table](#3-the-core-workflow) 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:
```java
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:
```kotlin
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:
```java
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](https://github.com/danielgindi/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)?**
```java
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` |

---

_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. Unofficial; not affiliated with or reviewed by the project._
