I am trying to get a JFreeChart ChartPanel
to remove unwanted extra space between the edge of the panel and the graph itself.
To best illustrate, here's a SSCCE (with JFreeChart installed):
public static void main(String[] args) {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.gridy = 1;
gbc.gridx = 1;
panel.add(createChart("Sales", Chart_Type.DOLLARS, 100000, 115000), gbc);
gbc.gridx = 2;
panel.add(createChart("Quotes", Chart_Type.DOLLARS, 250000, 240000), gbc);
gbc.gridx = 3;
panel.add(createChart("Profits", Chart_Type.PERCENTAGE, 40.00, 38.00), gbc);
JFrame frame = new JFrame();
frame.add(panel);
frame.setSize(800, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private static ChartPanel createChart(String title, Chart_Type type, double goal, double actual) {
double maxValue = goal * 2;
double yellowToGreenNum = goal;
double redToYellowNum = goal * .75;
DefaultValueDataset dataset = new DefaultValueDataset(actual);
JFreeChart jfreechart = createChart(dataset, Math.max(actual, maxValue), redToYellowNum, yellowToGreenNum, title, type);
ChartPanel chartPanel = new ChartPanel(jfreechart);
chartPanel.setBorder(new LineBorder(Color.red));
return chartPanel;
}
private static JFreeChart createChart(ValueDataset valuedataset, Number maxValue, Number redToYellowNum, Number yellowToGreenNum, String title, Chart_Type type) {
MeterPlot meterplot = new MeterPlot(valuedataset);
meterplot.setRange(new Range(0.0D, maxValue.doubleValue()));
meterplot.addInterval(new MeterInterval(" Goal Not Met ",
new Range(0.0D, redToYellowNum.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
new Color(255, 0, 0, 128)));
meterplot.addInterval(new MeterInterval(" Goal Almost Met ",
new Range(redToYellowNum.doubleValue(), yellowToGreenNum.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
new Color(255, 255, 0, 64)));
meterplot.addInterval(new MeterInterval(" Goal Met ",
new Range(yellowToGreenNum.doubleValue(), maxValue.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
new Color(0, 255, 0, 64)));
meterplot.setNeedlePaint(Color.darkGray);
meterplot.setDialBackgroundPaint(Color.white);
meterplot.setDialOutlinePaint(Color.gray);
meterplot.setDialShape(DialShape.CHORD);
meterplot.setMeterAngle(260);
meterplot.setTickLabelsVisible(false);
meterplot.setTickSize(maxValue.doubleValue() / 20);
meterplot.setTickPaint(Color.lightGray);
meterplot.setValuePaint(Color.black);
meterplot.setValueFont(new Font("Dialog", Font.BOLD, 0));
meterplot.setUnits("");
if(type == Chart_Type.DOLLARS)
meterplot.setTickLabelFormat(NumberFormat.getCurrencyInstance());
else if(type == Chart_Type.PERCENTAGE)
meterplot.setTickLabelFormat(NumberFormat.getPercentInstance());
JFreeChart jfreechart = new JFreeChart(title,
JFreeChart.DEFAULT_TITLE_FONT, meterplot, false);
return jfreechart;
}
enum Chart_Type {
DOLLARS,
PERCENTAGE
}
If you resize the frame, you can see that you cannot make the edge of the graph go to the edge of the panel (the panels are outlined in red). Especially on the bottom - there is always a gap between the bottom the graph and the bottom of the panel.
Is there a way to make the graph fill the entire area? Is there a way to at least guarantee that it is touching one edge of the panel (i.e., it is touching the top and bottom or the left and right) ??
For reference, without changing the plot, here's the result with the following settings:
Calling pack()
on the enclosing frame.
Using a no-gap GridLayout
.
Returning an equilateral preferred size.
setMeterAngle(360);
.
setDrawBorder(true);
Resizing to a non-square aspect fills the narrower dimension.
Addendum: As shown here, you can override the chart's draw()
method. For improved resizing behavior in the variation below, the plot's draw()
method is overridden to shift the area
by a fraction of its height. A function based on getMeterAngle()
may also be useful.
MeterPlot meterplot = new MeterPlot(valuedataset) {
@Override
public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, PlotState parentState, PlotRenderingInfo info) {
double h = area.getHeight() * 6 / 5;
area.setRect(area.getX(), area.getY(), area.getWidth(), h);
super.draw(g2, area, anchor, parentState, info);
}
};
Updated code:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.DialShape;
import org.jfree.chart.plot.MeterInterval;
import org.jfree.chart.plot.MeterPlot;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.PlotState;
import org.jfree.data.Range;
import org.jfree.data.general.DefaultValueDataset;
import org.jfree.data.general.ValueDataset;
//* @see https://stackoverflow.com/a/25416067/230513 */
public class Test {
public static void main(String[] args) {
JPanel panel = new JPanel(new GridLayout());
panel.add(createChart("Sales", Chart_Type.DOLLARS, 100000, 115000));
panel.add(createChart("Quotes", Chart_Type.DOLLARS, 250000, 240000));
panel.add(createChart("Profits", Chart_Type.PERCENTAGE, 40.00, 38.00));
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static ChartPanel createChart(String title, Chart_Type type, double goal, double actual) {
double maxValue = goal * 2;
double yellowToGreenNum = goal;
double redToYellowNum = goal * .75;
DefaultValueDataset dataset = new DefaultValueDataset(actual);
JFreeChart jfreechart = createChart(dataset, Math.max(actual, maxValue), redToYellowNum, yellowToGreenNum, title, type);
ChartPanel chartPanel = new ChartPanel(jfreechart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
chartPanel.setBorder(new LineBorder(Color.red));
return chartPanel;
}
private static JFreeChart createChart(ValueDataset valuedataset, Number maxValue, Number redToYellowNum, Number yellowToGreenNum, String title, Chart_Type type) {
MeterPlot meterplot = new MeterPlot(valuedataset) {
@Override
public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, PlotState parentState, PlotRenderingInfo info) {
double h = area.getHeight() * 6 / 5;
area.setRect(area.getX(), area.getY(), area.getWidth(), h);
super.draw(g2, area, anchor, parentState, info);
}
};
meterplot.setRange(new Range(0.0D, maxValue.doubleValue()));
meterplot.addInterval(new MeterInterval(" Goal Not Met ",
new Range(0.0D, redToYellowNum.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
new Color(255, 0, 0, 128)));
meterplot.addInterval(new MeterInterval(" Goal Almost Met ",
new Range(redToYellowNum.doubleValue(), yellowToGreenNum.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
new Color(255, 255, 0, 64)));
meterplot.addInterval(new MeterInterval(" Goal Met ",
new Range(yellowToGreenNum.doubleValue(), maxValue.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
new Color(0, 255, 0, 64)));
meterplot.setNeedlePaint(Color.darkGray);
meterplot.setDialBackgroundPaint(Color.white);
meterplot.setDialOutlinePaint(Color.gray);
meterplot.setDialShape(DialShape.CHORD);
meterplot.setMeterAngle(260);
meterplot.setTickLabelsVisible(false);
meterplot.setTickSize(maxValue.doubleValue() / 20);
meterplot.setTickPaint(Color.lightGray);
meterplot.setValuePaint(Color.black);
meterplot.setValueFont(new Font("Dialog", Font.BOLD, 0));
meterplot.setUnits("");
if (type == Chart_Type.DOLLARS) {
meterplot.setTickLabelFormat(NumberFormat.getCurrencyInstance());
} else if (type == Chart_Type.PERCENTAGE) {
meterplot.setTickLabelFormat(NumberFormat.getPercentInstance());
}
meterplot.setDrawBorder(true);
meterplot.setDialShape(DialShape.CHORD);
JFreeChart jfreechart = new JFreeChart(title,
JFreeChart.DEFAULT_TITLE_FONT, meterplot, false);
return jfreechart;
}
enum Chart_Type {
DOLLARS,
PERCENTAGE
}
}