Waterfall Chart
A waterfall chart: how an amount comes about, step by step. Each bar starts where the one before it ended, going up for what a row adds and down for what it takes away, and a total stands on nought and shows what the steps before it come to.
import com.pantrixui.components.chart.waterfall.PantrixWaterfallChart
- Steps. A row's value is the amount it adds; below zero, what it takes away. A step that adds is drawn in the chart's
risingcolour and one that takes away in itsfallingcolour: the theme'ssuccessanddangercolours, unlesscolorssays otherwise. - Totals. A row that
totalsays is a total stands on zero and shows what the steps before it come to; its own value is not asked for. A total with a value of its own is where the count starts again: like the opening amount before the first step. Totals are drawn in the series' own colour (color). - Connecting lines. A thin line goes from the end of each bar to where the next begins (
connectors). - Zero. The value axis takes zero in: the totals stand on it.
- Value labels.
labelswrites what each bar stands for at its end: over one that goes up, under one that goes down. - Horizontal.
horizontal = truesets the items down the side of the chart; each bar starts where the one above it ended, and one that adds goes right, one that takes away left (the other way about in a language read from the right). The values are written under the chart. - Automation. The chart is tagged as the
PantrixChartit is:Chart_<tagKey>. Its one series has the keysteps.
Examples
From opening to closing
A quarter's cash flow: the opening amount, income, expenses and the closing. The opening is a total with a value of its own: the count starts from it. The closing has no value: it shows what the steps come to.
Move the pointer over a bar, or touch the bar: the tooltip writes the step with its sign. The thin lines between the bars show that each step starts where the one before it ended.
PantrixWaterfallChart(
data = QUARTER_CASH,
x = { it.name },
y = { it.amount },
name = "Cash (thousand TL)",
total = { it.total },
description = "A quarter's cash flow, from opening to closing",
tagKey = "plain"
)
private data class CashMove(
val name: String,
val amount: Int?,
val total: Boolean = false
)
private val QUARTER_CASH = listOf(
CashMove("Opening", amount = 420, total = true),
CashMove("Sales", amount = 310),
CashMove("Services", amount = 120),
CashMove("Salaries", amount = -260),
CashMove("Rent", amount = -90),
CashMove("Tax", amount = -70),
CashMove("Closing", amount = null, total = true)
)
Subtotals
Subtotals along the way: at the end of each quarter, what has been reached so far. A subtotal stands on zero, and the count goes on after it from where it was.
PantrixWaterfallChart(
data = HALF_YEAR_CASH,
x = { it.name },
y = { it.amount },
name = "Cash (thousand TL)",
total = { it.total },
description = "Monthly change in cash over half a year, with a subtotal at the end of each quarter",
tagKey = "subtotals"
)
private data class CashMove(
val name: String,
val amount: Int?,
val total: Boolean = false
)
private val HALF_YEAR_CASH = listOf(
CashMove("Jan", amount = 180),
CashMove("Feb", amount = -60),
CashMove("Mar", amount = 140),
CashMove("Q1", amount = null, total = true),
CashMove("Apr", amount = -110),
CashMove("May", amount = 90),
CashMove("Jun", amount = 210),
CashMove("Q2", amount = null, total = true)
)
The values at the ends of the bars
What each bar stands for is written at its end (labels): over a step that adds and under a step that takes away, with its sign; over a total, as it is.
A label that has no room is left out; the value stays in the tooltip and for the screen reader.
PantrixWaterfallChart(
data = QUARTER_CASH,
x = { it.name },
y = { it.amount },
name = "Cash (thousand TL)",
total = { it.total },
labels = ChartDataLabels(),
description = "A quarter's cash flow, with its values",
tagKey = "labels"
)
private data class CashMove(
val name: String,
val amount: Int?,
val total: Boolean = false
)
private val QUARTER_CASH = listOf(
CashMove("Opening", amount = 420, total = true),
CashMove("Sales", amount = 310),
CashMove("Services", amount = 120),
CashMove("Salaries", amount = -260),
CashMove("Rent", amount = -90),
CashMove("Tax", amount = -70),
CashMove("Closing", amount = null, total = true)
)
Horizontal
The same quarter, horizontal (horizontal = true): the items are set down the side of the chart, and each bar starts where the one above it ended. Where the items have long names, or are many, a horizontal waterfall is easier to read.
PantrixWaterfallChart(
data = QUARTER_CASH,
x = { it.name },
y = { it.amount },
name = "Cash (thousand TL)",
total = { it.total },
horizontal = true,
labels = ChartDataLabels(),
description = "A quarter's cash flow, in horizontal bars",
tagKey = "horizontal_steps"
)
private data class CashMove(
val name: String,
val amount: Int?,
val total: Boolean = false
)
private val QUARTER_CASH = listOf(
CashMove("Opening", amount = 420, total = true),
CashMove("Sales", amount = 310),
CashMove("Services", amount = 120),
CashMove("Salaries", amount = -260),
CashMove("Rent", amount = -90),
CashMove("Tax", amount = -70),
CashMove("Closing", amount = null, total = true)
)
Your own colours
The two colours of the steps come from the chart's colours (the rising and falling fields of ChartColors), and the totals' colour from the series itself (color). Turn the switch: the lines between the bars go away (connectors).
Colour should not carry the meaning alone: which way a step goes is also read from where its bar starts and ends, and from the sign of its value.
var connectors by remember { mutableStateOf(true) }
val theme = PantrixTheme.colors
PantrixSwitchButton(
checked = connectors,
onCheckedChange = { connectors = it },
label = "Connecting lines",
tagKey = "waterfall_connectors"
)
PantrixWaterfallChart(
data = QUARTER_CASH,
x = { it.name },
y = { it.amount },
name = "Cash (thousand TL)",
total = { it.total },
connectors = connectors,
color = theme.neutral.color,
colors = ChartColors(rising = theme.info.color, falling = theme.warning.color),
description = "A quarter's cash flow, in its own colours",
tagKey = "own_colors"
)
private data class CashMove(
val name: String,
val amount: Int?,
val total: Boolean = false
)
private val QUARTER_CASH = listOf(
CashMove("Opening", amount = 420, total = true),
CashMove("Sales", amount = 310),
CashMove("Services", amount = 120),
CashMove("Salaries", amount = -260),
CashMove("Rent", amount = -90),
CashMove("Tax", amount = -70),
CashMove("Closing", amount = null, total = true)
)
Pressing a step
A press is handed the step and the level it starts from: the point's value is what the step adds and its from the level the step starts from; the two together are what is reached after the step. A total has no from. Press a bar: the line below writes what was pressed.
var pressed by remember { mutableStateOf<String?>(null) }
val strings = PantrixTheme.strings
PantrixWaterfallChart(
data = QUARTER_CASH,
x = { it.name },
y = { it.amount },
name = "Cash (thousand TL)",
total = { it.total },
onSelect = { point ->
val start = point.from
pressed = if (start == null) {
"${point.label}: total ${point.text}"
} else {
"${point.label}: ${point.text}, then ${strings.decimal(start + point.value)}"
}
},
description = "A quarter's cash flow",
tagKey = "press"
)
PantrixText(text = pressed ?: "Press a bar")
private data class CashMove(
val name: String,
val amount: Int?,
val total: Boolean = false
)
private val QUARTER_CASH = listOf(
CashMove("Opening", amount = 420, total = true),
CashMove("Sales", amount = 310),
CashMove("Services", amount = 120),
CashMove("Salaries", amount = -260),
CashMove("Rent", amount = -90),
CashMove("Tax", amount = -70),
CashMove("Closing", amount = null, total = true)
)
The long form
The chart the short form stands for: a PantrixChart with one WaterfallSeries. The short form's horizontal = true is orientation = ChartOrientation.Horizontal in the long form, and the series carries its key and its name itself. A screen that wants the waterfall together with other things writes it this way: here a line for the closing target.
PantrixChart(
series = listOf(
WaterfallSeries(
key = "cash",
name = "Cash (thousand TL)",
data = QUARTER_CASH,
x = { it.name },
y = { it.amount },
total = { it.total }
)
),
orientation = ChartOrientation.Horizontal,
marks = listOf(ChartReferenceLine(y = 500, label = "Target")),
description = "A quarter's cash flow and the closing target, in horizontal bars",
tagKey = "as_series"
)
private data class CashMove(
val name: String,
val amount: Int?,
val total: Boolean = false
)
private val QUARTER_CASH = listOf(
CashMove("Opening", amount = 420, total = true),
CashMove("Sales", amount = 310),
CashMove("Services", amount = 120),
CashMove("Salaries", amount = -260),
CashMove("Rent", amount = -90),
CashMove("Tax", amount = -70),
CashMove("Closing", amount = null, total = true)
)
API
data
A waterfall chart: how an amount comes about, step by step. Each bar starts where the one before it ended, going up for what a row adds and down for what it takes away, and a total stands on nought and shows what the steps before it come to.
| Parameter | Type | Default | What it is |
|---|---|---|---|
data | List<T> | the rows, in the order their steps are counted. | |
x | (T) -> Any | where a row stands along the chart: a name, a day, anything that is equal to itself. | |
y | (T) -> Number? | what a row adds, under nought what it takes away, or null where it has no value. For a total, the amount the count starts again from, or null for what the steps before it come to. | |
name | String | what the amounts are of: what the tooltip calls them, and a screen reader the chart where it has no description. | |
modifier | Modifier | Modifier | the chart's modifier. A height here is the chart's. |
total | ((T) -> Boolean)? | null | whether a row is a total. null, the chart has none. |
connectors | Boolean | true | whether a line leads from the end of each bar to the next. |
color | Color | Color.Unspecified | the colour the totals are drawn in. Left out, it is the first of the chart's colours. |
horizontal | Boolean | false | whether the places go down the chart's side and the bars along it, and not along its foot and up. |
labels | ChartDataLabels? | null | what each bar stands for written at its end, a step with its sign and a total as it is, where it has room. null writes none. |
xAxis | ChartAxis? | ChartAxis() | the axis of the places, under the chart, or beside it where it is horizontal. null draws nothing of it. |
yAxis | ChartAxis? | ChartAxis() | the axis of the values, beside the chart, or under it where it is horizontal. null draws nothing of it. |
marks | List<ChartMark> | emptyList() | the lines and the bands drawn in the plot besides the steps: a target, a limit. |
tooltip | ChartTooltip? | ChartTooltip() | what is shown for the place that is pointed at. null shows none. |
zoom | ChartZoom? | null | what lets the reader look closer at a part of the places and move along the rest. null, which it is unless the chart is given one, shows all the places and no more. |
export | ChartExport? | null | what lets the reader take the chart out of the app as a file: a picture, or a drawing that is sharp at any size. null, which it is unless the chart is given one, and the chart has no such button. |
empty | (@Composable () -> Unit)? | null | what the chart shows in its plot while it has no value to draw, in the place of the theme's words for it ("No data"), which a screen reader is then not told either. null writes the words. A file the chart is exported as says them. |
state | ChartState | rememberChartState() | what the reader points at: the chart's own where none is given. |
description | String? | null | what the chart shows, in a few words, for a screen reader. |
onSelect | ((ChartPoint) -> Unit)? | null | called with the step or the total that is pressed. |
style | ChartStyle? | null | this chart's own geometry. |
colors | ChartColors? | null | this chart's own colours, where they are not the theme's: rising and falling among them. |
tagKey | String? | null | the chart's automation key. The chart is tagged as the PantrixChart it is, Chart_<tagKey>, and its parts and events are that chart's; its one series has the key steps. |
ChartStyle
A chart's geometry: how tall it is where nothing says, how thick its lines and how large its marks are, and the room between its parts; and whether its fills have textures besides their colours.
| Parameter | Type | Default | What it is |
|---|---|---|---|
height | Dp | Dp.Unspecified | How tall a chart's plot is, with its axes, where the chart's modifier gives it no height. A legend above or under the plot adds its own. |
lineWidth | Dp | Dp.Unspecified | The width of a series' line. |
markerSize | Dp | Dp.Unspecified | The width and height of the mark on a point. |
selectedMarkerSize | Dp | Dp.Unspecified | The same of the mark on the point that is pointed at. |
gridWidth | Dp | Dp.Unspecified | The width of the grid's lines, of the lines along the axes and of the line that marks the place pointed at. Zero draws none. |
labelGap | Dp | Dp.Unspecified | Between the plot and what is written beside it and under it, and between that and an axis' title. |
tickSpacing | Dp | Dp.Unspecified | The least room between two values marked along the axis of values: what decides how many are marked where the axis does not say. |
legendGap | Dp | Dp.Unspecified | Between the legend and the chart it stands beside. |
legendItemGap | Dp | Dp.Unspecified | Between one entry of the legend and the next. |
swatchSize | Dp | Dp.Unspecified | How wide the sample of a series is in the legend and in the tooltip: a short run of its line, or a patch of its fill. |
swatchGap | Dp | Dp.Unspecified | Between that sample and the name after it. |
tooltipShape | ShapeSpec | ShapeSpec.Unspecified | The tooltip's corners: a step of the brand's shape scale, or a fixed shape. |
tooltipHorizontalPadding | Dp | Dp.Unspecified | Between the tooltip's sides and what it holds. |
tooltipVerticalPadding | Dp | Dp.Unspecified | Between its top and bottom and what it holds, and between its heading and rows. |
tooltipGap | Dp | Dp.Unspecified | Between the place pointed at and the tooltip beside it. |
tooltipElevation | Dp | Dp.Unspecified | The tooltip's shadow. |
barGap | Dp | Dp.Unspecified | Between two bars that stand side by side at a place. Bars too thin for it stand closer. |
barMaxWidth | Dp | Dp.Unspecified | The widest a bar is, however much room its place has: a chart of three places is not three slabs. |
barRadius | Dp | Dp.Unspecified | How round the corners of a bar's end are, the end away from nought. |
sliceGap | Dp | Dp.Unspecified | Between two slices of a pie that lie side by side, the same from the pie's middle to its rim. |
selectedSliceOffset | Dp | Dp.Unspecified | How far the slice of a pie that is pointed at stands out past the pie's rim. The pie keeps this much room about itself, so that the slice has where to stand. |
gaugeWidth | Dp | Dp.Unspecified | How thick the arc of a gauge is. An arc is no thicker than half its radius. |
meterHeight | Dp | Dp.Unspecified | How tall the bar of a meter group is. |
trackerHeight | Dp | Dp.Unspecified | How tall the blocks of a status tracker are. |
bubbleMinSize | Dp | Dp.Unspecified | How far across the smallest bubble of a scatter chart is: a point whose size is nothing, or too little to be seen as an area, is still a point. |
bubbleMaxSize | Dp | Dp.Unspecified | How far across its largest bubble is: the one whose size is the most of the chart's. |
navigatorHeight | Dp | Dp.Unspecified | How tall the strip under a chart's plot is, on which the part of the chart that is in view is marked and moved, in a chart whose zoom has one: how wide, beside a plot whose places go down its side. |
barBandShare | Float | Float.NaN | How much of a place's band its bars take, more than nought and one at the most: the rest is the room between one place's bars and the next's. Bars are no wider than barMaxWidth all the same. |
markLineWidth | Dp | Dp.Unspecified | The width of a mark's line: a target, a limit, a day. Zero draws none, and the mark's words are written all the same. |
markBandAlpha | Float | Float.NaN | How much of its colour a mark's band is drawn in, from nought to one: a band lies behind the series, and is a tint. |
patterns | Boolean? | null | Whether the fills of a chart's series, slices and tiles are drawn with textures besides their colours, and its lines broken in turn (ChartPattern): what tells them apart for a reader who cannot tell the colours apart. Left out, as the system is set: on where it is set to tell things apart without colour, iOS's "Differentiate Without Color" and Android's colour correction, and off otherwise. |
nodeWidth | Dp | Dp.Unspecified | How wide a node of a sankey is. |
nodeGap | Dp | Dp.Unspecified | Between two nodes of a column of a sankey. |
ChartColors
What a chart is painted with, for a chart that does not take the theme's colours: a colour that is set is used, and one that is left out stays the theme's.
| Parameter | Type | Default | What it is |
|---|---|---|---|
series | List<Color> | emptyList() | The colours the series are drawn in, in the order they are handed out, for the series that name none of their own. Empty, they are the theme's chart colours. |
grid | Color | Color.Unspecified | The lines drawn across the chart at the marks of an axis. The theme's divider. |
axis | Color | Color.Unspecified | The line along an axis. The theme's border. |
label | Color | Color.Unspecified | What is written beside the axes: the values, the places and the axes' titles, and the names in the legend. The theme's textSecondary. |
crosshair | Color | Color.Unspecified | The line that marks the place pointed at. The theme's borderHover: stronger than the grid it crosses, and quieter than the series it stands behind. |
tooltipContainer | Color | Color.Unspecified | The tooltip's fill. The theme's surface. |
tooltipBorder | Color | Color.Unspecified | The tooltip's edge. The theme's border. |
tooltipText | Color | Color.Unspecified | The tooltip's heading and its values. The theme's textPrimary. |
tooltipLabel | Color | Color.Unspecified | The names of the series in the tooltip. The theme's textSecondary. |
rising | Color | Color.Unspecified | What a value that goes up is drawn in: a step of a waterfall that adds. The theme's success. |
falling | Color | Color.Unspecified | What a value that goes down is drawn in: a step of a waterfall that takes away. The theme's danger. |
Accessibility
- Tooltip and screen reader. A step is written as what it adds, with its sign ("+310"); a total as what it comes to. A press is handed the step as the point's
valueand the level the step starts from as itsfrom.