I want to display the x-axis labels at a 45 degree angle, similar to this
The examples I've found all assume that getDomainAxis() returns a CategoryAxis, which has a setCategoryLabelPositions() method. But in an XY Plot, I get a ValueAxis. There's a method for displaying the labels vertical, but not rotating at an arbitrary angle.
Looking at the code for ValueAxis.drawTickMarksAndLabels()
, there does seem to be mention of an angle on the ValueTick
object, but I'm not sure how to get access to that or where to set it
I had previously thought that ValueAxis
tick label orientation was limited by setVerticalTickLabels()
. In this discussion, you cite a forum topic that suggests a potential workaround.
As a proof of concept, based on this example, the variation below illustrates the approach using a custom implementation of refreshTicksHorizontal()
. Note:
The use of setVerticalTickLabels(true)
prompts the axis to reserve space for the labels.
For expedience, the rotation angle is hard-coded; it should probably be made a constructor parameter.
The approach was only tested with horizontal orientation.
As the chart theme had already been applied in the ChartFactory
, the example uses an AttributedString
to decorate the axis label.
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.font.TextAttribute;
import java.awt.geom.Rectangle2D;
import java.text.AttributedString;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.axis.DateTick;
import org.jfree.chart.axis.Tick;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.ui.RectangleEdge;
import org.jfree.data.time.Minute;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
/**
* @see https://stackoverflow.com/q/76574565/230513
* @see https://stackoverflow.com/q/70071299/230513
* @see https://stackoverflow.com/a/12481509/230513
* @see https://stackoverflow.com/a/12481509/230513
*/
public class TimeTest {
private static XYDataset createDataset() throws ParseException {
SimpleDateFormat f = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
TimeSeries series = new TimeSeries("Temperature");
series.add(new Minute(f.parse("Sat Nov 20 12:10:00 PST 2021")), 72.5);
series.add(new Minute(f.parse("Sat Nov 20 13:11:00 PST 2021")), 70.7);
series.add(new Minute(f.parse("Sat Nov 20 14:12:00 PST 2021")), 70.1);
return new TimeSeriesCollection(series);
}
private static JFreeChart createChart(final XYDataset dataset) {
SimpleDateFormat f = new SimpleDateFormat("HH:mm");
f.setTimeZone(TimeZone.getTimeZone("PST"));
JFreeChart chart = ChartFactory.createTimeSeriesChart
( "Test", "Time", "Temperture °F", dataset, true, true, false);
XYPlot plot = (XYPlot) chart.getPlot();
XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) plot.getRenderer();
r.setDefaultShapesVisible(true);
DateAxis domain = new DateAxis() {
//@see https://www.jfree.org/forum/viewtopic.php?t=25189
//todo paramterize angle
@Override
protected List refreshTicksHorizontal(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge) {
List ticks = super.refreshTicksHorizontal(g2, dataArea, edge);
List ret = new ArrayList();
for (Tick tick : (List<Tick>) ticks) {
if (tick instanceof DateTick dateTick) {
ret.add(new DateTick(dateTick.getDate(), dateTick.getText(),
dateTick.getTextAnchor(), dateTick.getRotationAnchor(), -45));
} else {
ret.add(tick);
}
}
return ret;
}
};
AttributedString as = new AttributedString("TimeN");
as.addAttribute(TextAttribute.SIZE, 16, 0, 5);
as.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, 0, 5);
as.addAttribute(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB, 4, 5);
domain.setAttributedLabel(as);
domain.setDateFormatOverride(f);
domain.setVerticalTickLabels(true);
plot.setDomainAxis(domain);
return chart;
}
public static void main(String[] args) throws ParseException {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
XYDataset dataset = createDataset();
JFreeChart chart = createChart(dataset);
ChartPanel chartPanel = new ChartPanel(chart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 250);
}
};
f.add(chartPanel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}