JFreeChart Fixed range axis ticks
I am trying to generate a line chart but I cannot figure out how to
a) setup the range axis with fixed ticks for 0.001, 0.01, 0.1, 1, 10 and 100
b) display only those ticks in the graph
c) Custom label those ticks (which can only be addressed after a and b).
I am trying to use a SymbolAxis but I cannot get it working.
This is what I am after:
Solution 1:
After some experimentation. Following example
public static void main(String[] args) {
//setting up my ticks
final TickUnits standardUnits = new TickUnits();
standardUnits.add(new NumberTickUnit(0.001));
standardUnits.add(new NumberTickUnit(0.01));
standardUnits.add(new NumberTickUnit(0.1));
standardUnits.add(new NumberTickUnit(1));
standardUnits.add(new NumberTickUnit(10));
standardUnits.add(new NumberTickUnit(100));
//data
XYSeries series = new XYSeries("Series");
series.add(0, 130);
series.add(1, 0.35);
series.add(2, 0.021);
series.add(3, 0.0042);
series.add(4, 0.002);
series.add(5, 0.003);
series.add(6, 10130);
NumberAxis xAxis = new NumberAxis("X");
xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
LogAxis yAxis = new LogAxis("Y");
yAxis.setBase(10);
yAxis.setNumberFormatOverride(new DecimalFormat());
yAxis.setRange(0.001, 100);
yAxis.setStandardTickUnits(standardUnits); // NumberAxis.createIntegerTickUnits());
XYPlot plot = new XYPlot(new XYSeriesCollection(series), xAxis, yAxis, new XYLineAndShapeRenderer(true, false));
JFreeChart chart = new JFreeChart("Chart", JFreeChart.DEFAULT_TITLE_FONT, plot, false);
JFrame frame = new JFrame("LogAxis Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new ChartPanel(chart));
frame.pack();
frame.setVisible(true);
}
Solution 2:
This approach illustrates using a LogAxis
with integer tick units, as suggested here. The particular set of tick units shown is sometimes warranted, but a more general solution is seen in the variation below; it relies on the TickUnitSource
created by NumberAxis
:
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
Moreover,
-
As discussed here, absent a
ChartFactory
, a suitableChartTheme
"establishes coherent defaults for elements that affect geometry, such as font metrics and axis offsets." -
As mentioned here, it is essential to construct and manipulate Swing GUI objects only on the event dispatch thread.
-
As shown here,
NumberFormat.getNumberInstance()
is an alternative toDecimalFormat
.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.text.NumberFormat;
import javax.swing.JFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.LogAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public class LogTest {
/**
* @see https://stackoverflow.com/a/70648615/230513
* @see https://stackoverflow.com/a/10353270/230513
*/
private void display() {
XYSeries series = new XYSeries("Series");
series.add(0, 130);
series.add(1, 0.35);
series.add(2, 0.021);
series.add(3, 0.0042);
series.add(4, 0.002);
series.add(5, 0.003);
series.add(6, 10130);
NumberAxis xAxis = new NumberAxis("X");
xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
LogAxis yAxis = new LogAxis("Y");
yAxis.setBase(10);
yAxis.setNumberFormatOverride(NumberFormat.getNumberInstance());
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
XYPlot plot = new XYPlot(new XYSeriesCollection(series),
xAxis, yAxis, new XYLineAndShapeRenderer(true, false));
JFreeChart chart = new JFreeChart("Chart",
JFreeChart.DEFAULT_TITLE_FONT, plot, false);
StandardChartTheme theme = new StandardChartTheme("Custom");
theme.setPlotBackgroundPaint(Color.WHITE);
theme.setChartBackgroundPaint(new GradientPaint(
0, 0, Color.WHITE, 0, 480, new Color(0xB8C8E0)));
theme.apply(chart);
JFrame f = new JFrame("LogAxis Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new ChartPanel(chart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
});
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new LogTest()::display);
}
}