Charts
JavaFX comes with a handy set of charts to quickly display data visualizations. While there are more comprehensive charting libraries like JFreeChart and Orson Charts which work fine with TornadoFX, the built-in JavaFX charts satisfy a majority of visualization needs. They also have elegant animations when data is populated or changed.
TornadoFX comes with a few builders to streamline the declaration of charts using functional constructs.
PieChart
The PieChart
is a common visual aid to illustrate proportions of a whole. It is structurally simpler than XY charts which we will learn about later. Inside a piechart()
builder you can call the data()
function to pass multiple category-value pairs (Figure 8.1).
piechart("Desktop/Laptop OS Market Share") {
data("Windows", 77.62)
data("OS X", 9.52)
data("Other", 3.06)
data("Linux", 1.55)
data("Chrome OS", 0.55)
}
Figure 8.1
Note you can also provide an explicit ObservableList<PieChart.Data>
prepared in advance.
val items = listOf(
PieChart.Data("Windows", 77.62),
PieChart.Data("OS X", 9.52),
PieChart.Data("Other", 3.06),
PieChart.Data("Linux", 1.55),
PieChart.Data("Chrome OS", 0.55)
).observable()
piechart("Desktop/Laptop OS Market Share", items)
The block following piechart
can be used to modify any of the attributes of the PieChart
just like any other control builder we covered. You can also leverage for()
loops, Sequences, and other iterative tools within a block to add any number of data items.
val items = listOf(
PieChart.Data("Windows", 77.62),
PieChart.Data("OS X", 9.52),
PieChart.Data("Other", 3.06),
PieChart.Data("Linux", 1.55),
PieChart.Data("Chrome OS", 0.55)
).observable()
piechart("Desktop/Laptop OS Market Share") {
for (item in items) {
data.add(item)
}
}
Map-Based Data Sources
Sometimes you may want to build a chart using a Map
as a datasource. Using the Kotlin to
operator, you can construct a Map
in a Kotlin-esque way and then pass it to the data
function.
val items = mapOf(
"Windows" to 77.62,
"OS X" to 9.52,
"Other" to 3.06,
"Linux" to 1.55,
"Chrome OS" to 0.55
)
piechart("Desktop/Laptop OS Market Share") {
data(items)
}
XY Based Charts
Most charts often deal with one or more series of data points on an XY axis. The most common are bar and line charts.
Bar Charts
You can represent one or more series of data points through a BarChart
. This chart makes it easy to compare different data points relative to their distance from the X or Y axis (Figure 8.2).
barchart("Unit Sales Q2 2016", CategoryAxis(), NumberAxis()) {
series("Product X") {
data("MAR", 10245)
data("APR", 23963)
data("MAY", 15038)
}
series("Product Y") {
data("MAR", 28443)
data("APR", 22845)
data("MAY", 19045)
}
}
Figure 8.2
Above, the series()
and data()
functions allow quick construction of data structures backing the charts. On construction, you will need to construct the proper Axis
type for each X and Y axis. In this example, the months are not necessarily numeric but rather Strings. Therefore they are best represented by a CategoryAxis
. The units, already being numeric, are fit to use a NumberAxis
.
In the
series()
anddata()
blocks, you can customize further properties like colors. You can even callstyle()
to quickly apply type-safe CSS to the chart.
LineChart and AreaChart
A LineChart
connects data points on an XY axis with lines, quickly visualizing upward and downward trends between them (Figure 8.3)
linechart("Unit Sales Q2 2016", CategoryAxis(), NumberAxis()) {
series("Product X") {
data("MAR", 10245)
data("APR", 23963)
data("MAY", 15038)
}
series("Product Y") {
data("MAR", 28443)
data("APR", 22845)
data("MAY", 19045)
}
}
Figure 8.3
The backing data structure is not much different than a BarChart
, and you use the series()
and data()
functions in the same manner.
You can also use a variant of LineChart
called AreaChart
, which will shade the area under the lines a distinct color, as well as any overlaps (Figure 8.4).
Figure 8.4
Multiseries
You can streamline the declaration of more than one series using the multiseries()
function, and call the data()
functions with varargs
values. We can consolidate our previous example using this construct:
linechart("Unit Sales Q2 2016", CategoryAxis(), NumberAxis()) {
multiseries("Product X", "Product Y") {
data("MAR", 10245, 28443)
data("APR", 23963, 22845)
data("MAY", 15038, 19045)
}
}
This is just another convenience to reduce boilerplate and quickly declare your data structure for a chart.
ScatterChart
A ScatterChart
is the simplest representation of an XY data series. It plots the points without bars or lines. It is often used to plot a large volume of data points in order to find clusters. Here is a brief example of a ScatterChart
plotting machine capacities by week for two different product lines (Figure 8.5).
scatterchart("Machine Capacity by Product/Week", NumberAxis(), NumberAxis()) {
series("Product X") {
data(1,24)
data(2,22)
data(3,23)
data(4,19)
data(5,18)
}
series("Product Y") {
data(1,12)
data(2,15)
data(3,9)
data(4,11)
data(5,7)
}
}
Figure 8.5
BubbleChart
BubbleChart
is another XY chart similar to the ScatterPlot
, but there is a third variable to control the radius of each point. You can leverage this to show, for instance, output by week with the bubble radii reflecting number of machines used (Figure 8.6).
bubblechart("Machine Capacity by Output/Week", NumberAxis(), NumberAxis()) {
series("Product X") {
data(1,24,1)
data(2,46,2)
data(3,23,1)
data(4,27,2)
data(5,18,1)
}
series("Product Y") {
data(1,12,1)
data(2,31,2)
data(3,9,1)
data(4,11,1)
data(5,15,2)
}
}
Figure 8.6
Summary
Charts are a an effective way to visualize data, and the builders in TornadoFX help create them quickly. You can read more about JavaFX charts in Oracle's documentation. If you need more advanced charting functionality, there are libraries like JFreeChart and Orson Charts you can leverage and interop with TornadoFX, but this is beyond the scope of this book.