ComposePlotLib is a Kotlin Multiplatform charting library for Compose Multiplatform, shipping 26 chart families to Android and iOS from one source set. MPAndroidChart is still the default answer for Android charting and it's a View-era library: imperative mutation, notifyDataSetChanged(), and Android only.
The constraint: A chart is stateful in exactly the ways Compose dislikes. It has a viewport that pans and zooms, a selection that survives recomposition, and an animation clock. The obvious design gives all three to the chart itself. That is what View-era charting does, and it is why chart state can't be hoisted, restored, driven from a test, or shared between two charts that should scroll together. The second constraint is that none of the chart maths may touch a platform type, because the same source set has to compile for Android and for iOS.
The decision: Two modules and a planning pipeline. chart-core holds the geometry, the domain and viewport math, visible-range filtering and hit resolution, and has no UI dependency at all; chart-compose renders. Between them, one pass: an immutable ChartSpec plus a hoisted ChartViewportState and ChartSelectionState go into a ChartPlanner, which emits a ChartLayoutPlan, which becomes DrawCommands, which a canvas adapter draws. The state is the caller's, so two charts can share a viewport and a range selector can drive one.
What I rejected, and why: A stateful chart composable owning its own viewport. Smaller API, and it forecloses linked charts, state restoration and testing the math without a screen. And wrapping MPAndroidChart in an AndroidView, which is the cheap answer and works: it also pins the result to Android forever, which defeats the reason for building it.
What it cost:
34,491 lines of Kotlin, plus 11,559 lines of tests across 80 test files. The tests run against chart-core, so most of them need no UI.
26 families ship, but 12 are explicitly non-interactive: gauge, treemap, sunburst, funnel and friends have no viewport, selection or gestures. "26 chart families" is not 26 interactive charts.
No iosX64 target: Compose Multiplatform 1.11.1 publishes no ios_x64 klib variants, so Intel simulators are unsupported. That is verified against the artifacts and written in the build file, not assumed.
Distribution is GitHub Packages, which requires a token to consume, so installing it is four lines of credentials before the dependency line.
JMH benchmarks exist as a module that isn't shipped, and there's no CI baseline for them. Unpinned machines make the numbers flaky, so they are run locally before a release and the unit tests carry the regression load.
What I'd do differently: Publish to Maven Central first. The GitHub Packages token is the single biggest thing standing between this library and someone actually using it, and it's a packaging decision that's cheap at the start and awkward once versions are out. I optimised for getting a release out and picked the registry that needed no account setup, which is the wrong trade for a library whose entire purpose is to be depended on.