mardi 19 juin 2012

Logarithmic scale strikes back in JavaFX 2.0

JavaFX provides an impressive chart API that allows to draw a wide range of charts. Unfortunately the only available scale for XY charts is a linear implementation.
As we did it two years ago for javafx 1, we defined the logarithmic axis for javafx 2.
We received some requests of developpers who need to use a logarithmic axis but thay are confronted to the understanding of how axis works in javafx 2 and the impossibility to extend the NumberAxis, since it’s final in the API. So the only way to have a logarithmic axis is to extend directly the ValueAxis abstract class. Below, we’ll see how to implement all required methods to make it works. At the end you’ll be able to have this kind of chart :
So let’s create our LogarithmicAxis class that extends ValueAxis and define two properties that will represent the log lower and upper bounds of our axis. 


Then we bind our properties with the default bounds of the value axis. But before, we should verify the given range according to the mathematic logarithmic interval definition.


Now we have to implement all abstract methods of the ValueAxis class.
The first one, calculateMinorTickMarks is used to get the list of minor tick marks position that you want to display on the axis. You could find my definition below. It’s based on the number of minor tick and the logarithmic formula.


Then, the calculateTickValues method is used to calculate a list of all the data values for each tick mark in range, represented by the second parameter. The formula is the same than previously but here we want to display one tick each power of 10.


The getRange provides the current range of the axis. A basic implementation is to return an array of the lowerBound and upperBound properties defined into the ValueAxis class.


The getTickMarkLabel is only used to convert the number value to a string that will be displayed under the tickMark. Here I choose to use a number formatter.


The method setRange is used to update the range when data are added into the chart. There is two possibilities, the axis is animated or not. The simplest case is to set the lower and upper bound properties directly with the new values.


In order to have an animated axis, we should declare two timelines that will set progressively the range and use them if the animate parameter is true.



We are almost done but we forgot to override 3 important methods that are used to perform auto-ranging and the matching between data and the axis (and the reverse).


Well it’s done! I hope that this article will help you to define your own logarithmic axis and don’t hesitate to give me your feedback on this implementation.
Full code is available here :


3 commentaires:

  1. This just what I needed (I tweaked it for log base 2). But I am working with data that starts smaller than 1 and works its way up. Could you please provide some guidance on how to get axis tick labels smaller than one? (e.g. a label at 1/16, 1/8, 1/2, etc) Thanks!

    RépondreSupprimer
  2. I found a (very simple) solution. Initialize i in the outer loop in calculateTickValues to a negative number (-2 or -3 works well). The negative exponent results in some nice fractional values for the first few tick marks.

    RépondreSupprimer
  3. Thank you for sharing your solution!

    RépondreSupprimer