Bar Plots
Plotting vertical bars
Bar Plots are also 2-D plots and are therefore plotted within an XYGraph
parent. They are typically used with discrete data, and accordingly all of the examples on this page will use CategoryAxisModel
for the x-axis. The y-axis can be of any data type, but the examples will all use LinearAxisModel
.
Single Vertical Bar Plot
The simplest type of vertical bar plot has a single series of data, and there is a VerticalBarPlot
overload to make this use case easy when using Float values for the y-axis. The below example demonstrates this to plot the population of each New York City burrough.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| val boroughs = listOf("Bronx", "Brooklyn", "Manhattan", "Queens", "Staten Island")
val population = listOf(1.446788f, 2.648452f, 1.638281f, 2.330295f, 0.487155f)
XYGraph(
xAxisModel = remember { CategoryAxisModel(boroughs) },
yAxisModel = rememberFloatLinearAxisModel(0f..3f, minorTickCount = 0),
yAxisTitle = "Population (Millions)"
) {
VerticalBarPlot(
xData = boroughs,
yData = population,
bar = {
DefaultVerticalBar(SolidColor(Color.Blue))
}
)
}
|
/examples/src/jvmMain/kotlin/io/github/koalaplot/example/VerticalBar1.ktIn the above example, all bars were automatically extended to the origin of the y-axis, 0. In some cases it is desirable to plot vertical bars with starting positions that are not at 0. To support this use case, there is a second form of VerticalBarPlot
that allows specifying the starting and ending coordinates of each bar. The below example demonstrates using this flexibility to create a waterfall chart:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| @OptIn(ExperimentalKoalaPlotApi::class)
fun main() = singleWindowApplication {
val categories = listOf("Initial Cash", "Q1", "Q2", "Q3", "Q4", "Final Cash")
val colors = listOf(
Color.DarkGray, Color(0xFF00498F), Color(0xFFED7D31),
Color(0xFF00498F), Color(0xFF00498F), Color.DarkGray,
)
val data = listOf(
verticalBarPlotEntry(categories[0], 0f, 100f),
verticalBarPlotEntry(categories[1], 100f, 120f),
verticalBarPlotEntry(categories[2], 120f, 90f),
verticalBarPlotEntry(categories[3], 90f, 110f),
verticalBarPlotEntry(categories[4], 110f, 130f),
verticalBarPlotEntry(categories[5], 0f, 130f),
)
XYGraph(
xAxisModel = remember { CategoryAxisModel(categories) },
yAxisModel = rememberFloatLinearAxisModel(0f..150f, minorTickCount = 0),
) {
VerticalBarPlot(
data,
bar = { DefaultVerticalBar(SolidColor(colors[it])) }
|
/examples/src/jvmMain/kotlin/io/github/koalaplot/example/VerticalBar2.ktThere is also a builder DSL for vertical bar plots, that slightly improves on the syntax. The previous example can also be implemented as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| fun main() = singleWindowApplication {
val categories = listOf("Initial Cash", "Q1", "Q2", "Q3", "Q4", "Final Cash")
XYGraph(
xAxisModel = remember { CategoryAxisModel(categories) },
yAxisModel = rememberFloatLinearAxisModel(0f..150f, minorTickCount = 0),
) {
VerticalBarPlot {
item("Initial Cash", 0f, 100f, solidBar(Color.DarkGray))
item("Q1", 100f, 120f, solidBar(Color(0xFF00498F)))
item("Q2", 120f, 90f, solidBar(Color(0xFFED7D31)))
item("Q3", 90f, 110f, solidBar(Color(0xFF00498F)))
item("Q4", 110f, 130f, solidBar(Color(0xFF00498F)))
item("Final Cash", 0f, 130f, solidBar(Color.DarkGray))
}
|
Tip
For improved type safety, consider using an enumeration for the CategoryAxisModel
categories. If an item is added with a category value that is not a member of the list provided to the CategoryAxisModel
constructor, a runtime exception will be thrown.Stacked Bars
A stacked bar chart consists of multiple series of data, each of which have data points at the same set of x-axis values. The bars for the data at each x-axis value accumulate and stack on top of each other to form a total. The below example demonstrates a stacked bar plot showing the population for each of the 5 New York City boroughs by year.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| val boroughs = listOf("Bronx", "Brooklyn", "Manhattan", "Queens", "Staten Island")
val years = listOf(1980, 1990, 2000, 2010, 2020)
val colors =
listOf(
Color.hsv(0f, 1f, 0.7f),
Color.hsv(72f, 1f, 0.7f),
Color.hsv(144f, 1f, 0.7f),
Color.hsv(216f, 1f, 0.7f),
Color.hsv(288f, 1f, 0.7f)
) // 1 color per borough
// Population data is in order of borough, then year
val population = listOf(
listOf(1168972, 1203789, 1332650, 1385108, 1446788), // Bronx
listOf(2230936, 2300664, 2465326, 2552911, 2648452), // Brooklyn
listOf(1428285, 1487536, 1537195, 1585873, 1638281), // Manhattan
listOf(1891325, 1951598, 2229379, 2250002, 2330295), // Queens
listOf(352121, 378977, 443728, 468730, 487155), // Staten Island
)
XYGraph(
xAxisModel = remember { CategoryAxisModel(years) },
yAxisModel = rememberFloatLinearAxisModel(0f..10f, minorTickCount = 0),
yAxisTitle = "Population (Millions)"
) {
StackedVerticalBarPlot {
boroughs.forEachIndexed { index, _ ->
series(solidBar(colors[index])) {
years.forEachIndexed { yearIndex, year ->
item(year, population[index][yearIndex].toFloat() / 1E6f)
}
}
}
}
}
|
/examples/src/jvmMain/kotlin/io/github/koalaplot/example/StackedVerticalBar1.ktThis example uses a
StackedVerticalBarPlot overload that initiates a builder api for specifying the data series and items within each series. This builder will automatically accumulate the values in a stack, and is currently implemented only for vertical axes that use Float
values. An alternative is to use the other variant of StackedVerticalBarPlot
, which is lower level but directly receives a List of the data regardless of types used, and requires the user to pre-accumulate the stack values.
Grouped Bars
Like stacked bars, grouped bars also plot multiple series of data with a common set of x-axis values. However in grouped bars, each series is plotted side by side in a group centered on the common x-axis value for the group. The below example demonstrates creating a grouped vertical bar plot with Koala Plot.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| val boroughs = listOf("Bronx", "Brooklyn", "Manhattan", "Queens", "Staten Island")
val years = listOf(1980, 1990, 2000, 2010, 2020)
val colors =
listOf(
Color.hsv(0f, 1f, 0.7f),
Color.hsv(72f, 1f, 0.7f),
Color.hsv(144f, 1f, 0.7f),
Color.hsv(216f, 1f, 0.7f),
Color.hsv(288f, 1f, 0.7f)
) // 1 color per year
// Population data is in order of borough, then year
val population = listOf(
listOf(1168972, 1203789, 1332650, 1385108, 1446788), // Bronx
listOf(2230936, 2300664, 2465326, 2552911, 2648452), // Brooklyn
listOf(1428285, 1487536, 1537195, 1585873, 1638281), // Manhattan
listOf(1891325, 1951598, 2229379, 2250002, 2330295), // Queens
listOf(352121, 378977, 443728, 468730, 487155), // Staten Island
)
XYGraph(
xAxisModel = remember { CategoryAxisModel(boroughs) },
yAxisModel = rememberFloatLinearAxisModel(0f..3f, minorTickCount = 0),
yAxisTitle = "Population (Millions)"
) {
GroupedVerticalBarPlot {
years.indices.forEach {
series(solidBar(colors[it])) {
boroughs.forEachIndexed { index, borough ->
item(borough, 0f, population[index][it].toFloat() / 1E6f)
}
}
}
}
}
|
/examples/src/jvmMain/kotlin/io/github/koalaplot/example/GroupedVerticalBar1.ktMost of this example is establishing the data and the colors to use for each data series. The data series are the years, and the x-axis data values are the boroughs that make up the category axis. The key call is
GroupedVerticalBarPlot which initiates a builder API for the plot. Within that api, series
is used to add a new data series, which for this data are the years, and item
is used to add an item to the series at a specific x-axis value and with minimum and maximum y-axis values for the corresponding bar, in this case the population data.
In this example, a unique Composable to generate a bar is provided for each series. It is also possible to specify a bar Composable for the individual item as well, if it should be rendered differently than the other bars in the series.
Note
There are two overloaded variants of GroupedVerticalBarPlot
. The api builder described above, and a lower level variant that takes all of the plot data in a single parameter. The builder api delegates to the second variant, and depending on the initial form of the data to be plotted one form may be more convenient than the other.Last modified November 25, 2023:
Add bar plots section (51c53bb)