Dislpay multiple gantt tasks in a single row

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
kumat
Posts: 5
Joined: Mon Jul 13, 2015 7:37 am
antibot: No, of course not.

Dislpay multiple gantt tasks in a single row

Post by kumat » Mon Jul 13, 2015 8:37 am

I want to repeat the unanswered post Display multitasks on same row by narramadan from 2011.
Is there now a way to solve this issue in the actual jfreechart library?

I have to generate a report as shown in the image:

Image

which is a daily team schedule for employees. Green showing work hours, red as short break and yellow as long break.

I want to avoid that the TasksSeries-objects are grouped in different rows.

I tried using Gantt Chart to have multiple tasks for single employee on same row. But I couldn't achieve it.

Can you please tell me how can this be accomplished either with gantt charts or any other chart in jfreechart suite.

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Dislpay multiple gantt tasks in a single row

Post by paradoxoff » Fri Jul 17, 2015 9:10 am

You should be able to achieve that by a combination of XYPlot, SymbolAxis, and an IntervalXYDataset. Here is an example for that combination. For your requirement, you would have to replace the rooms with employess, and the courses with either a working time slot or one of the various breaks.

Code: Select all

public class RoomManager extends ApplicationFrame {

  public RoomManager(final String title) {

     super(title);
     XYIntervalSeriesCollection dataset = new XYIntervalSeriesCollection();
     //6 different rooms
     int roomCount= 6;
     String[] rooms = new String[roomCount];
     for(int i = 0; i < roomCount; i++){
          rooms[i] = "Room 0" + i;
     }
     //4 different courses inclucing "free"
     int courseTypes = 4;
     String[] courseNames= new String[]{"Cooking","Math","Painting","Free"};
     int totalCourseCount = 30;
     Random r = new Random();
     //Time, until the respective room is occupied
     double[] startTimes = new double[roomCount];

     //Create series. Start and end times are used as y intervals, and the room is represented by the x value
     XYIntervalSeries[] series = new XYIntervalSeries[courseTypes];
     for(int i = 0; i < courseTypes; i++){
          series[i] = new XYIntervalSeries(courseNames[i]);
          dataset.addSeries(series[i]);
     }

     for(int k = 0; k < totalCourseCount; k++){
          //get a random room
          int currentRoom = r.nextInt(roomCount);
          //get a random course
          int currentCourse = r.nextInt(courseTypes);
          //get a random course duration (1-3 h)
          int time = r.nextInt(3) + 1;
          //Encode the room as x value. The width of the bar is only 0.6 to leave a small gap. The course starts 0.1 h/6 min after the end of the preceding course.
          series[currentCourse].add(currentRoom, currentRoom - 0.3, currentRoom + 0.3, startTimes[currentRoom], startTimes[currentRoom] +0.1, startTimes[currentRoom] + time - 0.1);
          //Increase start time for the current room
          startTimes[currentRoom] += time;
     }
     XYBarRenderer renderer = new XYBarRenderer();
     renderer.setUseYInterval(true);
     XYPlot plot = new XYPlot(dataset, new SymbolAxis("Rooms", rooms), new NumberAxis(), renderer);
     plot.setOrientation(PlotOrientation.HORIZONTAL);
     JFreeChart chart = new JFreeChart(plot);
     getContentPane().add(new ChartPanel(chart));

  }

  public static void main(final String[] args) {

     final RoomManager demo = new RoomManager("RoomManager");
     demo.pack();
     RefineryUtilities.centerFrameOnScreen(demo);
     demo.setVisible(true);

  }

}

kumat
Posts: 5
Joined: Mon Jul 13, 2015 7:37 am
antibot: No, of course not.

Re: Dislpay multiple gantt tasks in a single row

Post by kumat » Wed Jul 22, 2015 2:34 pm

Thank you, thats a very good solution for my requirements. I could implement the x-axis as time line (with DateAxis()) and appropriate tooltips (with XYToolTipGenerator).

I tried to add a scroll bar for the x-axis, since the x-axis time line may be very long.
Can an existing Sliding*-class (or other class) be used for this purpose? In my example the data set is a XYIntervalSeriesCollection! I only have found Sliding*-classes for gantt tasks (SlidingGanttDatasetDemo) and categorie data sets (SlidingCategorieDataSetDemo2).

I also unsuccessfully tried to use the class SlidingXYDataset-class from http://sourceforge.net/p/jfreechart/patches/231/. The demo source code use XYSeriesCollection (SliderDemo1) and TimeSeries (SliderDemo2). I substituted the XYSeriesCollection in SliderDemo1 with the XYIntervalSeriesCollection data set from my example, but no (interval) bars are shown in the chart and no date/time tick labels are shown in the x-axis time line.

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Dislpay multiple gantt tasks in a single row

Post by paradoxoff » Wed Jul 22, 2015 6:20 pm

Well, a SlidingXYDataset is only an XYDataset and not an IntervalXYDataset. if you use a SlidingXYDataset, the XYBarRenderer only sees the XYDataset interface and throws an exception upcon casting the dataset to an IntervalXYDataset. You also can´t use any of the other existing Sliding datasets as they require a CategoyDataset as backend.
I see three options:
- Write your own SlidingIntervalXYDataset, using the SlidingXYDataset as a starter.
- Zoom the x axis to a desired/reasonable range, and then ue the pan feature to "slide" through the dataset.
- if you need to have a JScrollbar to scroll through the values, have a look at this code. Feel free to incorprate the AxisBoundedRangeModel into your own project.

Code: Select all

ackage jfree;
import javax.swing.*;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.*;
import org.jfree.chart.event.*;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.xy.*;
import org.jfree.data.Range;
import org.jfree.data.xy.DefaultXYDataset;
import java.awt.BorderLayout;

public class AxisBoundedRangeDemo {
    public static void main(String[] args) {
        int count = 50;
        double[][] data = new double[2][count];
        for(int i = 0; i < count; i++){
            data[0][i] = i;
            data[1][i] = i;
        }
        DefaultXYDataset dataset = new DefaultXYDataset();
        dataset.addSeries("Values", data);
        NumberAxis xAxis = new NumberAxis("x axis");
        NumberAxis yAxis = new NumberAxis("y axis");
        //XYItemRenderer renderer = new XYTrendDataRenderer(true, true);
        XYItemRenderer renderer = new XYLineAndShapeRenderer(true, true);
        XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
        JFreeChart chart = new JFreeChart(plot);
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new ChartPanel(chart));
        AxisBoundedRangeModel model = new AxisBoundedRangeModel(plot, plot.getDomainAxis());
        JScrollBar scroller = new JScrollBar();
        scroller.setModel(model);
        scroller.setOrientation(JScrollBar.HORIZONTAL);
        frame.getContentPane().add(scroller, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }
}
class AxisBoundedRangeModel extends DefaultBoundedRangeModel implements AxisChangeListener{
    private XYPlot plot;
    private ValueAxis axis;
    private final int MAX = 1000;

    AxisBoundedRangeModel(XYPlot plot, ValueAxis axis){
        super();
        this.plot = plot;
        this.axis = axis;
        super.setMinimum(0);
        super.setMaximum(MAX);
        axis.addChangeListener(this);
        adjustValues();
    }
    public void axisChanged(AxisChangeEvent ace){
        if(ace.getAxis() != axis) return;
        adjustValues();
    }
    private void adjustValues(){
        Range full = plot.getDataRange(axis);
        double min = full.getLowerBound();
        double max = full.getUpperBound();
        double value = axis.getLowerBound();
        double extent = axis.getRange().getLength();
        int iValue = (int)((value-min)/(max-min) * MAX);
        int iExtent = (int)((extent)/(max-min) * MAX);
        super.setExtent(iExtent);
        super.setValue(iValue);
        System.out.println("Full range/axis range: " + full + ", " + axis.getRange());
        System.out.println("Value/Extent/Min/Max: " + getValue() + ", " + getExtent() + ", " + this.getMinimum()+ ", " + getMaximum());
        super.fireStateChanged();
    }
    public void setValue(int value){
        System.out.println("Value/Extent: " + getValue() + ", " + getExtent());
        Range full = plot.getDataRange(axis);
        double length = full.getLength();
        Range oldRange = axis.getRange();
        double newLower = full.getLowerBound() + value*length/(1.0*MAX);
        axis.setLowerBound(newLower);
        axis.setUpperBound(oldRange.getUpperBound() - oldRange.getLowerBound() + newLower);
        super.setValue(value);
    }
}

kumat
Posts: 5
Joined: Mon Jul 13, 2015 7:37 am
antibot: No, of course not.

Re: Dislpay multiple gantt tasks in a single row

Post by kumat » Thu Jul 23, 2015 11:10 am

Thank you very much. I used the third option! This was exactly the scrollbar function i searched for. My company (C*core) has now purchased a
JFreeChart Developer Guide :).

Locked