当我创建一个需要带周周期的轴的图表时,我遇到了这个问题。
当我使用DateAxis
设置new DateTickUnit(DateTickUnitType.Day, 7)
的刻度单位时,它会每7天显示一次刻度线。但是,刻度标记的日期不是从一周的第一天开始。您可以在屏幕截图中观察此行为。
青色线05-01 w18(May. 1, Week 18)
低于w18(Week 18)
刻度线,这是因为刻度线w18
的日期实际上是5月2日,即星期三。
这个制作图表看起来不正确,因为人们倾向于认为每个刻度都是本周的开始。
在检查源代码后,我发现DateAxis
一周不支持这种行为(无论如何都没有周类型)。
我无法创建另一个DateTickUnitType
,因为correctTickDateForPosition()
中的私有构造函数和DateAxis
方法也是私有的。我试图覆盖nextStandardDate()
,但没有满足结果。
如何让DateAxis
始终从一周的第一天开始勾选刻度线?
以下是截图和示例代码
需要JFreeChart / JCommon
public class Main extends ApplicationFrame {
public Main (String title) throws ParseException {
super(title);
JPanel chartPanel = createDemoPanel();
chartPanel.setPreferredSize(new java.awt.Dimension(800, 600));
setContentPane(chartPanel);
}
private static JFreeChart createChart(XYDataset dataset) {
JFreeChart chart = ChartFactory.createXYLineChart("Week period in DateAxis", "X", "Y",
dataset, PlotOrientation.VERTICAL, true, true, false);
DateAxis x = new DateAxis("X");
x.setTickUnit(new DateTickUnit(DateTickUnitType.MONTH, 1, new SimpleDateFormat("MMM.")));
DateAxis y = new DateAxis("Y");
y.setTickUnit(new DateTickUnit(DateTickUnitType.DAY, 7, new SimpleDateFormat("MM-dd 'W'w.")));
XYPlot plot = chart.getXYPlot();
plot.setDomainAxis(x);
plot.setRangeAxis(y);
plot.setDomainGridlinesVisible(true);
plot.setRangeGridlinesVisible(true);
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer();
renderer.setBaseShapesVisible(true);
renderer.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator("{2}",
new SimpleDateFormat("MMM."), new SimpleDateFormat("MM-dd 'w'w")));
renderer.setBaseItemLabelsVisible(true);
return chart;
}
private static XYDataset createDataset() throws ParseException {
SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
String[] allDate = new String[]{
"2012/03/27", "2012/04/03", "2012/04/10",
"2012/04/17", "2012/04/24", "2012/05/01"};
String dateY1 = "2012/01/15";
String dateY2 = "2012/02/15";
String dateY3 = "2012/03/15";
String dateY4 = "2012/04/15";
String dateY5 = "2012/05/15";
String dateY6 = "2012/06/15";
XYSeriesCollection dataset = new XYSeriesCollection();
for (String date : allDate) {
XYSeries series = new XYSeries(date);
series.add(df.parse(dateY1).getTime(), df.parse(date).getTime());
series.add(df.parse(dateY2).getTime(), df.parse(date).getTime());
series.add(df.parse(dateY3).getTime(), df.parse(date).getTime());
series.add(df.parse(dateY4).getTime(), df.parse(date).getTime());
series.add(df.parse(dateY5).getTime(), df.parse(date).getTime());
series.add(df.parse(dateY6).getTime(), df.parse(date).getTime());
dataset.addSeries(series);
}
return dataset;
}
public static JPanel createDemoPanel() throws ParseException {
JFreeChart chart = createChart(createDataset());
return new ChartPanel(chart);
}
public static void main(String[] args) throws ParseException {
Main demo = new Main("Test");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
答案 0 :(得分:6)
以下是支持周期(仅限)的DateAxis
版本。
public static class WeeklyDateAxis extends DateAxis {
private static final long serialVersionUID = 1L;
private Locale locale;
public WeeklyDateAxis(String label, TimeZone zone, Locale locale) {
super(label, zone, locale);
this.locale = locale;
}
@Override
protected Date previousStandardDate(Date date, DateTickUnit unit) {
Calendar cal = Calendar.getInstance(getTimeZone(), locale);
cal.setTime(date);
resetFieldBelowDay(cal);
cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
return cal.getTime();
}
@Override
protected Date nextStandardDate(Date date, DateTickUnit unit) {
Date previous = previousStandardDate(date, unit);
Calendar cal = Calendar.getInstance(getTimeZone(), locale);
cal.setTime(previous);
resetFieldBelowDay(cal);
cal.add(Calendar.WEEK_OF_YEAR, 1);
return cal.getTime();
}
private void resetFieldBelowDay(Calendar cal) {
cal.clear(Calendar.MILLISECOND);
cal.clear(Calendar.SECOND);
cal.clear(Calendar.MINUTE);
cal.set(Calendar.HOUR_OF_DAY, 0);
}
}
当DateAxis
计算滴答时,它将通过调用
nextStandardDate(getMinimumDate(), unit);
,其中getMinimumDate()
是图表的边缘值。然后它将继续使用日期的最后一个滴答作为输入来计算下一个日期,直到它达到最高可用日期。
所以我将时间设置为previousStandardDate()
中的第一天的第一天,然后每次计算下一个刻度时,我都会在previousStandardDate()
的结果中添加一周。
resetFieldBelowDay()
部分只是删除一些噪音数据,这些数据可能导致线条剂量与刻度线不对齐。
这是我用来验证结果的另一个数据集,你可以简单地用我提供的示例代码替换它。
private static XYDataset createDataset() throws ParseException {
SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
String[][] allDate = new String[][] {
{"2012/03/25", "2012/03/29", "2012/03/28", "2012/03/27", "2012/03/27", "2012/03/27"},
{"2012/04/01", "2012/04/02", "2012/04/06", "2012/04/06", "2012/04/06", "2012/04/06"},
{"2012/04/11", "2012/04/12", "2012/04/08", "2012/04/10", "2012/04/10", "2012/04/10"},
{"2012/04/15", "2012/04/14", "2012/04/15", "2012/04/18", "2012/04/19", "2012/04/19"},
{"2012/05/01", "2012/05/02", "2012/05/08", "2012/05/04", "2012/05/04", "2012/05/04"},
{"2012/05/12", "2012/05/12", "2012/05/18", "2012/05/14", "2012/05/14", "2012/05/14"},
{"2012/05/22", "2012/05/22", "2012/05/28", "2012/05/28", "2012/05/28", "2012/05/30"},
};
String dateY1 = "2012/01/15";
String dateY2 = "2012/02/15";
String dateY3 = "2012/03/15";
String dateY4 = "2012/04/15";
String dateY5 = "2012/05/15";
String dateY6 = "2012/06/15";
XYSeriesCollection dataset = new XYSeriesCollection();
for (String[] dateOfOneSeries : allDate) {
XYSeries series = new XYSeries(dateOfOneSeries[0]);
series.add(df.parse(dateY1).getTime(), df.parse(dateOfOneSeries[0]).getTime());
series.add(df.parse(dateY2).getTime(), df.parse(dateOfOneSeries[1]).getTime());
series.add(df.parse(dateY3).getTime(), df.parse(dateOfOneSeries[2]).getTime());
series.add(df.parse(dateY4).getTime(), df.parse(dateOfOneSeries[3]).getTime());
series.add(df.parse(dateY5).getTime(), df.parse(dateOfOneSeries[4]).getTime());
series.add(df.parse(dateY6).getTime(), df.parse(dateOfOneSeries[5]).getTime());
dataset.addSeries(series);
}
return dataset;
}
答案 1 :(得分:1)
通过覆盖previousStandardDate
的{{1}},我设法调整星期几的刻度线。
在您的示例中,数据显示为星期二,因此在下面的代码中,DateAxis
的第一天的第一天设置为星期二,它将数据行与刻度线对齐。
Calendar
[编辑:] 我刚刚意识到您实际上并不想对齐刻度线,而是在一周的实际第一天显示它们。解决方法是
DateAxis y = new DateAxis("Y") {
@Override
protected Date previousStandardDate(Date date, DateTickUnit unit) {
Date prevDate = super.previousStandardDate(date, unit);
Calendar calendar = Calendar.getInstance();
calendar.setTime(prevDate);
int showDayOfWeek = Calendar.TUESDAY;
calendar.setFirstDayOfWeek(showDayOfWeek);
if (showDayOfWeek != calendar.get(Calendar.DAY_OF_WEEK)) {
calendar.set(Calendar.DAY_OF_WEEK, showDayOfWeek);
}
return calendar.getTime();
}
};