Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

MPAndroidChart Admin & Developer 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.

This guide is the architectural and operational reference for MPAndroidChart — for developers integrating it deeply, architects evaluating it, and contributors extending it. It covers the internal design, the rendering pipeline, the coordinate-transform system, extension points, performance characteristics, security considerations, and the contribution workflow.

For day-to-day usage (drawing each chart type, configuring axes, handling gestures), see the companion User Guide.


Table of Contents

  1. Executive Summary
  2. Architecture Overview
  3. Requirements & Build Configuration
  4. Repository Structure
  5. The Rendering Pipeline
  6. The Coordinate-Transform System
  7. Class Hierarchies (Module Reference)
  8. Extension Points
  9. Performance Engineering
  10. Security Analysis
  11. Testing Strategy
  12. Integration & Deployment
  13. Contributing
  14. Known Limitations & Improvement Opportunities
  15. Quick Reference

1. Executive Summary

MPAndroidChart is a self-contained Android charting library that renders charts directly onto a Canvas using the Android 2D graphics API. It ships nine chart types (line, bar, horizontal bar, pie, scatter, bubble, candlestick, radar, combined) as View subclasses that integrate into standard Android layouts.

Attribute Value
Library version 3.1.0
Group / artifact com.github.philjay / MPAndroidChart (consumed via JitPack as com.github.PhilJay:MPAndroidChart:v3.1.0)
Language Java
Min SDK / Target SDK 14 / 28
Compile SDK 28
Runtime dependencies androidx.annotation:annotation only
Test dependencies junit:junit:4.12
License Apache License 2.0
Build system Gradle (Android Gradle Plugin 7.0.4)
Distribution JitPack (source-built AAR)

Architectural essence: the library cleanly separates four concerns — data (what to draw), chart views (the public API and lifecycle), renderers (how to paint it), and coordinate transforms (where pixels go). This separation is what allows the same gesture, animation, and axis machinery to serve every chart type, and it is the seam along which the library is extended.

Note

There is no networking, persistence, reflection, or dynamic code loading anywhere in the library. It is a pure, offline rendering component. This sharply narrows its security and dependency surface (see Security Analysis).


2. Architecture Overview

The library is built around a Model–View–Renderer decomposition, with a dedicated coordinate-transform layer underneath.

                         ┌─────────────────────────────────────────────┐
                         │            Chart (extends ViewGroup)         │
   YOUR DATA             │   public API · lifecycle · onDraw() · touch  │
  ┌──────────┐  setData  │                                              │
  │ ChartData │ ────────►│  ┌────────────┐   ┌──────────────────────┐   │
  │  ▲        │          │  │ Animator   │   │ ChartTouchListener   │   │
  │  │ holds  │          │  │ (Easing)   │   │ (drag/zoom/highlight)│   │
  │ DataSet[] │          │  └────────────┘   └──────────────────────┘   │
  │  ▲        │          │         │ onDraw() orchestrates:             │
  │  │ holds  │          │         ▼                                    │
  │ Entry[]   │          │  ┌────────────┐  ┌────────────┐  ┌────────┐  │
  └──────────┘          │  │DataRenderer│  │AxisRenderer│  │Legend  │  │
                         │  └─────┬──────┘  └─────┬──────┘  │Renderer│  │
                         │        │               │         └────────┘  │
                         │        ▼               ▼                     │
                         │   ┌─────────────────────────────────────┐   │
                         │   │ Transformer  +  ViewPortHandler      │   │
                         │   │ (value↔pixel matrices, zoom/pan)     │   │
                         │   └─────────────────────────────────────┘   │
                         │                    │                         │
                         │                    ▼                         │
                         │              Android Canvas                  │
                         └─────────────────────────────────────────────┘

The four layers

Layer Responsibility Key classes
Data model Holds values and per-series styling; computes min/max. ChartData, BaseDataSet/DataSet, Entry/BaseEntry
Chart views Public API, Android View lifecycle, dispatching draw, handling touch. Chart, BarLineChartBase, PieRadarChartBase, the 9 concrete charts
Renderers Paint data, axes, legend, grid, limit lines, markers onto the Canvas. DataRenderer (+ subclasses), AxisRenderer, LegendRenderer
Transform Convert data values to screen pixels and back; manage zoom/pan state. Transformer, ViewPortHandler

Two parallel chart families

The chart hierarchy splits early into two families with fundamentally different geometry:

  • Cartesian charts (BarLineChartBase): line, bar, horizontal bar, scatter, bubble, candlestick, combined. They have X and dual Y axes, support drag/pinch-zoom, and use Transformer matrices.
  • Radial charts (PieRadarChartBase): pie and radar. They have a center, a rotation angle, and angular/distance math instead of axis transforms.

This bifurcation is the single most important fact for understanding why some features (zoom, dual axes) exist only on some charts.


3. Requirements & Build Configuration

Library module (MPChartLib/build.gradle)

apply plugin: 'com.android.library'
group = 'com.github.philjay'

android {
    compileSdkVersion 28
    buildToolsVersion '28.0.3'
    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 28
        versionCode 3
        versionName '3.1.0'
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    testOptions {
        unitTests.returnDefaultValues = true   // allows JVM unit tests without mocking Android
    }
}

dependencies {
    implementation 'androidx.annotation:annotation:1.0.0'
    testImplementation 'junit:junit:4.12'
}

The build also defines sourcesJar, javadoc, and javadocJar tasks, publishing sources and Javadoc alongside the AAR — which is how JitPack serves the -sources and -javadoc artifacts.

Project requirements (gradle.properties)

android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx2048M

Important

The library is AndroidX-based. Consuming projects must have android.useAndroidX=true. The proguard-rules.pro file ships empty — the library has no special keep-rules, because it uses no reflection. Standard R8/ProGuard shrinking is safe without custom configuration.


4. Repository Structure

MPAndroidChart/
├── MPChartLib/                        # the published library module
│   └── src/main/java/com/github/mikephil/charting/
│       ├── charts/        (12 files)  # public View classes + 2 base classes
│       ├── data/          (29 files)  # ChartData, DataSet, Entry families
│       ├── components/    (11 files)  # XAxis, YAxis, Legend, LimitLine, Description, MarkerView
│       ├── interfaces/                # data-provider + dataset interfaces (decoupling)
│       │   ├── dataprovider/ (8)
│       │   └── datasets/     (11)
│       ├── renderer/      (22 + 8)    # all painting logic (+ scatter shape renderers)
│       ├── highlight/     (10 files)  # touch-to-value hit testing
│       ├── formatter/     (11 files)  # value & axis label formatting
│       ├── listener/      (7 files)   # touch & gesture listeners
│       ├── animation/     (2 files)   # ChartAnimator, Easing
│       ├── jobs/          (6 files)   # pooled viewport-animation jobs
│       ├── buffer/        (3 files)   # reusable draw buffers
│       ├── utils/         (13 files)  # transforms, pools, color templates, geometry
│       ├── matrix/, model/, exception/
│       └── (test) src/test/...        # 7 JUnit test classes
├── MPChartExample/                    # demo app (not published) — 30+ example activities
├── design/, screenshots/              # marketing assets
├── README.md, CONTRIBUTING.md, LICENSE
└── build.gradle, settings.gradle, gradle/

The MPChartExample app is the de-facto integration test and living documentation: each activity (e.g. LineChartActivity1, PieChartActivity, CombinedChartActivity) demonstrates one chart type with sliders that mutate the data live.


5. The Rendering Pipeline

All drawing happens inside the chart's overridden onDraw(Canvas). The base Chart.onDraw() handles the empty-data placeholder and one-time offset calculation; each family then orchestrates its renderers in a fixed order.

Cartesian render order (BarLineChartBase.onDraw)

  1. drawGridBackground() — optional grey backdrop + borders.
  2. Auto-scale Y axis if setAutoScaleMinMaxEnabled(true).
  3. Compute axis intervals (AxisRenderer.computeAxis) for X, left Y, right Y.
  4. Render axis lines, then grid lines (order depends on setDrawGridLinesBehindData).
  5. Render limit lines behind data (if configured).
  6. Clip to content rect (unless disabled) and mRenderer.drawData(canvas) — the actual series.
  7. Draw highlighted values (drawHighlighted) if anything is selected.
  8. drawExtras(), then limit lines on top, then axis labels.
  9. drawValues() — per-point value text.
  10. LegendRenderer.renderLegend(), then description, then markers.

Note

The library tracks per-frame draw time when setLogEnabled(true) is set, logging average draw time and cycle count. This is the built-in profiling hook for diagnosing slow charts.

Renderer class family

Renderer (base, holds ViewPortHandler)
├── DataRenderer (abstract: drawData/drawValues/drawHighlighted/drawExtras + paints)
│   ├── LineRadarRenderer ──► LineChartRenderer, RadarChartRenderer
│   ├── BarLineScatterCandleBubbleRenderer
│   │     ├── BarChartRenderer ──► HorizontalBarChartRenderer
│   │     ├── ScatterChartRenderer, CandleStickChartRenderer, BubbleChartRenderer
│   ├── PieChartRenderer
│   └── CombinedChartRenderer (delegates to a list of sub-renderers)
├── AxisRenderer ──► XAxisRenderer, YAxisRenderer (+ HorizontalBarChart / RadarChart variants)
└── LegendRenderer

Scatter shapes are themselves pluggable: IShapeRenderer has implementations CircleShapeRenderer, SquareShapeRenderer, TriangleShapeRenderer, CrossShapeRenderer, XShapeRenderer, ChevronUpShapeRenderer, ChevronDownShapeRenderer. You can supply your own via ScatterDataSet.setShapeRenderer().


6. The Coordinate-Transform System

The most architecturally significant subsystem. Two cooperating classes convert between data space (your Entry x/y values) and pixel space (screen coordinates), and manage zoom/pan.

ViewPortHandler

Owns a Matrix (mMatrixTouch) representing the current zoom and translation, plus the content rectangle (the drawable area inside the axis margins). It enforces zoom/scroll limits.

Concern Methods
Dimensions setChartDimens(), restrainViewPort()
Zoom zoomIn/Out, zoom, setZoom, fitScreen, resetZoom
Limits setMinimumScaleX/Y, setMaximumScaleX/Y, setMinMaxScaleX/Y
Translate translate, centerViewPort, limitTransAndScale
Drag bounds setDragOffsetX/Y

Transformer

Holds two matrices — mMatrixValueToPx (data→pixels) and mMatrixOffset (applies the content offset) — combined with the ViewPortHandler's touch matrix. This is what chart.getPixelForValues() and chart.getValuesByTouchPoint() use.

data value (x, y)
   │  mMatrixValueToPx     (scale to content size, flip Y)
   ▼
   │  ViewPortHandler.mMatrixTouch   (apply user zoom + pan)
   ▼
   │  mMatrixOffset        (shift into the content rect)
   ▼
screen pixel

Cartesian charts keep two transformers — mLeftAxisTransformer and mRightAxisTransformer — so the left and right Y axes can have independent scales. HorizontalBarChart swaps in a TransformerHorizontalBarChart and HorizontalViewPortHandler to achieve the 90° rotation without changing any data code.

Tip

When debugging "my point is in the wrong place," the issue is almost always in the transform chain: check which AxisDependency the dataset uses, and whether the axis min/max were set manually (which fixes the value-to-pixel scale).


7. Class Hierarchies (Module Reference)

Chart views

View → ViewGroup → Chart<T extends ChartData>  (implements ChartInterface)
   ├── BarLineChartBase<T>  (implements BarLineScatterCandleBubbleDataProvider)
   │     ├── LineChart, BarChart → HorizontalBarChart
   │     ├── ScatterChart, BubbleChart, CandleStickChart
   │     └── CombinedChart
   └── PieRadarChartBase<T>
         ├── PieChart
         └── RadarChart

Chart provides the cross-cutting API: setData, invalidate, highlighting, markers, animation, description/legend access, image export, and offset management. BarLineChartBase adds axes, zoom/pan, and viewport jobs. PieRadarChartBase adds rotation and angular geometry.

Data model

BaseEntry (y, data, icon)
   └── Entry (adds x)  → BarEntry, BubbleEntry, CandleEntry, PieEntry, RadarEntry

IDataSet → BaseDataSet → DataSet
   └── LineScatterCandleRadarDataSet → LineRadarDataSet → LineDataSet / RadarDataSet
   └── BarLineScatterCandleBubbleDataSet → BarDataSet, ScatterDataSet, CandleDataSet, BubbleDataSet
   └── PieDataSet

ChartData → BarLineScatterCandleBubbleData → {Bar,Line,Scatter,Candle,Bubble}Data
         └── PieData, RadarData, CombinedData

Note

Charts depend on interfaces (ILineDataSet, LineDataProvider, etc.), not concrete classes. This interfaces/dataprovider + interfaces/datasets indirection is what lets CombinedChart reuse the line/bar/scatter renderers, and lets you substitute custom dataset implementations.

Supporting subsystems

Subsystem Classes Purpose
Highlighting ChartHighlighter + per-type (Bar, Pie, Radar, Combined, …), Highlight, Range Map a touch point to the nearest entry.
Touch ChartTouchListener → BarLineChartTouchListener, PieRadarChartTouchListener Gesture state machines.
Animation ChartAnimator, Easing (30+ EasingFunctions) Phase-based value animation.
Viewport jobs ViewPortJob → MoveViewJob, ZoomJob, AnimatedMoveViewJob, AnimatedZoomJob Deferred/animated viewport changes, object-pooled.
Formatters IValueFormatter/IAxisValueFormatter + LargeValueFormatter, PercentFormatter, IndexAxisValueFormatter, StackedValueFormatter Label text generation.
Utilities ColorTemplate, Fill, MPPointF, MPPointD, ObjectPool, Utils, FSize, EntryXComparator Colors, pooled geometry, dp conversion.

8. Extension Points

The library is designed to be extended without forking. The principal seams:

To customize… Override / supply Set via
How a series is painted A DataRenderer subclass chart.setRenderer(...)
Axis painting XAxisRenderer / YAxisRenderer subclass chart.setXAxisRenderer(...), setRendererLeftYAxis(...)
Scatter point shape IShapeRenderer implementation scatterDataSet.setShapeRenderer(...)
Value / axis label text IValueFormatter / IAxisValueFormatter dataSet.setValueFormatter(...), axis.setValueFormatter(...)
Fill position under a line IFillFormatter lineDataSet.setFillFormatter(...)
Hit-testing logic IHighlighter implementation chart.setHighlighter(...)
Tooltip content/layout MarkerView subclass (or raw IMarker) chart.setMarker(...)
A custom dataset backing store implement I*DataSet pass to the matching *Data

This interface-first design (every collaborator is referenced through an interface) is the architectural property that makes the library so extensible despite being a closed AAR.


9. Performance Engineering

Charting redraws the entire view every frame during gestures, so the library invests heavily in allocation avoidance.

  • Reusable draw buffers (buffer/AbstractBuffer and subclasses): the bar/line renderers pre-fill a flat float[] of x,y,x,y,… coordinates and replace rather than recreate it each frame. The class comment is explicit: "Concept: Replace instead of recreate … This needs to run FAST."
  • Object pooling (utils/ObjectPool, MPPointF, MPPointD): geometry points are borrowed from pools (MPPointF.getInstance(...)) and returned (MPPointF.recycleInstance(...)), keeping per-frame allocation near zero to avoid GC pauses.
  • Viewport clipping: data is clipped to the content rect (setClipDataToContent, default on) so off-screen geometry isn't painted.
  • Visible-range windowing: setVisibleXRangeMaximum() + moveViewToX() let large datasets render only a slice.
  • Value-label suppression: mMaxVisibleCount (default 100) automatically stops drawing value labels when too many entries are visible.

Performance trade-offs to document for operators

Setting Cost
setDrawBarShadow(true) ~50% slower bar rendering
enableDashedLine(...) Requires hardware acceleration off (slower overall)
TRIANGLE scatter shape Slowest shape; prefer CIRCLE/SQUARE
Drawing value labels Per-point text layout each frame; disable for dense data
setHardwareAccelerationEnabled(false) Needed for some effects, but disables GPU compositing

Warning

All values are stored as 32-bit float. For large magnitudes or high precision (currency, epoch-millis), precision is lost. Normalize/scale data into a friendly range and use a formatter to display real magnitudes. There is no double/BigDecimal path.


10. Security Analysis

MPAndroidChart has an exceptionally small attack surface for an Android library.

Concern Finding
Network access None. No HTTP, sockets, or URL usage in the library.
Reflection / dynamic loading None. Hence the empty ProGuard rules — safe to shrink/obfuscate.
Permissions required None for rendering. Only saveToGallery()/saveToPath() need WRITE_EXTERNAL_STORAGE.
File system writes Only via the explicit image-export methods, into external storage.
Untrusted input Charts render numeric data only; there is no parser/eval path to exploit.
Dependencies One runtime dep (androidx.annotation) — minimal supply-chain exposure.

Hardening guidance

  • Storage permission: saveToGallery() writes to Environment.getExternalStorageDirectory() using the legacy storage model. On Android 10+ (scoped storage), this path is restricted; if you export images, prefer capturing getChartBitmap() and writing through MediaStore/Storage Access Framework yourself, and request the runtime permission on API 23+.
  • No data leaves the device through this library — any analytics/telemetry would be in your own code, not here.
  • Obfuscation is fully supported; do not add reflective keep-rules (none are needed).

Important

The only OS-version-sensitive code path is image export (legacy external-storage API). Treat it as the single integration point requiring permission handling and scoped-storage awareness on modern Android.


11. Testing Strategy

The library ships 7 JVM JUnit 4 tests under MPChartLib/src/test/:

Test Covers
ApproximatorTest Data reduction / Douglas-Peucker approximation.
AxisRendererTest Axis interval computation.
BarDataTest Bar data min/max and grouping math.
ChartDataTest Multi-dataset aggregation, min/max across sets.
DataSetTest Entry insertion/ordering, binary search by x.
LargeValueFormatterTest 1.2k/3.4m formatting.
ObjectPoolTest Pool borrow/recycle correctness.

Tests run on the JVM (no instrumented device) thanks to testOptions.unitTests.returnDefaultValues = true, which stubs Android framework calls. Coverage is concentrated on pure-logic components (data math, formatters, pools); rendering and gesture code is validated manually through the example app.

Note

The contribution guidelines require testing changes by actually running the example app (or adding a new example activity), reflecting the reality that visual/gesture behavior is not unit-testable here.


12. Integration & Deployment

Consuming the library

The library is not on Maven Central; JitPack builds the AAR from the tagged source on first request. Consumers must add the JitPack repository (see User Guide → Installation). Pinning a release tag (v3.1.0) ensures a cached, reproducible build rather than a freshly compiled -SNAPSHOT.

Embedding a chart

A chart is a plain View. Two integration modes:

XML layout

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

Programmatic

LineChart chart = new LineChart(context);
container.addView(chart);

Jetpack Compose

AndroidView(factory = { ctx -> LineChart(ctx) }, update = { it.data = lineData; it.invalidate() })

Lifecycle considerations

  • Charts hold bitmaps in some renderers; LineChart/PieChart release them in onDetachedFromWindow().
  • For memory-tight screens, enable chart.setUnbindEnabled(true) to unbind drawables on detach, and call chart.clear() when discarding data.
  • setKeepPositionOnRotation(true) preserves zoom/scroll across configuration changes.

13. Contributing

The project accepts community PRs under a defined workflow (CONTRIBUTING.md):

  • [ ] Search existing issues and PRs before starting.
  • [ ] Fork; branch from master, named for the change.
  • [ ] Make commits of logical units; conform to the surrounding code style.
  • [ ] Commit titles ≤ 50 characters; body after a blank line for non-obvious changes.
  • [ ] Test by running the example app, or add a new example activity demonstrating the change.
  • [ ] Open a PR following the auto-generated template.

Issue templates exist for bugs and feature requests — the maintainers ask that "how do I…" questions go to Stack Overflow (mpandroidchart tag), not the issue tracker.

Note

The repository also documents that this is the Android library; the iOS sibling is danielgindi/Charts, which mirrors the same architecture in Swift.


14. Known Limitations & Improvement Opportunities

Derived from the source and the community issue tracker:

  • float-only precision. No double/BigDecimal support. Repeatedly reported (huge values rendering wrong, lost precision in CandleEntry, requests for BigDecimal in BarEntry). The fix would be invasive — the entire data model and transform matrices are float-based.
  • No Jetpack Compose API. Compose users must wrap charts in AndroidView. A first-class Compose surface is a long-standing feature request.
  • Legacy external-storage image export. saveToGallery() predates scoped storage; modernizing it to MediaStore would remove the WRITE_EXTERNAL_STORAGE requirement on API 29+.
  • Accessibility gaps. TalkBack/screen-reader support for selecting individual bars/slices is limited — a noted issue for a11y-sensitive apps.
  • Targets API 28. compileSdkVersion/targetSdkVersion 28 predate current Play Store target-API requirements; consuming apps set their own target SDK, but the library's own modernization (AGP, SDK levels) lags.
  • Dashed lines vs. hardware acceleration. The requirement to disable HW acceleration for dashes is a usability sharp edge inherent to the Android Canvas API.
  • Manual rendering tests. No instrumented/screenshot tests; visual regressions can only be caught by running the example app.

15. Quick Reference

Package map

Package Role
charts Public View classes + 2 base classes
data ChartData, DataSet, Entry families
components Axes, legend, limit lines, description, markers
interfaces Dataset + data-provider interfaces (decoupling)
renderer All Canvas painting (+ scatter/ shape renderers)
highlight Touch-to-value hit testing
formatter Value & axis label formatting
listener Touch / gesture listeners
animation ChartAnimator, Easing
jobs Pooled viewport-animation jobs
buffer Reusable draw buffers
utils Transforms, pools, color templates, geometry

Extension cheat sheet

Override Interface/class Setter
Series painting DataRenderer setRenderer
Axis painting AxisRenderer setXAxisRenderer / setRendererLeftYAxis
Scatter shape IShapeRenderer setShapeRenderer
Value text IValueFormatter setValueFormatter
Axis text IAxisValueFormatter setValueFormatter (on axis)
Hit testing IHighlighter setHighlighter
Tooltip MarkerView setMarker

Key facts

Fact Value
Min SDK 14
Animations require API 11+
Runtime deps androidx.annotation only
Value type 32-bit float
Permissions none (except image export)
Reflection none (empty ProGuard rules)
License Apache 2.0