我有一个JFreeChart
图表,以DateAxis
为域。它看起来很好,但是最后一个轴标签有时会离开图表区域。下面是要重现的示例代码:
public class LineChart_AWT extends ApplicationFrame {
public LineChart_AWT( String applicationTitle , String chartTitle ) {
super(applicationTitle);
ValueAxis timeAxis = new DateAxis("");
NumberAxis valueAxis = new NumberAxis("Number");
((DateAxis)timeAxis).setDateFormatOverride(new SimpleDateFormat("YYYY-MM-dd HH:mm"));
XYPlot plot = new XYPlot(createDataset(), timeAxis, valueAxis, null);
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, false);
plot.setRenderer(renderer);
plot.getRangeAxis().setAutoRange(true);
((NumberAxis)plot.getRangeAxis()).setAutoRangeIncludesZero(false);
JFreeChart lineChart = new JFreeChart(chartTitle, plot);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinesVisible(true);
plot.setRangeGridlinesVisible(true);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
lineChart.setBackgroundPaint(Color.white);
ChartPanel chartPanel = new ChartPanel( lineChart );
chartPanel.setPreferredSize( new java.awt.Dimension( 560 , 367 ) );
setContentPane( chartPanel );
}
private TimeSeriesCollection createDataset( ) {
TimeSeries typeA = new TimeSeries("TypeA");
TimeSeries typeB = new TimeSeries("TypeB");
TimeSeriesCollection collection = new TimeSeriesCollection();
collection.addSeries(typeA);
collection.addSeries(typeB);
typeA = collection.getSeries("TypeA");
typeA.add(new Hour(8, new Day()), 1.0);
typeA.add(new Hour(10, new Day()), 1.0);
typeA.add(new Hour(11, new Day()), 1.0);
typeA.add(new Hour(13, new Day()), 1.0);
typeA.add(new Hour(16, new Day()), 2.0);
typeA.add(new Hour(18, new Day()), 2.0);
typeB.add(new Hour(8, new Day()), 1.0);
typeB.add(new Hour(19, new Day()), 2.0);
typeB.add(new Hour(20, new Day()), 5.0);
return collection;
}
public static void main( String[ ] args ) {
LineChart_AWT chart = new LineChart_AWT(
"X-axis demo" ,
"X-axis labels are truncated");
chart.pack( );
RefineryUtilities.centerFrameOnScreen( chart );
chart.setVisible( true );
}
}
以下是当前的截图;问题可以在最后一个标签上看到:
是什么原因导致最后一个标签呈现在当前图表区域之外?还有,我该如何预防呢?
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.text.SimpleDateFormat;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.data.time.Minute;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
/**
* @see https://stackoverflow.com/a/57637615/230513
* @see https://stackoverflow.com/a/57544811/230513
*/
public class TimeChart extends ApplicationFrame {
private static boolean lot_of_values = false;
public TimeChart(String applicationTitle, String chartTitle) {
super(applicationTitle);
DateAxis timeAxis = new DateAxis("Timestamp");
timeAxis.setUpperMargin(DateAxis.DEFAULT_UPPER_MARGIN /* * 2*/); // UPDATED
timeAxis.setLowerMargin(DateAxis.DEFAULT_LOWER_MARGIN /* * 2*/); // UPDATED
timeAxis.setDateFormatOverride(new SimpleDateFormat("YYYY-MM-dd HH:mm"));
NumberAxis numberAxis = new NumberAxis("Number");
numberAxis.setAutoRangeIncludesZero(false);
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, false);
XYPlot plot = new XYPlot(createDataset(), timeAxis, numberAxis, renderer);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
JFreeChart lineChart = new JFreeChart(chartTitle, plot);
lineChart.setBackgroundPaint(Color.white);
ChartPanel chartPanel = new ChartPanel(lineChart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(1529 , 538);
}
};
add(chartPanel);
}
private TimeSeriesCollection createDataset() {
TimeSeries typeA = new TimeSeries("Temperatures");
TimeSeriesCollection collection = new TimeSeriesCollection();
collection.addSeries(typeA);
if (lot_of_values) {
typeA.add(Minute.parseMinute("2019-08-25 00:00"), 26.68);
typeA.add(Minute.parseMinute("2019-08-25 01:00"), 26.75);
typeA.add(Minute.parseMinute("2019-08-25 02:00"), 25.95);
typeA.add(Minute.parseMinute("2019-08-25 03:00"), 25.47);
typeA.add(Minute.parseMinute("2019-08-25 04:00"), 25.19);
typeA.add(Minute.parseMinute("2019-08-25 05:00"), 24.65);
typeA.add(Minute.parseMinute("2019-08-25 06:00"), 24.61);
typeA.add(Minute.parseMinute("2019-08-25 07:00"), 25.58);
typeA.add(Minute.parseMinute("2019-08-25 08:00"), 26.43);
typeA.add(Minute.parseMinute("2019-08-25 09:00"), 26.96);
typeA.add(Minute.parseMinute("2019-08-25 10:00"), 27.81);
typeA.add(Minute.parseMinute("2019-08-25 11:00"), 28.69);
typeA.add(Minute.parseMinute("2019-08-25 12:00"), 29.39);
typeA.add(Minute.parseMinute("2019-08-25 13:00"), 29.89);
typeA.add(Minute.parseMinute("2019-08-25 14:00"), 30.32);
typeA.add(Minute.parseMinute("2019-08-25 15:00"), 30.69);
typeA.add(Minute.parseMinute("2019-08-25 16:00"), 30.83);
typeA.add(Minute.parseMinute("2019-08-25 17:00"), 30.85);
typeA.add(Minute.parseMinute("2019-08-25 18:00"), 30.64);
typeA.add(Minute.parseMinute("2019-08-25 19:00"), 30.04);
typeA.add(Minute.parseMinute("2019-08-25 20:00"), 29.51);
typeA.add(Minute.parseMinute("2019-08-25 21:00"), 28.63);
typeA.add(Minute.parseMinute("2019-08-25 22:00"), 28.48);
typeA.add(Minute.parseMinute("2019-08-25 23:00"), 27.15);
typeA.add(Minute.parseMinute("2019-08-26 00:00"), 27.3);
typeA.add(Minute.parseMinute("2019-08-26 01:00"), 27.05);
typeA.add(Minute.parseMinute("2019-08-26 02:00"), 26.84);
typeA.add(Minute.parseMinute("2019-08-26 03:00"), 26.47);
typeA.add(Minute.parseMinute("2019-08-26 04:00"), 26.34);
typeA.add(Minute.parseMinute("2019-08-26 05:00"), 25.95);
typeA.add(Minute.parseMinute("2019-08-26 06:00"), 26.46);
typeA.add(Minute.parseMinute("2019-08-26 07:00"), 26.75);
typeA.add(Minute.parseMinute("2019-08-26 08:00"), 26.94);
typeA.add(Minute.parseMinute("2019-08-26 09:00"), 27.05);
typeA.add(Minute.parseMinute("2019-08-26 10:00"), 27.35);
typeA.add(Minute.parseMinute("2019-08-26 11:00"), 27.67);
typeA.add(Minute.parseMinute("2019-08-26 12:00"), 28.12);
typeA.add(Minute.parseMinute("2019-08-26 13:00"), 28.41);
typeA.add(Minute.parseMinute("2019-08-26 14:00"), 28.67);
typeA.add(Minute.parseMinute("2019-08-26 15:00"), 28.99);
typeA.add(Minute.parseMinute("2019-08-26 16:00"), 28.99);
typeA.add(Minute.parseMinute("2019-08-26 17:00"), 29.02);
typeA.add(Minute.parseMinute("2019-08-26 18:00"), 29.02);
typeA.add(Minute.parseMinute("2019-08-26 19:00"), 28.43);
typeA.add(Minute.parseMinute("2019-08-26 20:00"), 27.87);
typeA.add(Minute.parseMinute("2019-08-26 21:00"), 27.2);
typeA.add(Minute.parseMinute("2019-08-26 22:00"), 26.88);
typeA.add(Minute.parseMinute("2019-08-26 23:00"), 26.31);
typeA.add(Minute.parseMinute("2019-08-27 00:00"), 26.02);
typeA.add(Minute.parseMinute("2019-08-27 01:00"), 25.51);
typeA.add(Minute.parseMinute("2019-08-27 02:00"), 25.12);
typeA.add(Minute.parseMinute("2019-08-27 03:00"), 25.11);
typeA.add(Minute.parseMinute("2019-08-27 04:00"), 24.97);
typeA.add(Minute.parseMinute("2019-08-27 05:00"), 24.85);
typeA.add(Minute.parseMinute("2019-08-27 06:00"), 24.73);
typeA.add(Minute.parseMinute("2019-08-27 07:00"), 25.04);
typeA.add(Minute.parseMinute("2019-08-27 08:00"), 25.68);
typeA.add(Minute.parseMinute("2019-08-27 09:00"), 26.22);
typeA.add(Minute.parseMinute("2019-08-27 10:00"), 26.69);
typeA.add(Minute.parseMinute("2019-08-27 11:00"), 27.3);
typeA.add(Minute.parseMinute("2019-08-27 12:00"), 27.84);
typeA.add(Minute.parseMinute("2019-08-27 13:00"), 28.26);
typeA.add(Minute.parseMinute("2019-08-27 14:00"), 28.6);
typeA.add(Minute.parseMinute("2019-08-27 15:00"), 29.03);
typeA.add(Minute.parseMinute("2019-08-27 16:00"), 29.38);
typeA.add(Minute.parseMinute("2019-08-27 17:00"), 29.62);
typeA.add(Minute.parseMinute("2019-08-27 18:00"), 29.47);
typeA.add(Minute.parseMinute("2019-08-27 19:00"), 29.01);
typeA.add(Minute.parseMinute("2019-08-27 20:00"), 28.31);
typeA.add(Minute.parseMinute("2019-08-27 21:00"), 27.69);
typeA.add(Minute.parseMinute("2019-08-27 22:00"), 26.93);
typeA.add(Minute.parseMinute("2019-08-27 23:00"), 26.37);
}
typeA.add(Minute.parseMinute("2019-08-28 00:00"), 26.12);
typeA.add(Minute.parseMinute("2019-08-28 01:00"), 25.77);
typeA.add(Minute.parseMinute("2019-08-28 02:00"), 25.42);
typeA.add(Minute.parseMinute("2019-08-28 03:00"), 25.0);
typeA.add(Minute.parseMinute("2019-08-28 04:00"), 24.57);
typeA.add(Minute.parseMinute("2019-08-28 05:00"), 24.23);
typeA.add(Minute.parseMinute("2019-08-28 06:00"), 24.38);
typeA.add(Minute.parseMinute("2019-08-28 07:00"), 24.99);
typeA.add(Minute.parseMinute("2019-08-28 08:00"), 25.86);
typeA.add(Minute.parseMinute("2019-08-28 09:00"), 26.53);
typeA.add(Minute.parseMinute("2019-08-28 10:00"), 27.32);
typeA.add(Minute.parseMinute("2019-08-28 11:00"), 27.95);
typeA.add(Minute.parseMinute("2019-08-28 12:00"), 28.64);
typeA.add(Minute.parseMinute("2019-08-28 13:00"), 29.38);
typeA.add(Minute.parseMinute("2019-08-28 14:00"), 29.74);
typeA.add(Minute.parseMinute("2019-08-28 15:00"), 30.13);
typeA.add(Minute.parseMinute("2019-08-28 16:00"), 30.42);
typeA.add(Minute.parseMinute("2019-08-28 17:00"), 30.48);
typeA.add(Minute.parseMinute("2019-08-28 18:00"), 30.14);
typeA.add(Minute.parseMinute("2019-08-28 19:00"), 29.41);
typeA.add(Minute.parseMinute("2019-08-28 20:00"), 28.47);
typeA.add(Minute.parseMinute("2019-08-28 21:00"), 28.05);
return collection;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
TimeChart chart = new TimeChart(
"Date axis demo",
"Date axis labels are visible");
chart.pack();
chart.setVisible(true);
}
});
}
}
但是,如果我将lot_of_values更改为true(这将向集合中添加更多数据-您可以在源代码中看到),那么域轴的最后一个标签将被剪切。下面是lot_of_values=true的截图:
我已经深入研究了JFreeChart的源代码,并且正在解决这个问题。(我还不得不从上面的源代码中删除一些行,以适应30K字符的限制)
我认为边距值应用于图表当前数据绘制之前和之后,而不是应用于当前范围刻度。这就是为什么最后一个滴答标签可以被剪掉的原因。
typeA.add(Minute.parseMinute("2019-08-28 21:00"), 28.05); //original line
typeA.add(Minute.parseMinute("2019-08-28 22:00"), 28.05); //new line
typeA.add(Minute.parseMinute("2019-08-28 23:00"), 28.05); //new line
typeA.add(Minute.parseMinute("2019-08-29 00:00"), 28.05); //new line
这也可以通过修改轴的最大日期来实现,方法是调用:
timeAxis.setMaximumDate(new Date(119,7,29,4,36));
现在我将继续寻找这个MaximumDate的计算位置。如果有人知道,请告诉我。
这种效果是人为地减小图表的首选大小,同时显式地增加日期轴刻度标签的大小造成的。注意,省略对setPreferredSize()
的调用可以消除这种影响。或者,您可以将轴边距设置为补偿,如这里所建议的那样。下面的示例将默认的上下边距加倍,从滴答间隔的10%增加到20%。
timeAxis.setUpperMargin(DateAxis.DEFAULT_UPPER_MARGIN * 2);
timeAxis.setLowerMargin(DateAxis.DEFAULT_LOWER_MARGIN * 2);
更确切地说:它是针对这些标签长度的最终解决方案,还是针对当前情况的特定黑客攻击?
DateAxis
使用标签的计算大小使标签在其刻度线/网格线上居中。因为字体大小因平台而异,标签大小因格式和区域设置而异,所以总是有一些值的组合可以为给定的封装组件大小剪辑标签。当组件调整大小时,显示的标签数量将改变以优化显示。只要您允许图表随着大小的变化而调整,这里讨论过,用户就不会有麻烦了。调整示例框架的大小或使用这些内置控件查看效果。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.text.SimpleDateFormat;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.chart.ui.UIUtils;
import org.jfree.data.time.Day;
import org.jfree.data.time.Hour;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
/**
* @see https://stackoverflow.com/a/57637615/230513
* @see https://stackoverflow.com/a/57544811/230513
*/
public class TimeChart extends ApplicationFrame {
public TimeChart(String applicationTitle, String chartTitle) {
super(applicationTitle);
DateAxis timeAxis = new DateAxis("Timestamp");
timeAxis.setUpperMargin(DateAxis.DEFAULT_UPPER_MARGIN * 2);
timeAxis.setLowerMargin(DateAxis.DEFAULT_LOWER_MARGIN * 2);
timeAxis.setDateFormatOverride(new SimpleDateFormat("YYYY-MM-dd HH:mm"));
NumberAxis numberAxis = new NumberAxis("Number");
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, false);
XYPlot plot = new XYPlot(createDataset(), timeAxis, numberAxis, renderer);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
JFreeChart lineChart = new JFreeChart(chartTitle, plot);
lineChart.setBackgroundPaint(Color.white);
ChartPanel chartPanel = new ChartPanel(lineChart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(560 , 367);
}
};
add(chartPanel);
}
private TimeSeriesCollection createDataset() {
TimeSeries typeA = new TimeSeries("TypeA");
TimeSeries typeB = new TimeSeries("TypeB");
TimeSeriesCollection collection = new TimeSeriesCollection();
collection.addSeries(typeA);
collection.addSeries(typeB);
typeA = collection.getSeries("TypeA");
typeA.add(new Hour(8, new Day()), 1.0);
typeA.add(new Hour(10, new Day()), 1.0);
typeA.add(new Hour(11, new Day()), 1.0);
typeA.add(new Hour(13, new Day()), 1.0);
typeA.add(new Hour(16, new Day()), 2.0);
typeA.add(new Hour(18, new Day()), 2.0);
typeB.add(new Hour(8, new Day()), 1.0);
typeB.add(new Hour(19, new Day()), 2.0);
typeB.add(new Hour(20, new Day()), 5.0);
return collection;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
TimeChart chart = new TimeChart(
"Date axis demo",
"Date axis labels are visible");
chart.pack();
UIUtils.centerFrameOnScreen(chart);
chart.setVisible(true);
}
});
}
}
问题内容: 我有一个SQL Server Reporting Services(2008)图表(错误图表)。X轴的日期间隔为1/1 / 2009、2 / 1/2009等。Y轴的数字间隔为50。Y轴上的值为0、50和100。但是,不是显示0。 ,50和100我想分别显示“小”,“中”和“大”。有谁知道如何执行此文本替换? 问题答案: 这有点hack,但是这里有: 首先,将值标准化为零左右,因此最小值
我正在尝试使用vue-chartjs和Chart.js(2.7.1)绘制线图。显示图形,但没有xAx和yAx标签。 这是我的选项对象: 我认为scales.xAxes.scaleLabel不起作用。
我正在使用MPAndroidChart在我的android项目中绘制折线图,我看到X轴上的标签没有正确对齐,如下图所示。 未对齐标签
我正在使用jFreechart创建这样的折线图(取自演示): 是否可以将范围和域转换为Unicode编码系统? 非常感谢。
我创建了一个水平条形图w/chart.js,需要在y轴上创建两组标签,但只能创建一个。 例如,参见下图,在y轴上,我有一组单词“other”和“paper ”,计数分别为2和3;在这个分组和下面的两个分组中,我还需要显示与这两个词相关的月份——比如五月。 有办法做到这一点吗? 附言:在附加的图像中,我将镜像设置为true,但如果解决方案能给我所需的输出,我愿意关闭镜像。 到目前为止,我已经查看了这
我使用javafx绘制条形图和饼图。我需要: 更改条形图中x轴标签的字体大小 更改条形图标题的字体大小 更改饼图标题的字体大小 我正在使用的条形图 它仅更改xaxis上文本(单位)的字体大小,但不更改x轴标签 同样地,我正在使用 更改饼图中馅饼的标签。它确实会改变饼图标题的大小,但比例不一样。