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:
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.
Dislpay multiple gantt tasks in a single row
-
- Posts: 1634
- Joined: Sat Feb 17, 2007 1:51 pm
Re: Dislpay multiple gantt tasks in a single row
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);
}
}
Re: Dislpay multiple gantt tasks in a single row
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.
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.
-
- Posts: 1634
- Joined: Sat Feb 17, 2007 1:51 pm
Re: Dislpay multiple gantt tasks in a single row
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.
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);
}
}
Re: Dislpay multiple gantt tasks in a single row
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 .
JFreeChart Developer Guide .