The various data visualization (DVT) graphs provided as part of the ADF Faces component set provide a very rich and comprehensive set of visualizations for representing your data. One of the issues with them, that some folks struggle with however, is the fact that not all the features are controlled in an a completely declarative manner.
In this article I want to concentrate on labeling capabilities for a graph axis, looking first of all that the declarative approaches, but then following that up with the more advanced programmatic option.
Managing Labels Declaritively
Control over the labels on the axis tick points is a good example of making the simple things declarative and the advanced things possible. For basic numeric formatting you can do everything with tags - for example formatting as currency, percentage or with a certain precision.
This is a default (bar)graph plotting employee salary against name, notice how the Y1 Axis has defaulted to a fairly sensible representation of the salary data using 0-14K:
I can change that default scaling by setting the scaling attribute in the <dvt:y1TickLabel> tag. This allows scaling at the level of none | thousand | million | billion | trillion | quadrillion (enough to show national debt then!):
<dvt:y1TickLabel id="y1TickLabel1" scaling="none"/>
Changes the graph to:
We can then further change the pattern of the numbers themselves by embedding <af:convertNumber> inside of the <dvt:y1TickLabel> tag.
e.g.
<dvt:y1TickLabel id="y1TickLabel1" scaling="none"><af:convertNumber type="currency" currencyCode="USD"/></dvt:y1TickLabel>
Adds currency formatting:
And using the <dvt:graphFont> we can change colors and style:
<dvt:y1TickLabel id="y1TickLabel1" scaling="none"> <dvt:graphFont name="SansSerif" size="8" color="#FF0000" bold="true" italic="true" /><af:convertNumber type="currency" currencyCode="USD"/></dvt:y1TickLabel>
Giving:
Need More Control? Using the TickLabelCallback...
So we can achieve quite a lot by simply using the tags. However, what about a more complex requirement such as replacing a numerical value on an axis with a totally different string e.g. converting to a Roman Numeral (I, IV XII etc.) or maybe converting a millisecond value to a formatted date string? To do this, ADF provides a simple callback that you can implement to map a value to whatever string you need. Here's a simple case where I've plotted the salaries in department 100 of the standard HR EMPLOYEES demo table against the HireDate on a scatter plot. For the sake of illustration I've actually converted the HireDate to it's time value (e.g. a long value representing the number of milliseconds since 01/01/1970) . In a real graph I'd use the proper support that we have for representing time and date and just map a date object. Then you get to use the timeSelector and can directly set the formatting, however, bear with me because I'm just illustrating the point here.
Here's the default output with the millisecond version of the date, as you can see the millisecond value gets automatically scaled to the billions level.
To override the default representation of the millisecond value we will need to create a java class that implements the oracle.dss.graph.TickLabelCallback interface. Here's the simple example I'll use in this case:
import java.text.SimpleDateFormat; import oracle.dss.graph.DataTickLabelInfo; import oracle.dss.graph.GraphConstants; import oracle.dss.graph.TickLabelCallback; import oracle.dss.graph.TickLabelInfo; public class MSToDateFormatLabelCallback implements TickLabelCallback, Serializable { @Override public String getTickLabel(TickLabelInfo tickLabelInfo, int axisID) { String label = null; if (axisID == GraphConstants.X1TICKLABEL) { long timeInMillis = (long) ((DataTickLabelInfo) tickLabelInfo).getValue(); SimpleDateFormat fmt = new SimpleDateFormat("MM/yy"); label = fmt.format(timeInMillis); } else { label = "" + ((DataTickLabelInfo) tickLabelInfo).getValue(); } return label; } }
As you can see the formatting is applied only to the specified axis and we have to upcast the tickLabelInfo argument to a DataTickLabelInfo in order to gain access to the value that is being applied. Note that the callback class must also be Serializable.
Once you have this class, then you need to apply it to the chart instance by calling the relevant set*TickLabelCallback. So for example I might set this in the backing bean for a page in the setter used by the binding attribute on the dvt graph component
public class GraphPageHandler { private UIGraph scatterPlot; public void setScatterPlot(UIGraph scatterPlot) { this.scatterPlot = scatterPlot; scatterPlot.setX1TickLabelCallback(new MSToDateFormatLabelCallback()); }
Now with the callback in place and the addition of:
- Using the axisMinValue attribute along with axisMinAutoScaled="false" on the <dvt:x1Axis> to reset the start date for the plot to the year 2000 rather than the default 1970
- Some of the currency formatting that we've already looked at to format the Y axis
Here's the result: