Line Chart
A line chart of rows that are given once: a line for each of the values read from them, along the places x reads from them.
import com.pantrixui.components.chart.line.PantrixLineChart
- Rows and values.
datagives the rows,xa row's place. EachChartValueis a series: its key, its name and the function that reads its value from a row. - How the line goes.
curvesays how the line goes from one point to the next: straight, smooth or stepped. A smooth line stays between two points; it shows no peak or dip that the values do not have. - More than colour. A series'
dashdraws its line in dashes or in dots, and itsmarkerputs a shape on its points. Both show in the series' sample in the legend and in the tooltip. - Missing values.
missingsays what the line does at a row that has no value: it breaks, connects, or counts it as zero. - Numeric axis. Where the places are numbers and
xAxis = ChartAxis(numeric = true), the points stand as far apart as their numbers and the axis is marked at round numbers; otherwise numbers are names too, set out at even steps. - Value labels and marks.
labelswrites the values over the points;marksdraws a target line or the band of a range. - When `PantrixChart`. For a chart whose series come from different lists, are of different kinds or are read by a second axis: each series takes its own
LineSeries. - Automation. The chart is tagged as the
PantrixChartit is:Chart_<tagKey>.
Examples
Lines from the same rows
At its plainest: the rows, the x that gives a row's place, and a ChartValue for each series. A series takes its key and its name; the block at the end reads its value from a row.
Three series take the theme's first three chart colours. Press a name in the legend: its series goes, and the ones that stay keep their colours.
PantrixLineChart(
data = TRAFFIC,
x = { it.day },
values = listOf(
ChartValue("search", "Search") { it.search },
ChartValue("direct", "Direct") { it.direct },
ChartValue("social", "Social") { it.social }
),
description = "Three sources of visits by day of the week",
tagKey = "plain"
)
private data class Traffic(
val day: String,
val search: Int,
val direct: Int,
val social: Int
)
private val TRAFFIC = listOf(
Traffic("Mon", search = 420, direct = 240, social = 130),
Traffic("Tue", search = 480, direct = 260, social = 120),
Traffic("Wed", search = 455, direct = 300, social = 165),
Traffic("Thu", search = 530, direct = 280, social = 190),
Traffic("Fri", search = 510, direct = 330, social = 240),
Traffic("Sat", search = 360, direct = 210, social = 310),
Traffic("Sun", search = 330, direct = 180, social = 285)
)
Numeric axis
The height of a hiking trail, measured at uneven points along the way: the places are numbers, in kilometres. With xAxis = ChartAxis(numeric = true) the points stand as far apart as their numbers: 0.8 km and 1.2 km close together, 7.5 km and 11 km far apart; the axis is marked at round kilometres, written as format says. The summit's line does not stand at a measurement but at 9.6 km.
Turn the switch off: the numbers become names, set out at even steps, and the trail's steepness reads wrong.
var numeric by remember { mutableStateOf(true) }
val strings = PantrixTheme.strings
PantrixSwitchButton(
checked = numeric,
onCheckedChange = { numeric = it },
label = "Numeric axis",
tagKey = "line_numeric"
)
PantrixLineChart(
data = TRAIL,
x = { it.first },
values = listOf(ChartValue("height", "Height (m)") { it.second }),
curve = ChartCurve.Smooth,
xAxis = ChartAxis(numeric = numeric, format = { "${strings.decimal(it)} km" }),
marks = listOf(ChartReferenceLine(x = 9.6, label = "Summit")),
description = "The height of a hiking trail, measured along the way",
tagKey = "numeric"
)
private val TRAIL = listOf(
0.0 to 420,
0.8 to 455,
1.2 to 470,
2.5 to 560,
4.0 to 610,
7.5 to 820,
9.6 to 1_040,
11.0 to 930,
12.4 to 780
)
How the line goes
curve says how the line goes from one point to the next. Linear goes straight. Smooth goes round through the points but stays between them: it makes up no peak or dip. The stepped ones carry a value level from one point to the next: StepAfter holds until the value changes, like a stock or a price; StepBefore goes to the next value ahead of it; Step steps halfway between the two.
var curve by remember { mutableStateOf(ChartCurve.Smooth) }
PantrixSegmentButton(
options = CURVES,
selected = curve,
onSelect = { curve = it },
fullWidth = false,
tagKey = "curve"
)
PantrixLineChart(
data = TRAFFIC,
x = { it.day },
values = listOf(ChartValue("search", "Search", marker = ChartMarker.Circle) { it.search }),
curve = curve,
description = "Visits from search by day of the week",
tagKey = "curves"
)
private data class Traffic(
val day: String,
val search: Int,
val direct: Int,
val social: Int
)
private val TRAFFIC = listOf(
Traffic("Mon", search = 420, direct = 240, social = 130),
Traffic("Tue", search = 480, direct = 260, social = 120),
Traffic("Wed", search = 455, direct = 300, social = 165),
Traffic("Thu", search = 530, direct = 280, social = 190),
Traffic("Fri", search = 510, direct = 330, social = 240),
Traffic("Sat", search = 360, direct = 210, social = 310),
Traffic("Sun", search = 330, direct = 180, social = 285)
)
private val CURVES = listOf(
SegmentOption(value = ChartCurve.Linear, label = "Straight", tagKey = "linear"),
SegmentOption(value = ChartCurve.Smooth, label = "Smooth", tagKey = "smooth"),
SegmentOption(value = ChartCurve.Step, label = "Step", tagKey = "step"),
SegmentOption(value = ChartCurve.StepBefore, label = "Before", tagKey = "before"),
SegmentOption(value = ChartCurve.StepAfter, label = "After", tagKey = "after")
)
Series told apart by more than colour
Colour alone is not enough for every reader: for an eye that does not tell red from green, for a black and white printout, for a chart of many series. Here each series is told apart by more than its colour too: one is a solid line with circles, one a dashed line with squares, one a dotted line with triangles.
The same sample stands in the legend and in the tooltip: a series is known there too by its line and its shape.
PantrixLineChart(
data = TRAFFIC,
x = { it.day },
values = listOf(
ChartValue("search", "Search", marker = ChartMarker.Circle) { it.search },
ChartValue("direct", "Direct", dash = ChartDash.Dashed, marker = ChartMarker.Square) { it.direct },
ChartValue("social", "Social", dash = ChartDash.Dotted, marker = ChartMarker.Triangle) { it.social }
),
description = "Three sources of visits by day of the week",
tagKey = "told_apart"
)
private data class Traffic(
val day: String,
val search: Int,
val direct: Int,
val social: Int
)
private val TRAFFIC = listOf(
Traffic("Mon", search = 420, direct = 240, social = 130),
Traffic("Tue", search = 480, direct = 260, social = 120),
Traffic("Wed", search = 455, direct = 300, social = 165),
Traffic("Thu", search = 530, direct = 280, social = 190),
Traffic("Fri", search = 510, direct = 330, social = 240),
Traffic("Sat", search = 360, direct = 210, social = 310),
Traffic("Sun", search = 330, direct = 180, social = 285)
)
A small line with no axes
A small line in the corner of a card: it has no axes and no legend (null), and is sixty dp tall. Its values are still in place: the value of the day pointed at with a pointer or a finger is read in the tooltip, and a screen reader says the days one by one.
A chart with no axis tells its tooltip how its values are written (ChartTooltip.format): here what the number counts is added after the number.
val strings = PantrixTheme.strings
PantrixLineChart(
data = TRAFFIC,
x = { it.day },
values = listOf(ChartValue("search", "Search") { it.search }),
modifier = Modifier.height(60.dp),
curve = ChartCurve.Smooth,
xAxis = null,
yAxis = null,
tooltip = ChartTooltip(format = { "${strings.decimal(it)} visits" }),
description = "Visits from search by day of the week",
tagKey = "bare"
)
private data class Traffic(
val day: String,
val search: Int,
val direct: Int,
val social: Int
)
private val TRAFFIC = listOf(
Traffic("Mon", search = 420, direct = 240, social = 130),
Traffic("Tue", search = 480, direct = 260, social = 120),
Traffic("Wed", search = 455, direct = 300, social = 165),
Traffic("Thu", search = 530, direct = 280, social = 190),
Traffic("Fri", search = 510, direct = 330, social = 240),
Traffic("Sat", search = 360, direct = 210, social = 310),
Traffic("Sun", search = 330, direct = 180, social = 285)
)
API
data
A line chart of rows that are given once: a line for each of the values read from them, along the places x reads from them.
| Parameter | Type | Default | What it is |
|---|---|---|---|
data | List<T> | the rows, in the order the lines go through them. | |
x | (T) -> Any | where a row stands along the chart: a name, a day, anything that is equal to itself. | |
values | List<ChartValue<T>> | the series: what each reads from a row, and how it is called and drawn. | |
modifier | Modifier | Modifier | the chart's modifier. A height here is the chart's, the legend's with it. |
curve | ChartCurve | ChartCurve.Linear | how each line goes from a point to the next. |
missing | ChartMissing | ChartMissing.Gap | what a line does at a row that has no value. |
labels | ChartDataLabels? | null | the values written over the points of every line, where they have room. null writes none. |
xAxis | ChartAxis? | ChartAxis() | the axis of the places, under the chart. null draws nothing of it. |
yAxis | ChartAxis? | ChartAxis() | the axis of the values, beside the chart. null draws nothing of it. |
secondYAxis | ChartAxis? | ChartAxis() | the second axis of the values, at the chart's other side: drawn where a value is read by it (ChartValue.axis), and not otherwise. null draws nothing of it. |
marks | List<ChartMark> | emptyList() | the lines and the bands drawn in the plot besides the series: a target, a limit, a stretch of places. |
legend | ChartLegend? | ChartLegend() | where the names of the series stand. null shows none. |
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. |
decimation | ChartDecimation? | ChartDecimation() | how a line with more points in view than the plot has room for is drawn through fewer of them. null draws every point, as many as there are. |
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 has hidden and what they point 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 value 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. |
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. |
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. |