简体   繁体   English

JFreeChart自定义x轴标签

[英]JFreeChart custom x-axis labels

I have multiple series of data. 我有多个系列的数据。

  • Series are years: 2013,2014,2015 etc. 系列年份:2013,2014,2015等
  • Data is date+value within a given year. 数据是给定年份内的日期+值。
  • Because data needs to be categorized with years, I'm using "day of the year" values on the x axis, range between 1 and 366. So values for a given year look like this: (1,80), (30,100), (60,71) ..... (255,130) 因为数据需要按年份分类,所以我在x轴上使用“一年中的一天”值,范围在1到366之间。因此给定年份的值如下所示:(1,80),(30,100) ,(60,71).....(255,130)

Example diagram: 示例图:

在此输入图像描述

My problem is that the X axis contains "day of the year" values, but I have to put month names there. 我的问题是X轴包含“一年中的某一天”值,但我必须在那里放置月份名称。 Unfortunately, using a simple DateAxis is not an option, because X values are day numbers (not dates), and AFAIK there is no date format that could convert "335" to "December". 不幸的是,使用简单的DateAxis不是一个选项,因为X值是日期数字(不是日期),而AFAIK没有可以将“335”转换为“12月”的日期格式。 Another problem with DateAxis is that it represents points in time, and it provides a separate X axis label for any point in time. DateAxis的另一个问题是它表示时间点,它为任何时间点提供单独的X轴标签。 But I need to write out labels for exact points in time. 但我需要及时写出确切时间点的标签。 Namely: only at the begining of the months. 即:仅在几个月的开始。 What I really want is something like this: 我真正想要的是这样的:

在此输入图像描述

Eg instead of putting "ticks" at the beginning/end of a month, I want to display regions. 例如,我想在一个月的开头/结尾放置“滴答声”,而是要显示区域。 What makes it harder is that the months have different lengths. 更难的是月份有不同的长度。 Since February has 29 days in leap years, I think I will have to use fixed points (day of the year values). 由于二月有闰年29天,我想我将不得不使用固定点(一年中的数值)。

Do I have to write a custom axis renderer for this? 我是否必须为此编写自定义轴渲染器? How? 怎么样? Is there an easier solution for my problem? 我的问题有更简单的解决方案吗?

import java.awt.Graphics2D;
import java.awt.font.LineMetrics;
import java.awt.geom.Rectangle2D;
import java.util.List;
import java.awt.Color;

import org.jfree.chart.axis.AxisState;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueTick;
import org.jfree.text.TextUtilities;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.TextAnchor;



public class DayOfYearAxis extends NumberAxis {
    /* Day of the year values for month end days. */
    public static final Integer[] MONTH_LENGTHS = {
            31,29,31,30,31,30,31,31,30,31,30,31
    };
    public static final String[] MONTH_NAMES = {
        "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
};

    protected AxisState  drawTickMarksAndLabels(Graphics2D g2,double cursor,Rectangle2D plotArea,Rectangle2D dataArea,RectangleEdge edge) {
        AxisState state = new AxisState(cursor);

        g2.setFont(getTickLabelFont());

        double ol = getTickMarkOutsideLength();
        double il = getTickMarkInsideLength();
        int y = (int)(Math.round(cursor-ol));
        LineMetrics lineMetrics = g2.getFont().getLineMetrics("Ápr", g2.getFontRenderContext());        
        int h = (int) (lineMetrics.getHeight() + 6);

        List<ValueTick> ticks = refreshTicks(g2, state, dataArea, edge);
        state.setTicks(ticks);

        /* Last x point */
        ValueTick tick = ticks.get(ticks.size()-1);     
        float[] prevAnchorPoint = calculateAnchorPoint(tick, cursor,dataArea, edge);
        double xmax = prevAnchorPoint[0];
        double max_day = tick.getValue();

        /* First x point */
        tick = ticks.get(0);
        prevAnchorPoint = calculateAnchorPoint(tick, cursor,dataArea, edge);
        double xmin = Math.round(prevAnchorPoint[0]);
        double min_day = tick.getValue();       
        double days_visible = max_day - min_day + 1;
        /* 0.1 day horizontal gap. */
        double gap = 0.1*(xmax-xmin)/days_visible;

        System.out.println("min_day "+min_day+" max_day"+max_day);

        g2.setFont(getTickLabelFont());
        g2.setColor(Color.BLACK);
        int start_day = 0;
        for (int month=0;month<12;month++) {
            int end_day = start_day + MONTH_LENGTHS[month] - 1;
            System.out.println("start-end "+start_day+" "+end_day);
            if ( (start_day>=min_day) && (start_day<=max_day) && (end_day>=min_day) && (end_day<=max_day) ) {
                double factor_x1 = (start_day - min_day) / days_visible;
                double x1 = xmin + (xmax-xmin)* factor_x1;
                double factor_x2 = (end_day - min_day) / days_visible;
                double x2 = xmin + (xmax-xmin)* factor_x2;
                System.out.println("month="+month+", start_day="+start_day+" end_day="+end_day+" x1="+x1+" x2="+x2);
                g2.setColor(Color.LIGHT_GRAY);
                g2.fill3DRect((int)(x1+gap),y,(int)(x2-x1-2*gap),h,true);
                g2.setColor(Color.BLACK);
                TextUtilities.drawAlignedString(MONTH_NAMES[month], g2, (float)((x1+x2)/2), (float)(y+ol), TextAnchor.TOP_CENTER);
            }           
            start_day += MONTH_LENGTHS[month];
        }
        return state;
    }

}

Usage: 用法:

    JFreeChart chart = ChartFactory.createXYLineChart(...);
    DayOfYearAxis doyAxis = new DayOfYearAxis();
    /* optional
    doyAxis.setAutoRange(false);
    doyAxis.setRange(new Range(min_yday, max_yday));
    */
    chart.getXYPlot().setDomainAxis(doyAxis);        

Example output (with hungarian month names): 输出示例(匈牙利月份名称):

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM