0

I have created a simple line chart where I compare the current years values to past years (could be an average or not).

Example of the basic chart

The issue is that as this is for UK Academic purposes I want the months to run from June through to June the following year.

Currently my code looks like:

xAxis.setLabel("Date/Month");
    xAxis.setTickLabelRotation(90);

    xAxis.setAutoRanging(false);
    xAxis.setLowerBound(1);
    xAxis.setUpperBound(12);
    xAxis.setTickUnit(1.0);

    xAxis.setTickLabelFormatter(new StringConverter<Number>() {

        @Override
        public String toString(Number month) {
            logger.debug("Converting " + month);
            return new DateFormatSymbols().getMonths()[month.intValue()-1];
        }

        @Override
        public Number fromString(String string) {
            try {
                Date date = new SimpleDateFormat("MMMM").parse(string);
                Calendar cal = Calendar.getInstance();
                cal.setTime(date);
                return cal.get(Calendar.MONTH);
            } catch (ParseException ex) {
                logger.error("Parse Exception");
            }
            return  0;
        }

    });


    yAxis.setLabel("Units");

where the series are created using a simple function:

    private XYChart.Series createSeries(String name, List<AccountUtilities> data) {
    XYChart.Series series = new XYChart.Series();
    series.setName(name);
    for (AccountUtilities utility : data) {
        String[] dateParts = utility.getStartdate().split("-");
        Double dateCode = Double.valueOf(dateParts[1]);
        series.getData().add(new XYChart.Data( dateCode , utility.getGasunits()));
    }
    return series;
}

My current thought is that I can reindex the months as June = 1, July = 2 etc. to get the values into the chart in the correct order and then decode them into their 'correct' values June = 6 when I get setTickLabelFormatter to do its thing but this seems a long way around.

Is there a nifty feature of javafx charting that I'm missing?

Current resources used:

Byte Insight
  • 745
  • 1
  • 6
  • 17
  • 1
    Any reason why you are still using the long outdated and poorly designed classes `Date`, `Calendar` and `SimpleDateFormat`? [`java.time`, the modern Java date and time API,](https://docs.oracle.com/javase/tutorial/datetime/) is so much nicer to work with. It seems to me you want [`Month.getDisplayName`](https://docs.oracle.com/javase/10/docs/api/java/time/Month.html#getDisplayName(java.time.format.TextStyle,java.util.Locale)). – Ole V.V. Aug 29 '18 at 10:07
  • Because my knowledge is circa 2000 and I'm getting back up to date? Thanks for the knowledge - I'll update. – Byte Insight Aug 29 '18 at 10:10
  • @OleV.V. Thanks again for the advice. Hopefully my updated answer below is more in keeping with current best practice. – Byte Insight Aug 31 '18 at 07:48
  • It certainly is (+1). This should be helpful to future readers, thank you. – Ole V.V. Aug 31 '18 at 07:56

1 Answers1

1

So I followed my initial thought process and although it was more complicated than I initially thought with any offset that wasn't 6 months the following works for both 6 and 8. The following method reorders Jan(1) to Dec(12) to the offsetted order e.g. Jun(1) to May(12) so the data appears in the desired order in the chart.

private Double getAcademicMonth(String baseDate) {
    Integer dateCode = Integer.valueOf(baseDate);

    //Any month greater than the accounting start month gets shifted by six.
    if (dateCode > offset) { dateCode = dateCode - offset; }
    else { dateCode = dateCode + (12-offset); }

    return dateCode;
}

I then required a means of converting the months back on the fly when the chart was drawn so I got the correct month labels, which was achieved with setTickLabelFormatter

    //We have to set tick label formatter now once the offset has been retrieved.
    xAxis.setTickLabelFormatter(new StringConverter<Number>() {

        @Override
        public String toString(Number month) {

            //Shift our months to account for the accounting start month
            int dateCode = month.intValue();
            if (dateCode <= (12 - offset) ) { dateCode = dateCode + offset; }
            else { dateCode = dateCode - (12-offset); }

            Month day = Month.of(dateCode);
            return day.getDisplayName(TextStyle.SHORT, Locale.ENGLISH);

        }

        @Override
        public Number fromString(String string) {
          DateTimeFormatter parser = DateTimeFormatter.ofPattern("MMMM").withLocale(Locale.ENGLISH);
          TemporalAccessor accessor = parser.parse(string);
          return accessor.get(ChronoField.MONTH_OF_YEAR);
        }

    });

The end result with additional data series.

Byte Insight
  • 745
  • 1
  • 6
  • 17
  • hmm ... what's the type of the xAxis? Wouldn't a Category axis suit your needs? If not, there are DateAxis out in the wild that allow setting the start in terms of a LocalDate – kleopatra Aug 29 '18 at 10:12
  • That was the knowledge I was looking for. Thanks. TBH this works pretty well for my purposes for now. – Byte Insight Aug 29 '18 at 11:00