charty

charty-3d#

Projected three-dimensional charts, published as a separate artifact so a project that does not want them does not carry them.

Kotlin
implementation("com.himanshoe:charty:3.0.0")implementation("com.himanshoe:charty-3d:1.0.0")

The two carry their own version numbers. charty-3d arrived at Charty 3.0 with no releases behind it, and calling it 3.0.0 would claim two major versions it never had. It also moves at its own pace: it is experimental, so it will break more often than charty does, and tying it to charty's number would force a major bump on the stable library every time a 3D chart changed shape.

Every release is rehearsed against this: scripts/verify-release.sh publishes both artifacts locally and then compiles a consumer against the published coordinates, so a POM missing a dependency or a platform variant that never got built fails before the release rather than after it.

You never have to work out which pair goes together. Each charty-3d release declares the exact charty it was built and tested against — 1.0.0 requires charty:3.0.0 — so the build resolves the right one whether or not you name charty yourself.

Opting in#

Every public declaration here carries @ChartyExperimental. The API is still finding its shape and may change in a minor release without the deprecation cycle the rest of Charty follows, so the compiler makes you say you accept that:

Kotlin
@OptIn(ChartyExperimental::class)@Composablefun Dashboard() {    Bar3DChart(data = { bars })}

Or once for a whole module, in its build.gradle.kts:

Kotlin
kotlin {    sourceSets.all {        languageSettings.optIn("com.himanshoe.charty.common.annotation.ChartyExperimental")    }}

What "3D" means here#

These are projected, not rendered. There is no GPU scene, no depth buffer and no lighting model. Shapes are built as solids, their visible faces are worked out from the viewing angle, and the nearer ones are painted over the further ones. That is enough to read as three-dimensional on every platform Compose runs on, and it costs nothing beyond the Canvas a flat chart already uses.

Read this before choosing one#

Depth in both of these charts is decoration — it carries no data. That has real costs:

Use these when the figure is the point — a dashboard, a slide, a headline number — and the exact values are read from labels or a legend. Use BarChart or PieChart when the comparison is the point. Both defaults here are deliberately shallow and parallel, so the comparison stays as honest as a projection allows unless you ask for more.

The charts#

ChartWhat it is
Bar3DChartBars extruded into solids on a floor
Pie3DChartA pie or ring given thickness

Projection3D#

Both charts take the same viewing angle type.

Kotlin
Projection3D(    pitch: Float = 18f,        // degrees; positive tips the far edge up — looking down at it    yaw: Float = 14f,          // degrees; positive swings the right-hand side toward you    depth: Float = 0.45f,      // reference distance for perspective, as a fraction of the plot    perspective: Float = 0f,   // 0f parallel, 1f strongly convergent)

Presets:

PresetAnglePerspective
Defaultpitch 18°, yaw 14°none — values stay comparable
Isometricpitch 30°, yaw 45°none
Subtlepitch 8°, yaw 8°none — depth as a hint
Dramaticpitch 34°, yaw 28°0.6 — photographic, hardest to compare

perspective is the one setting that changes what the reader can conclude. At 0f a parallel projection keeps equal lengths equal wherever they sit; above it, they converge. Three of the four presets are parallel for that reason.

Interaction#

Both charts take a click listener, and both resolve it nearest face first — a tap always selects the shape you can see, never one occluded behind it.

Limitations#