Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
418 views
in Technique[技术] by (71.8m points)

java - JFreeChart - horizontal stacked bar chart with date axis

I have a set of machines and for the management application I need to make a diagram or chart to show the state of each machine. In the database there is a column state where the actual state is stored. This state changes according other parameters and by change the time of the event is also stored, that means the timestamp of the event is the start time for the state.

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

enter image description here

As you can see in the image there are many states on one horizontal line (machine), the colors will be set accourding the value in database.
The time axis goes in both directions, past and future (forecast), with predefined steps (here 1/4 hour) so the user should be able to scroll it somehow.

As a library I am allowed to use JFreeChart, but I've never worked with it before and also I am not such an experienced Java-Developer.

My questions:
- What do I need to do it? (which classes of jfreechart)
- How can I set a first time axis separated in 1/4 hour steps
- How to set a second time axis with the date (formated dd:mm:yyyy) (nice to have)
- How can I make the time axis scrollable (past and future)
- How to set the color for each status

What I really need is a how-to or a tutorial.
The sources and examples I found on the net are almost all a copy of eachother with a very basic usage of the jfreechart lib. So I don't really know how or where to start...

I'll be thankfull for your help.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You're going to have to combine some examples:

  • Use a CategoryDataset like DefaultCategoryDataset for your data. Use ChartFactory.createStackedBarChart() with PlotOrientation.HORIZONTAL to create the chart.

  • Make sure the first parameter to addValue() is a multiple of 15 minutes, in milliseconds.

  • Use a DateAxis for the domain; call setDateFormatOverride() to get the format you want.

    DateAxis dateAxis = new DateAxis("Time");
    dateAxis.setDateFormatOverride(new SimpleDateFormat("HH:mm"));
    categoryplot.setRangeAxis(dateAxis);
    
  • For scrolling, use a SlidingCategoryDataset like they suggest here, or use the zoom commands from the context menu.

  • For color, use a custom getItemPaint(), like they show here.

I did set the DateFormat to show years, and it has 1970 as a year! Why?

You're example is creating new date values using seconds, but Date expects milliseconds. I added 000L to the time values, moved the range calculation to createDataset(), and let the axis auto-range.

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;
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...