2

週単位の軸が必要なグラフを作成したときに、この問題に遭遇しました。

DateAxiswithのティック単位を設定すると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週の最初の日から目盛りを常に描画するにはどうすればよいですか?


これがスクリーンショットとサンプルコードです

週の期間に 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);
  }
}
4

2 に答える 2

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()、次のティックを計算するたびに、の結果に1週間を追加し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;
}

結果 :

結果

于 2012-06-15T16:07:14.377 に答える
1

をオーバーライドすることで、目盛りの曜日を調整することができましたpreviousStandardDateDateAxis

あなたの例では、データは火曜日に表示されるため、以下のコードでは、週の最初の曜日が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();
  }
};

[編集:]目盛りを実際に揃えるのではなく、実際の週の最初の日に表示することに気付きました。そのための解決策は

DateAxis y = new DateAxis("Y") {    
  @Override
  protected Date previousStandardDate(Date date, DateTickUnit unit) {
    Date prevDate = super.previousStandardDate(date, unit);

    Calendar calendar = Calendar.getInstance(TimeZone.getDefault());
    calendar.setTime(prevDate);

    int firstDayOfWeek = calendar.getFirstDayOfWeek();
    if (firstDayOfWeek != calendar.get(Calendar.DAY_OF_WEEK)) {
      calendar.set(Calendar.DAY_OF_WEEK, firstDayOfWeek);
    }

    return calendar.getTime();
  }
};
于 2012-06-15T13:59:18.077 に答える