JFreeChart - 带日期轴的水平堆积条形图

时间:2016-10-18 09:55:56

标签: java jfreechart

我有一套机器,对于管理应用程序,我需要制作一个图表或图表来显示每台机器的状态。 在数据库中有一个列状态,其中存储了实际状态。此状态根据其他参数更改,并且通过更改还存储事件的时间,这意味着事件的时间戳是状态的开始时间。

machine-id | event_time (long) | status (int)  

enter image description here

正如您在图像中看到的那样,在一条水平线(机器)上有许多状态,颜色将根据数据库中的值进行设置。
时间轴在两个方向上,过去和未来(预测),预定义的步骤(这里是1/4小时),因此用户应该能够以某种方式滚动它。

作为一个库我可以使用JFreeChart,但我以前从未使用它,而且我也不是一个经验丰富的Java开发人员。

我的问题:
- 我需要做什么? (哪类jfreechart)
- 如何设置以1/4小时步长分隔的第一个时间轴
- 如何设置带日期的第二个时间轴(格式化dd:mm:yyyy)(很高兴)
- 如何使时间轴可滚动(过去和将来)
- 如何为每种状态设置颜色

我真正需要的是操作方法或教程 我在网上找到的来源和示例几乎都是彼此的副本,其中包含jfreechart lib的基本用法。所以我真的不知道如何或从哪里开始...

我会感谢你的帮助。

2 个答案:

答案 0 :(得分:2)

你将不得不结合一些例子:

  • 使用CategoryDataset之类的DefaultCategoryDataset作为您的数据。将ChartFactory.createStackedBarChart()PlotOrientation.HORIZONTAL一起使用即可创建图表。

  • 确保addValue()的第一个参数是15分钟的倍数,以毫秒为单位。

  • 对域名使用DateAxis;致电setDateFormatOverride()以获取您想要的格式。

    DateAxis dateAxis = new DateAxis("Time");
    dateAxis.setDateFormatOverride(new SimpleDateFormat("HH:mm"));
    categoryplot.setRangeAxis(dateAxis);
    
  • 要进行滚动,请使用他们建议hereSlidingCategoryDataset,或使用上下文菜单中的缩放命令。

  • 对于颜色,请使用自定义getItemPaint(),就像它们显示here一样。

  

我确实将DateFormat设置为显示年份,并且它将1970年作为一年!为什么呢?

您的示例是使用创建新的日期值,但Date需要毫秒。我将000L添加到时间值,将范围计算移至createDataset(),然后让轴自动范围。

chart

import java.awt.Color;
import java.awt.Dimension;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.DateTickUnitType;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.StackedBarRenderer;
import org.jfree.data.Range;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

public class StackedTimeBarChart extends ApplicationFrame {

    private static final String STANDBY_SERIES = "STANDBY";
    private static final String HEATING_SERIES = "HEATING";
    private static final String HOLDING_SERIES = "HOLDING";
    private static final String COOLING_SERIES = "COOLING";
    private static final String LOWERING_SERIES = "LOWERING";
    private static final int STANDBY_SERIES_INDEX = 0;
    private static final int HEATING_SERIES_INDEX = 1;
    private static final int HOLDING_SERIES_INDEX = 2;
    private static final int COOLING_SERIES_INDEX = 3;
    private static final int LOWERING_SERIES_INDEX = 4;
    private static final Color STANDBY_COLOR = Color.DARK_GRAY;
    private static final Color HEATING_COLOR = Color.ORANGE;
    private static final Color HOLDING_COLOR = Color.YELLOW;
    private static final Color COOLING_COLOR = Color.CYAN;
    private static final Color LOWERING_COLOR = Color.GREEN;

    ArrayList<EventStatus> testData = null;
    CategoryPlot plot;

    public StackedTimeBarChart(String title) {
        super(title);
        // set up some test data
        initData();

        // set the start and end date of the chart
        plot = new CategoryPlot();
        plot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
        plot.setOrientation(PlotOrientation.HORIZONTAL);

        // create dataset
        CategoryDataset dataset = createDataset();

        // create the axis
        CategoryAxis catAxis = new CategoryAxis();
        DateAxis dateAxis = new DateAxis();
        dateAxis.setVerticalTickLabels(true);
        //dateAxis.setTickUnit(new DateTickUnit(DateTickUnitType.HOUR, 1));
        dateAxis.setDateFormatOverride(new SimpleDateFormat("dd.MM.yyyy HH:mm"));

        // set up the renderer
        StackedBarRenderer rend = new StackedBarRenderer();
        //rend.setBase(chartRange.getLowerBound());
        rend.setSeriesPaint(STANDBY_SERIES_INDEX, STANDBY_COLOR);
        rend.setSeriesPaint(HEATING_SERIES_INDEX, HEATING_COLOR);
        rend.setSeriesPaint(HOLDING_SERIES_INDEX, HOLDING_COLOR);
        rend.setSeriesPaint(COOLING_SERIES_INDEX, COOLING_COLOR);
        rend.setSeriesPaint(LOWERING_SERIES_INDEX, LOWERING_COLOR);

        // set up the plot
        plot.setDataset(dataset);
        plot.setDomainAxis(catAxis);
        plot.setRangeAxis(dateAxis);
        plot.setRenderer(rend);

        // create the chart and add it
        JFreeChart chart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
        ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new Dimension(600, 450));
        setContentPane(chartPanel);
    }

    private CategoryDataset createDataset() {
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        Date chartStartDate = new Date(testData.get(0).getTime());
        Date chartEndDate = new Date(testData.get(testData.size() - 1).getTime());
        Range chartRange = new Range(chartStartDate.getTime(), chartEndDate.getTime());
        if (testData != null) {
            for (int i = 0; i < testData.size(); i++) {
                // is there data?
                if (testData.size() > 0) {
                    for (int j = 0; j < testData.size(); j++) {
                        EventStatus es = testData.get(j);
                        long eventTime = es.getTime();
                        int status = es.getStatus();
                        String name = es.getName();

                        // if data event time is in the range of the chart then show it
                        // THIS DOES NOT WORK PROPERLY!!!!
                        if (eventTime >= chartStartDate.getTime() && eventTime < chartEndDate.getTime()) {
                            // create series and categories
                            if (es.getStatus() == STANDBY_SERIES_INDEX) {
                                dataset.addValue(new Double(es.getTime()), STANDBY_SERIES, es.getName());
                            } else if (es.getStatus() == HEATING_SERIES_INDEX) {
                                dataset.addValue(new Double(es.getTime()), HEATING_SERIES, es.getName());
                            } else if (es.getStatus() == HOLDING_SERIES_INDEX) {
                                dataset.addValue(new Double(es.getTime()), HOLDING_SERIES, es.getName());
                            } else if (es.getStatus() == COOLING_SERIES_INDEX) {
                                dataset.addValue(new Double(es.getTime()), COOLING_SERIES, es.getName());
                            } else if (es.getStatus() == LOWERING_SERIES_INDEX) {
                                dataset.addValue(new Double(es.getTime()), LOWERING_SERIES, es.getName());
                            } else {
                                dataset.addValue(chartRange.getUpperBound() - chartRange.getLowerBound(), STANDBY_SERIES, es.getName());
                            }
                        } else {
                            continue;
                        }
                    }
                }
            }
        } else {
            plot.setNoDataMessage("NO DATA AVAILABLE");
        }

        return dataset;
    }

    public static void main(String[] args) {
        StackedTimeBarChart demo = new StackedTimeBarChart("demo");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);

    }

    private void initData() {
        testData = new ArrayList<EventStatus>();
        testData.add(new EventStatus("Mach-1", 1476950160000L, 1));
        testData.add(new EventStatus("Mach-1", 1476952200000L, 2));
        testData.add(new EventStatus("Mach-1", 1476964800000L, 4));
        testData.add(new EventStatus("Mach-1", 1476966600000L, 3));
        testData.add(new EventStatus("Mach-2", 1476943200000L, 1));
        testData.add(new EventStatus("Mach-2", 1476946800000L, 4));
        testData.add(new EventStatus("Mach-2", 1476954000000L, 2));
        testData.add(new EventStatus("Mach-2", 1476955800000L, 1));
        testData.add(new EventStatus("Mach-2", 1476973800000L, 3));
        testData.add(new EventStatus("Mach-3", 1476959400000L, 2));
        testData.add(new EventStatus("Mach-3", 1476966600000L, 1));
        testData.add(new EventStatus("Mach-3", 1476970200000L, 4));
        testData.add(new EventStatus("Mach-3", 1476972000000L, 1));
        testData.add(new EventStatus("Mach-3", 1476986400000L, 2));
    }

// Chart object class that hold category, event time and status
    private class EventStatus {

        private String name;
        private long time;
        private int status;

        public EventStatus(String name, long time, int status) {
            this.name = name;
            this.time = time;
            this.status = status;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public long getTime() {
            return time;
        }

        public void setTime(long time) {
            this.time = time;
        }

        public int getStatus() {
            return status;
        }

        public void setStatus(int status) {
            this.status = status;
        }
    }
}

答案 1 :(得分:1)

我使用了XYIntervalSeries和XYPlot 如果有人需要提示,那么Hier就是示例代码:

public class XYIntervalBarChart extends ApplicationFrame{

private static final String NODATA_SERIES   = "NODATA";
private static final String STANDBY_SERIES  = "STANDBY";
private static final String HEATING_SERIES  = "HEATING";
private static final String HOLDING_SERIES  = "HOLDING";
private static final String COOLING_SERIES  = "COOLING";
private static final String LOWERING_SERIES = "LOWERING";

ArrayList<EventStatus> testData = null;
String[] catArray;

JFreeChart chart;
DateAxis dateAxis;

Date chartStartDate;
Date chartEndDate;

public XYIntervalBarChart(String title) {
    super(title);
    // set up some test data
    initData();

    chartStartDate  = new Date(1477461600000L);
    chartEndDate = new Date(1477497600000L);
    chart = createIntervalStackedChart();
    ChartPanel chartPanel = new ChartPanel(chart);
    chartPanel.setPreferredSize(new Dimension(600, 450));
    setContentPane(chartPanel);
}

private JFreeChart createIntervalStackedChart() {
    XYIntervalSeriesCollection dataset = createXYIntervalDataset();
    XYBarRenderer xyRend = new XYBarRenderer();
    xyRend.setShadowVisible(false);
    xyRend.setUseYInterval(true);
    xyRend.setBarPainter(new StandardXYBarPainter());
    xyRend.setSeriesPaint(0, Color.BLACK);
    xyRend.setSeriesPaint(1, Color.DARK_GRAY);
    xyRend.setSeriesPaint(2, Color.RED);
    xyRend.setSeriesPaint(3, Color.YELLOW);
    xyRend.setSeriesPaint(4, Color.CYAN);
    xyRend.setSeriesPaint(5, Color.GREEN);

    dateAxis = new DateAxis();
    dateAxis.setVerticalTickLabels(true);
    dateAxis.setDateFormatOverride(new SimpleDateFormat("dd.MM.yy HH:mm"));
    XYPlot plot = new XYPlot(dataset, new SymbolAxis("", catArray), dateAxis, xyRend);
    plot.setOrientation(PlotOrientation.HORIZONTAL);
    plot.setBackgroundPaint(Color.LIGHT_GRAY);
    return new JFreeChart(plot);
}

private XYIntervalSeriesCollection createXYIntervalDataset() {
    XYIntervalSeriesCollection dataset = new XYIntervalSeriesCollection();

    int statesCount = 6;
    String[] states = new String[] {NODATA_SERIES, STANDBY_SERIES, HEATING_SERIES, HOLDING_SERIES, COOLING_SERIES, LOWERING_SERIES};

    XYIntervalSeries[] series = new XYIntervalSeries[statesCount];
    for (int i = 0; i < statesCount; i++) {
        series[i] = new XYIntervalSeries(states[i]);
        dataset.addSeries(series[i]);
    }

    for (int i = 0; i < testData.size(); i++) {
        EventStatus es = testData.get(i);
        int machNo = es.getPlanningNo();
        int state = es.getStatus();
        long eventStart = es.getTime();
        long eventEnd = 0;
        if (testData.indexOf(es) == testData.size() - 1) {
            eventEnd = chartEndDate.getTime();
        }
        else {
            EventStatus nextEs = testData.get(i + 1);
            if (nextEs.getTime() > eventStart) {
                eventEnd = nextEs.getTime();
            }
            else {
                eventEnd = chartEndDate.getTime();
            }
        }

        long duration = TimeUnit.MILLISECONDS.convert(eventEnd - eventStart, TimeUnit.MILLISECONDS);
        series[state].add(machNo, machNo - 0.2, machNo + 0.2, eventStart, eventStart, eventStart + duration);
    }

    return dataset;
}

private void initData() {
    testData = new ArrayList<EventStatus>();
    testData.add(new EventStatus("Mach-1", 1477468500000L, 1, 0)); // 26.10.16 09:55  standby
    testData.add(new EventStatus("Mach-1", 1477472100000L, 2, 0)); // 26.10.16 10:55  heating
    testData.add(new EventStatus("Mach-1", 1477474200000L, 5, 0)); // 26.10.16 11:30  lowering
    testData.add(new EventStatus("Mach-1", 1477476000000L, 3, 0)); // 26.10.16 12:00  holding
    testData.add(new EventStatus("Mach-1", 1477479600000L, 4, 0)); // 26.10.16 13:00  cooling
    testData.add(new EventStatus("Mach-1", 1477486800000L, 1, 0)); // 26.10.16 15:00  standby

    testData.add(new EventStatus("Mach-2", 1477465200000L, 3, 1)); // 26.10.16 09:00  holding
    testData.add(new EventStatus("Mach-2", 1477472400000L, 2, 1)); // 26.10.16 11:00  heating
    testData.add(new EventStatus("Mach-2", 1477474200000L, 5, 1)); // 26.10.16 11:30  lowering
    testData.add(new EventStatus("Mach-2", 1477476000000L, 2, 1)); // 26.10.16 12:00  heating
    testData.add(new EventStatus("Mach-2", 1477479600000L, 3, 1)); // 26.10.16 13:00  holding
    testData.add(new EventStatus("Mach-2", 1477486800000L, 4, 1)); // 26.10.16 15:00  cooling


    ArrayList<String> list = new ArrayList<>();
    for (EventStatus eventStatus : testData) {
        if (list.contains(eventStatus.getName()))
            continue;
        else
            list.add(eventStatus.getName());
    }

    catArray = new String[list.size()];
    catArray = list.toArray(catArray);
}

public static void main(String[] args) {
    XYIntervalBarChart demo = new XYIntervalBarChart("XYIntervalBarChart");
    demo.pack();
    RefineryUtilities.centerFrameOnScreen(demo);
    demo.setVisible(true);

}}

结果:
enter image description here