It turned out to be less difficult than expected, at least for some simple cases, since the calculations are more or less already implemented in the current version and needed only some very minor modification to make them run into the other direction. The approach simply consists in reverting the drawing process.
Here is the code for three methods.
The first one has to be placed in the XYPlot class. It receives a Graphics2D and a Rectangle2D as argument and expands the rectangle in-place with the space required for the plot insets, the plot border, and the axis space.
The second one belongs to the JFreeChart class. It also receives a graphics and rectangle parameter. The rectangle is expanded by the chart insets and the space required by the titles. A proper consideration of the space for the titles simply required to iterate over the titles list in reverse order. The third method is just a helper for the second. If a given rectangle is expanded consecutively with these two methods, it can be used as rectangle parameter to draw a JFreeChart which will then have the original rectangle as data area.
At present, the code only cares about the rectangle size, i. e. the rectangle is only expanded to the left and bottom but it should be possible to also care about the position. This could be a way to not only give different plots of different charts the same size but also to align them in a certain way in a suitable container.
Here is the code. I would be happy to know if somebody else has also worked on this and has an altenative/better solution.
The same approach should also work for CategoryPlots but I have not yet checked that.
XYPlot method
Code: Select all
public void expandDataToPlotArea(Graphics2D g2, Rectangle2D dataArea) {
AxisSpace domainSpace = new AxisSpace();
AxisSpace rangeSpace = new AxisSpace();
domainSpace = calculateDomainAxisSpace(g2, dataArea, null);
rangeSpace = calculateRangeAxisSpace(g2, dataArea, null);
double leftRightOffset;
double topBottomOffset;
if(orientation.equals(PlotOrientation.VERTICAL)){
leftRightOffset = rangeSpace.getLeft()+rangeSpace.getRight();
topBottomOffset = domainSpace.getTop()+domainSpace.getBottom();
}
else{
leftRightOffset = domainSpace.getLeft()+domainSpace.getRight();
topBottomOffset = rangeSpace.getTop()+rangeSpace.getBottom();
}
if(isOutlineVisible()){
leftRightOffset += 2;
topBottomOffset += 2;
}
leftRightOffset = leftRightOffset + getInsets().getLeft() + getInsets().getRight();
topBottomOffset = topBottomOffset + getInsets().getTop() + getInsets().getBottom();
dataArea.setRect(dataArea.getX(),dataArea.getY(),dataArea.getWidth()+leftRightOffset,dataArea.getHeight()+topBottomOffset);
//return plotArea;
}
Code: Select all
public void expandPlotToChartArea(Graphics2D g2,Rectangle2D plotArea){
for(int ti = subtitles.size()-1 ; ti>=0 ; ti--){
Title currentTitle = (Title)(subtitles.get(ti));
if(currentTitle.isVisible()){
expandWithTitleArea(g2,plotArea,currentTitle);
}
}
if (this.title != null && this.title.isVisible()) {
expandWithTitleArea(g2,plotArea,this.title);
}
plotArea.setRect(plotArea.getX(),plotArea.getY(),plotArea.getWidth()+padding.getLeft()+padding.getRight(),plotArea.getHeight()+padding.getTop()+padding.getBottom());
}
Code: Select all
private void expandWithTitleArea(Graphics2D g2,Rectangle2D rect, Title title){
Rectangle2D titleArea = new Rectangle2D.Double();
RectangleEdge position = title.getPosition();
double ww = rect.getWidth();
double hh = rect.getHeight();
double width = rect.getWidth();
double height = rect.getHeight();
RectangleConstraint constraint = new RectangleConstraint(ww,
new Range(0.0, ww), LengthConstraintType.RANGE, hh,
new Range(0.0, hh), LengthConstraintType.RANGE);
if (position == RectangleEdge.TOP) {
Size2D size = title.arrange(g2, constraint);
titleArea = createAlignedRectangle2D(size, rect,
title.getHorizontalAlignment(), VerticalAlignment.TOP);
height += size.height;
}
else if (position == RectangleEdge.BOTTOM) {
Size2D size = title.arrange(g2, constraint);
titleArea = createAlignedRectangle2D(size, rect,
title.getHorizontalAlignment(), VerticalAlignment.BOTTOM);
height += size.height;
}
else if (position == RectangleEdge.RIGHT) {
Size2D size = title.arrange(g2, constraint);
titleArea = createAlignedRectangle2D(size, rect,
HorizontalAlignment.RIGHT, title.getVerticalAlignment());
width += size.width;
}
else if (position == RectangleEdge.LEFT) {
Size2D size = title.arrange(g2, constraint);
titleArea = createAlignedRectangle2D(size, rect,
HorizontalAlignment.LEFT, title.getVerticalAlignment());
width += size.width;
}
rect.setRect(rect.getX(), rect.getY(), width, height);
}
Code: Select all
import java.awt.geom.Rectangle2D;
import java.awt.geom.Rectangle2D.Double;
import java.awt.Font;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.io.File;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.xy.DefaultXYDataset;
import org.jfree.ui.RectangleEdge;
public class QuadraticPlotDemo {
public static void main(String[] args) {
double[][] values = new double[][]{{1,2,3,4,5},{10,15,8,37,23}};
DefaultXYDataset set = new DefaultXYDataset();
set.addSeries("Values",values);
JFreeChart chart = ChartFactory.createScatterPlot(
"Quadratic Demo","x","y",set,PlotOrientation.VERTICAL,true, true, false);
//chart.getLegend().setPosition(RectangleEdge.LEFT);
TextTitle big = new TextTitle("Long title in a big font",new Font("SansSerif",1,36));
big.setPosition(RectangleEdge.RIGHT);
chart.addSubtitle(big);
TextTitle small = new TextTitle("An even longer title than the first one but with a smaller font",new Font("SansSerif",1,24));
small.setPosition(RectangleEdge.LEFT);
chart.addSubtitle(small);
//chart.getXYPlot().setOrientation(PlotOrientation.HORIZONTAL);
BufferedImage image = new BufferedImage(400,800,BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2 = image.createGraphics();
Rectangle2D rect = new Rectangle2D.Double(0,0,600,600.0);
chart.getXYPlot().expandDataToPlotArea(g2,rect);
chart.expandPlotToChartArea(g2,rect);
Rectangle2D drawer = new Rectangle2D.Double(0,0,rect.getWidth()-rect.getX(),rect.getHeight()-rect.getY());
System.out.println(rect.toString());
try{
ChartUtilities.saveChartAsPNG(new File("export.png"),chart,(int)rect.getWidth(),(int)rect.getHeight());
}
catch(Exception e){
e.printStackTrace();
}
}
}