A theme-agnostic Compose Multiplatform charting library for bar and line charts that scale to any number of series - add a second, third, or tenth ChartSeries and the chart grows automatically. No forked code paths for "2 bars" vs "5 bars."
Built for Android, iOS, and Desktop targets via Kotlin Multiplatform, drawn entirely with Compose Canvas - no platform-specific rendering code, no third-party chart dependency underneath.
- Bar charts - grouped (side-by-side) or stacked, switchable per call
- Line charts - any number of lines, independently smoothed with optional gradient area fill
- Unbounded series count - the whole API is built around
ChartDataset/ChartSeries, not a fixed number of parameters - Theme-agnostic - every color comes from
ChartStyle, nothing is read fromMaterialThemeinternally, so it looks identical regardless of the host app's theme - Animated by default - entry animations on both chart types, tunable via
ChartStyle.animationDurationMs - Per-series color override - pin any series to an exact color, or let the palette assign one automatically
implementation("io.github.jeremy-gitau:multiplot:0.1.0")mavenCentral() is already part of any standard Kotlin Multiplatform project's settings.gradle.kts - no extra repository config needed.
val dataset = ChartDataset(
categories = listOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"),
series = listOf(
ChartSeries(id = "completed", label = "Completed", values = listOf(4f, 6f, 3f, 8f, 5f, 2f, 7f)),
ChartSeries(id = "active", label = "Active", values = listOf(2f, 1f, 4f, 2f, 3f, 1f, 2f)),
ChartSeries(id = "cancelled", label = "Cancelled", values = listOf(1f, 0f, 1f, 0f, 2f, 0f, 1f)),
),
)
MultiplotBarChart(dataset = dataset, displayMode = BarDisplayMode.GROUPED)
MultiplotBarChart(dataset = dataset, displayMode = BarDisplayMode.STACKED)
MultiplotLineChart(dataset = dataset)Add a fourth series any time - no other code changes needed:
series = listOf(
ChartSeries(id = "completed", label = "Completed", values = listOf(4f, 6f, 3f, 8f, 5f, 2f, 7f)),
ChartSeries(id = "active", label = "Active", values = listOf(2f, 1f, 4f, 2f, 3f, 1f, 2f)),
ChartSeries(id = "cancelled", label = "Cancelled", values = listOf(1f, 0f, 1f, 0f, 2f, 0f, 1f)),
ChartSeries(id = "refunded", label = "Refunded", values = listOf(0f, 1f, 0f, 1f, 0f, 0f, 1f)),
)Every visual knob lives on ChartStyle, passed into either chart:
val style = ChartStyle(
palette = listOf(Color(0xFF7F52FF), Color(0xFFB125EA), Color(0xFFE44857)),
gridColor = Color(0x33808080),
labelColor = Color(0xFF808080),
backgroundColor = Color(0x14808080),
cornerRadius = 12.dp,
ySteps = 5,
animationDurationMs = 900,
)
MultiplotBarChart(dataset = dataset, style = style)Leave ChartSeries.color unset to let ChartStyle.palette assign one automatically (cycling in list order by default, or using a stable hash of ChartSeries.id if you opt into that behavior). Set it explicitly to pin an exact color regardless of palette:
ChartSeries(id = "completed", label = "Completed", values = ..., color = Color(0xFF00B894))Use one of the built-in palette presets if you want a ready-made starting point:
ChartStyle(palette = MultiplotPalettes.Kotlin)
ChartStyle(palette = MultiplotPalettes.Vibrant)
ChartStyle(palette = MultiplotPalettes.Pastel)
ChartStyle(palette = MultiplotPalettes.Monochrome)If you want the same series id to keep the same palette color even when the list order changes, use stable hash assignment:
ChartStyle(
palette = MultiplotPalettes.Kotlin,
colorAssignment = ColorAssignment.ByStableHash,
)The library itself never reads MaterialTheme - build a ChartStyle from it at the call site if you want that:
val style = ChartStyle(
palette = listOf(MaterialTheme.colorScheme.primary, MaterialTheme.colorScheme.secondary),
labelColor = MaterialTheme.colorScheme.onSurfaceVariant,
)GROUPED |
STACKED |
|---|---|
| Each series gets its own bar, side by side - best for comparing series against each other at a glance | Series stack into one bar per category - best for showing totals and composition |
MultiplotBarChart(dataset = dataset, displayMode = BarDisplayMode.GROUPED)
MultiplotBarChart(dataset = dataset, displayMode = BarDisplayMode.STACKED)MultiplotLineChart(
dataset = dataset,
smooth = true, // cubic-bezier curves vs straight segments
showArea = true, // gradient fill under each line
showDots = true, // dot at every data point
emphasizeLastPoint = true, // larger dot + bold label on the final point, like "today"
)- Kotlin 2.3.10+
- Compose Multiplatform 1.11.1+
- Targets: Android, iOS (arm64 + simulator arm64 - x86_64 dropped, matching Compose Multiplatform 1.11.1), Desktop (JVM)
Apache License 2.0 - see LICENSE.
Issues and PRs welcome. This is a young library - if you hit a real limitation (not just a missing convenience), an issue with a minimal reproducing ChartDataset is the fastest way to get it looked at.