Radar Chart
A radar chart: several measures of one thing set out on spokes about a middle, and joined into a web, so that its shape is read at a glance and two things are told apart by theirs. The skills of two people, a product against its rival, this year against the last.
import com.pantrixui.components.chart.radar.PantrixRadarChart
- Web. Each series is a web: its line, its fill with a share of its colour (
filled; the share isfillAlpha, a fifth where left out) and a mark at each of its values (marker). The line can be dashed or dotted (dash): to tell a target from what was measured. Every fill lies under every line. - Rings.
gridsays whether the rings of the values are drawn straight from spoke to spoke (as a web) or round. - Axes.
xAxisis the spokes: whether their names are written (labels), how they are written (label), whether the spokes are drawn (line).yAxisis the axis of values: its ends, how many values it marks, how they are written, whether the values are written (labels) and whether the rings are drawn (grid). The axis of values starts at nought unless it is told otherwise. - The spoke pointed at. The spoke nearest the pointer, or the one that is tapped, is pointed at: the spoke stands out, the values on it grow, and the tooltip writes the values the series have there. With
ChartTooltip(shared = false)the tooltip writes only the value of the series nearest the pointer. - Direction. The chart turns the same way in a language read from right to left too.
- Export.
exportputs a button over the chart: the chart is made, as it is on the screen and without the part that is pointed at or its tooltip, into a PNG, an SVG or a PDF file and handed to the app. - Automation.
RadarChart_<tagKey>; the plot is.Plot, the spokes.Point_<number>, the legend's entries.Legend_<series>, the tooltip.Tooltip.
Examples
Two webs
Two people's scores in six skills, out of ten. The shapes of the two webs show who is strong where.
Move the pointer near a spoke or tap it: the tooltip writes the two people's scores in that skill. A press on an entry of the legend takes that person out of the chart.
val skills = teamSkills()
PantrixRadarChart(
series = listOf(
RadarSeries("ada", "Ada", skills, x = { it.name }, y = { it.ada }),
RadarSeries("lin", "Lin", skills, x = { it.name }, y = { it.lin })
),
yAxis = ChartAxis(max = 10.0),
description = "The skills of Ada and Lin",
tagKey = "plain"
)
internal fun teamSkills(): List<TeamSkill> = listOf(
TeamSkill("Design", ada = 8, lin = 5, target = 7),
TeamSkill("Code", ada = 6, lin = 9, target = 8),
TeamSkill("Testing", ada = 5, lin = 7, target = 7),
TeamSkill("Writing", ada = 9, lin = 4, target = 6),
TeamSkill("Presenting", ada = 7, lin = 6, target = 8),
TeamSkill("Planning", ada = 4, lin = 8, target = 7)
)
internal class TeamSkill(
val name: String,
val ada: Int,
val lin: Int,
val target: Int
)
Against a target
What was measured and the target: the measured is a filled web, the target a dashed line (filled = false, dash) with no marks. The rings are round here (RadarGrid.Circle).
val skills = teamSkills()
PantrixRadarChart(
series = listOf(
RadarSeries("now", "Now", skills, x = { it.name }, y = { it.ada }),
RadarSeries(
key = "target",
name = "Target",
data = skills,
x = { it.name },
y = { it.target },
filled = false,
marker = ChartMarker.None,
dash = ChartDash.Dashed
)
),
yAxis = ChartAxis(max = 10.0),
grid = RadarGrid.Circle,
description = "Ada's skills, with the target",
tagKey = "target"
)
internal fun teamSkills(): List<TeamSkill> = listOf(
TeamSkill("Design", ada = 8, lin = 5, target = 7),
TeamSkill("Code", ada = 6, lin = 9, target = 8),
TeamSkill("Testing", ada = 5, lin = 7, target = 7),
TeamSkill("Writing", ada = 9, lin = 4, target = 6),
TeamSkill("Presenting", ada = 7, lin = 6, target = 8),
TeamSkill("Planning", ada = 4, lin = 8, target = 7)
)
internal class TeamSkill(
val name: String,
val ada: Int,
val lin: Int,
val target: Int
)
Telling the series apart
With ChartTooltip(shared = false) the tooltip writes not all the series of the spoke but the one nearest the pointer. On the keyboard the up and down arrows go from one series to the next on the same spoke.
val skills = teamSkills()
PantrixRadarChart(
series = listOf(
RadarSeries("ada", "Ada", skills, x = { it.name }, y = { it.ada }),
RadarSeries("lin", "Lin", skills, x = { it.name }, y = { it.lin }, marker = ChartMarker.Square)
),
yAxis = ChartAxis(max = 10.0),
tooltip = ChartTooltip(shared = false),
description = "The skills of Ada and Lin",
tagKey = "apart"
)
internal fun teamSkills(): List<TeamSkill> = listOf(
TeamSkill("Design", ada = 8, lin = 5, target = 7),
TeamSkill("Code", ada = 6, lin = 9, target = 8),
TeamSkill("Testing", ada = 5, lin = 7, target = 7),
TeamSkill("Writing", ada = 9, lin = 4, target = 6),
TeamSkill("Presenting", ada = 7, lin = 6, target = 8),
TeamSkill("Planning", ada = 4, lin = 8, target = 7)
)
internal class TeamSkill(
val name: String,
val ada: Int,
val lin: Int,
val target: Int
)
How dark the fill is
Ada's web is filled darker (fillAlpha = 0.5f), Lin's lighter (0.08f): one stands out, the other stays behind. Lin's line is still over Ada's fill.
val skills = teamSkills()
PantrixRadarChart(
series = listOf(
RadarSeries("ada", "Ada", skills, x = { it.name }, y = { it.ada }, fillAlpha = 0.5f),
RadarSeries("lin", "Lin", skills, x = { it.name }, y = { it.lin }, fillAlpha = 0.08f)
),
yAxis = ChartAxis(max = 10.0),
description = "The skills of Ada and Lin",
tagKey = "fills"
)
internal fun teamSkills(): List<TeamSkill> = listOf(
TeamSkill("Design", ada = 8, lin = 5, target = 7),
TeamSkill("Code", ada = 6, lin = 9, target = 8),
TeamSkill("Testing", ada = 5, lin = 7, target = 7),
TeamSkill("Writing", ada = 9, lin = 4, target = 6),
TeamSkill("Presenting", ada = 7, lin = 6, target = 8),
TeamSkill("Planning", ada = 4, lin = 8, target = 7)
)
internal class TeamSkill(
val name: String,
val ada: Int,
val lin: Int,
val target: Int
)
Pressing a value
onSelect gives the value that is pressed: press a spoke, or go to one with the keyboard and press Enter, and the line under the card writes what was pressed.
val report = LocalExampleEvents.current
val skills = teamSkills()
PantrixRadarChart(
series = listOf(RadarSeries("ada", "Ada", skills, x = { it.name }, y = { it.ada })),
yAxis = ChartAxis(max = 10.0),
onSelect = { point -> report("${point.label}: ${point.text}") },
description = "Ada's skills",
tagKey = "pressed"
)
internal fun teamSkills(): List<TeamSkill> = listOf(
TeamSkill("Design", ada = 8, lin = 5, target = 7),
TeamSkill("Code", ada = 6, lin = 9, target = 8),
TeamSkill("Testing", ada = 5, lin = 7, target = 7),
TeamSkill("Writing", ada = 9, lin = 4, target = 6),
TeamSkill("Presenting", ada = 7, lin = 6, target = 8),
TeamSkill("Planning", ada = 4, lin = 8, target = 7)
)
internal class TeamSkill(
val name: String,
val ada: Int,
val lin: Int,
val target: Int
)
Export
export = ChartExport(...) puts an export button over the chart: press it and choose the kind (PNG, SVG or PDF). The chart makes the file and hands it to onExport; below, its name and size show, and a PNG's picture, and "Save the file" hands it over in the platform's way.
The file has the rings, the names and the two webs; the legend is under them.
var file by remember { mutableStateOf<ChartExportFile?>(null) }
val skills = teamSkills()
PantrixRadarChart(
series = listOf(
RadarSeries("ada", "Ada", skills, x = { it.name }, y = { it.ada }),
RadarSeries("lin", "Lin", skills, x = { it.name }, y = { it.lin })
),
yAxis = ChartAxis(max = 10.0),
description = "The skills of Ada and Lin",
tagKey = "exported",
export = ChartExport(fileName = "skills") { file = it }
)
ExportedFile(file, tagKey = "exported")
internal fun teamSkills(): List<TeamSkill> = listOf(
TeamSkill("Design", ada = 8, lin = 5, target = 7),
TeamSkill("Code", ada = 6, lin = 9, target = 8),
TeamSkill("Testing", ada = 5, lin = 7, target = 7),
TeamSkill("Writing", ada = 9, lin = 4, target = 6),
TeamSkill("Presenting", ada = 7, lin = 6, target = 8),
TeamSkill("Planning", ada = 4, lin = 8, target = 7)
)
internal class TeamSkill(
val name: String,
val ada: Int,
val lin: Int,
val target: Int
)
API
series
A radar chart: several measures of one thing set out on spokes about a middle, and joined into a web, so that its shape is read at a glance and two things are told apart by theirs. The skills of two people, a product against its rival, this year against the last.
| Parameter | Type | Default | What it is |
|---|---|---|---|
series | List<RadarSeries<*>> | the series, in the order they are drawn and listed: a later one is drawn over an earlier. Their keys tell them apart, and two with one key are refused. | |
modifier | Modifier | Modifier | the chart's modifier. A height here is the chart's, the legend's with it. |
xAxis | ChartAxis? | ChartAxis() | the spokes: whether their names are written about the chart (labels), how a name is written (label), and whether the spokes are drawn (line). null draws nothing of them. |
yAxis | ChartAxis? | ChartAxis() | the axis of the values, out from the chart's middle: its ends, about how many values it marks, how a value is written, whether the marked values are written (labels) and whether a ring is drawn at each (grid). It starts at nought unless startFromZero or min says otherwise. null draws nothing of it. |
grid | RadarGrid | RadarGrid.Polygon | whether a ring goes straight from spoke to spoke, as a web, or round. |
legend | ChartLegend? | ChartLegend() | where the names of the series stand. null shows none. |
tooltip | ChartTooltip? | ChartTooltip() | what is shown for the spoke that is pointed at. null shows none. |
empty | (@Composable () -> Unit)? | null | what the chart shows 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. |
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: the first thing it says of the chart. Left out, the chart is announced by the names of its series. |
onSelect | ((ChartPoint) -> Unit)? | null | called with the value that is pressed: the one pointed at, or of the series nearest the press where the spoke's values are pointed at together. |
style | ChartStyle? | null | this chart's own geometry: the fields set here, with the theme's for the rest. |
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 RadarChart_<tagKey>, its plot RadarChart_<tagKey>.Plot, a spoke of it RadarChart_<tagKey>.Point_<number> counted from one, the legend's entry of a series RadarChart_<tagKey>.Legend_<series' key> and the tooltip RadarChart_<tagKey>.Tooltip. A press on a value is reported as a RadarChart select event with the series' key, and a press on a legend's entry as a toggle event with the key and whether the series is shown. Nothing of the values is reported. |
export | ChartExport? | null | what lets the reader take the chart out of the app as a PNG, an SVG or a PDF: a button over the chart makes the file of it as it is and hands it over (see ChartExport). null, the chart has no such button. |
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
- Keyboard. The chart is one stop for Tab: the arrows go from spoke to spoke round the chart, and after the last back to the first; Home and End go to the first and the last spoke, Escape lets go, Enter and Space press the value that is pointed at.
- Screen reader. The chart says its
description, then each spoke with the values the series have there.