Help Needed on XYPlot

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
sri_krishni
Posts: 10
Joined: Thu Nov 15, 2007 10:36 pm

Help Needed on XYPlot

Post by sri_krishni » Mon Mar 03, 2008 8:16 pm

Hi,
I have been using JFreechart only for a while. I had few other issues earlier and had gone thro this forum, got some info and fixed those. But for this issue, even after searching thro this forum, I could not get much info. Please help me out.

The image is posted in the below URL :
farm4.static.flickr.com/3057/2308256082_1cb79025ee.jpg?v=0

I am using a combination of XYPlot, XYDifferenceRenderer, TimeseriesCollection, XYBarRenderer, DateAxis, NumberAxis, StandardXYItemRenderer to create the chart shown in the above URL.

I have two problems.

1) I would like to have the right side Y-Axis and X-axis combination to be similar to left side Y-Axis and X-axis combination. In other words, there are few spaces between the last entry of X-axis and right side Y-Axis and this makes the black line look detached from the right side Y-Axis. FYI. I am setting the minimum and maximum dates for the X-axis.

2) I want the (red)bars to be center aligned with respect to the tick units of X-Axis. Now it looks like right aligned.

Appreciate if someone can provide any lead.

Thanks.

sri_krishni
Posts: 10
Joined: Thu Nov 15, 2007 10:36 pm

Post by sri_krishni » Mon Mar 24, 2008 9:21 pm

Dave / Richard,
Appreciate if you can help me out.

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

Post by paradoxoff » Tue Mar 25, 2008 9:39 am

Hi,
the alignment of the buttons probably just reflects the x-values of your timeSeries data and the positions of the tick marks. If your timeSeries data has one data point at noon of each day and if the tick marks are drawn at midnight then you will get the behaviour shown in your image.
If this is not the case, maybe DateAxis.setTickMarkPosition(DateTickMarkPosition position) can help you.
The extra space on the right of the x-axis might also come from a subtle additional time gap in your data.
Regards, paradoxoff
[Edit] I just looked at the chart again, and the tick labels on the x-axis are rotated. AFAIK, rotated labels are only supported by a CategoryAxis. How did you make the DateAxis support rotate labels?

sri_krishni
Posts: 10
Joined: Thu Nov 15, 2007 10:36 pm

Post by sri_krishni » Tue Mar 25, 2008 7:44 pm

First of all, thanks a bunch to you paradoxoff for taking your time to look into the problem.
I will go thro the code again to see if there any traces of the scenarios that you had mentioned.
I will also take a look at the setTickMarkPosition method though I had already looked at that method once without much value.
To answer your question, this is what I used.
DateAxis domainAxis = new DateAxis("Time Range");
domainAxis.setVerticalTickLabels(true);

------------------
And, if I can't get that alignment right by myself, would you mind me sending sample code to you for you to take a look at it ?

Thanks again..

sri_krishni
Posts: 10
Joined: Thu Nov 15, 2007 10:36 pm

Post by sri_krishni » Tue Mar 25, 2008 8:15 pm

Paradoxoff,
I tried what you had suggested, the setTickMarkPosition method. I tried setting it to MIDDLE and the red bars came fine just as I wanted. Thanks for your suggestion.
But the black line and blue band stay at the same place they were last time (even though the red bars display nicely now, still the logical position for the x-axis tick mark is not right. Thatswhy I guess the blue band and black line stop well before the end.)
If you want the screen shot after the change, let me know. I will upload it somewhere or will send that to you thro email.

Thanks a ton. Appreciate it.

sri_krishni
Posts: 10
Joined: Thu Nov 15, 2007 10:36 pm

Post by sri_krishni » Tue Mar 25, 2008 8:28 pm

Paradoxoff,
I just noticed it. I was in an happy mood for the red bars came fine that I didn't notice one thing. Now the blue band's points are not relative to the x-axis tick mark.

sri_krishni
Posts: 10
Joined: Thu Nov 15, 2007 10:36 pm

Post by sri_krishni » Tue Mar 25, 2008 8:45 pm

Paradoxoff,
The URL of the modified chart : http://farm4.static.flickr.com/3096/236 ... 4d6a_m.jpg

The URL of the old one (same as the one in my initial post) :
farm4.static.flickr.com/3057/2308256082_1cb79025ee.jpg?v=0

Thanks.

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

Post by paradoxoff » Tue Mar 25, 2008 11:08 pm

When I compare the first and the actual image, the data points for the blue, green and black band are completely different. I can´t imagine that this can come from a change of the tick mark positions ? Have you changed the data in between?
If the new range for the series mentioned above is intended, it seems that the only problem is a shift of the green/blue/black series half a month to the past (or of the read series half a month to the future).
The discrepancy might either come from the data points that you are using. If the data points are misaligned (i.e. if the data points for the red bars are indeed half a month earlier than the data points of the other series) then you will have to change the data to get the visualization right. A "display artifact" from the XYBarRenderer might also be an issue. To get a better idea about where the visual discrepancy comes from (from the data or the renderer), you could try to change the renderer for the data sets and check whether the outcome is different.
Without seeing any code (especially the data) it is nearly impossible to suggest a real solution.
Regards
Paradoxoff

sri_krishni
Posts: 10
Joined: Thu Nov 15, 2007 10:36 pm

Post by sri_krishni » Wed Mar 26, 2008 5:39 pm

Paradoxoff,
Thanks for your reply. I guess your last point made sense. Without seeing the code and data, it will be difficult to suggest anything. Hence, I have hard-coded the values needed to build the chart in an action class. Will this help you ? If so, please let me know how can I send that to you. If not, please let me know how you want the class to be. Thanks for your continued response.

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

Post by paradoxoff » Thu Mar 27, 2008 3:09 pm

What about posting the code of your ActionClass in this thread? Then other people will have an opportunity to check as well.
Keep in mind that it should be as short as possible. Sometimes the reason for odd behaviour becomes clear when you try to trim the code.

sri_krishni
Posts: 10
Joined: Thu Nov 15, 2007 10:36 pm

Post by sri_krishni » Thu Mar 27, 2008 7:16 pm

Thanks for your reply. I converted the file to a Java application so that you can run this as you run any simple java application. Thanks for your help paradoxoff.

*****************************************************
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Paint;
import java.awt.Stroke;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.DefaultDrawingSupplier;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.renderer.xy.XYDifferenceRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.time.Month;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

/**
* This class will be used to generate the Forecast Accuracy Chart
*
*/
public class GenerateFrcstAccChart extends ApplicationFrame {

public GenerateFrcstAccChart(final String title) {
super(title);
}

public void execute() {
JFreeChart chart = generateFrcstAccChart();
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}

/**
* This method will populate calendars for year 2007
* starting from January till December
*/
private List getCalendars() {
List calendars = new ArrayList();
Calendar startDtCalendar = new GregorianCalendar();
startDtCalendar.set(Calendar.DATE, 1);
startDtCalendar.set(Calendar.MONTH, 0);
startDtCalendar.set(Calendar.YEAR, 2007);
Calendar tempCalendar = null;
for (int indx = 1; indx <= 12; indx++) {
tempCalendar = new GregorianCalendar();
tempCalendar.setTimeInMillis(startDtCalendar.getTimeInMillis());
calendars.add(tempCalendar);
startDtCalendar.add(Calendar.MONTH, 1);
}

return calendars;
}

/**
* This method will create the chart
*/
private JFreeChart generateFrcstAccChart() {
List calendars = getCalendars();
final TimeSeriesCollection areaSet = getFrcstAreaSet(calendars);

XYPlot plot = new XYPlot();
setAxisValuesForPlot(plot);
plot.setDataset(0, areaSet);
plot.setRenderer(0, getAreaRenderer());

setFctryShipDataSet(plot, calendars);

final XYBarRenderer barRenderer = new XYBarRenderer();
barRenderer.setMargin(0.5);
Color historyColor = new Color(255, 0, 0);
barRenderer.setSeriesPaint(0, historyColor);

plot.setRenderer(1, barRenderer);
plot.mapDatasetToRangeAxis(1, 0);

setDeviationDataSet(plot, calendars);

plot.setRenderer(2, getLineRenderer());
plot.mapDatasetToRangeAxis(2, 1);

setTargetDataSet(plot, calendars);

plot.setRenderer(3, getTargetRenderer());
plot.mapDatasetToRangeAxis(3, 1);

plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);

plot.setOrientation(PlotOrientation.VERTICAL);

// for the dotted horizontal lines in the chart area
Stroke stroke =
new BasicStroke(
1.5f,
BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_MITER,
1,
new float[] {5,4},
0);
plot.setRangeGridlineStroke(stroke);
Paint paint = new Color(65, 65, 65);
plot.setRangeGridlinePaint(paint);

// to not display the vertical lines in the chart area
plot.setDomainGridlinesVisible(false);

final JFreeChart chart =
createChart(plot, "");
chart.removeLegend();
chart.setBackgroundPaint(Color.WHITE);

LegendTitle title = new LegendTitle(plot);
chart.addLegend(title);
title.setItemFont(new Font("Arial",1,15));
title.setBorder(2,2,2,2);

return chart;
}

private XYDifferenceRenderer getAreaRenderer() {
final XYDifferenceRenderer areaRenderer = new XYDifferenceRenderer();
areaRenderer.setSeriesVisibleInLegend(1, new Boolean(false));
areaRenderer.setSeriesPaint(0, Color.BLACK);
Color blue = new Color(136, 196, 255);
areaRenderer.setPositivePaint(blue);
areaRenderer.setSeriesPaint(1, Color.BLACK);

return areaRenderer;
}

/**
* This method will create the data set for the blue band
*/
private TimeSeriesCollection getFrcstAreaSet(List calendars) {
final TimeSeriesCollection areaSet = new TimeSeriesCollection();
List upperRangeFrcstDta = new ArrayList();
upperRangeFrcstDta.add(new Double(12));
upperRangeFrcstDta.add(new Double(16.8));
upperRangeFrcstDta.add(new Double(22.8));
upperRangeFrcstDta.add(new Double(10.8));
upperRangeFrcstDta.add(new Double(15.6));
upperRangeFrcstDta.add(new Double(21.6));
upperRangeFrcstDta.add(new Double(6));
upperRangeFrcstDta.add(new Double(28.8));
upperRangeFrcstDta.add(new Double(13.2));
upperRangeFrcstDta.add(new Double(10.8));
upperRangeFrcstDta.add(new Double(7.2));
upperRangeFrcstDta.add(new Double(9.6));

List lowerRangeFrcstDta = new ArrayList();
lowerRangeFrcstDta.add(new Double(8.0));
lowerRangeFrcstDta.add(new Double(11.2));
lowerRangeFrcstDta.add(new Double(15.2));
lowerRangeFrcstDta.add(new Double(7.2));
lowerRangeFrcstDta.add(new Double(10.4));
lowerRangeFrcstDta.add(new Double(14.4));
lowerRangeFrcstDta.add(new Double(4.0));
lowerRangeFrcstDta.add(new Double(19.2));
lowerRangeFrcstDta.add(new Double(8.8));
lowerRangeFrcstDta.add(new Double(7.2));
lowerRangeFrcstDta.add(new Double(4.8));
lowerRangeFrcstDta.add(new Double(6.4));

areaSet.addSeries(
convertToSeries(upperRangeFrcstDta, calendars, "Forecast"));
areaSet.addSeries(
convertToSeries(lowerRangeFrcstDta, calendars, "Lower Bound"));

return areaSet;
}

/**
* This method will set the x-axis
*/
private void setAxisValuesForPlot(XYPlot xyPlot) {
final DateAxis domainAxis =
new DateAxis("Range");
domainAxis.setDateFormatOverride(new SimpleDateFormat("MMM-yy"));
final NumberAxis deviationAxis =
new NumberAxis("%".concat("deviation"));
final NumberAxis forecastAxis =
new NumberAxis("Planned Factory Shipments");

xyPlot.setRangeAxis(0, forecastAxis);
xyPlot.setDomainAxis(0, domainAxis);
xyPlot.setRangeAxis(1, deviationAxis);

domainAxis.setVerticalTickLabels(true);
domainAxis.setLabelFont(new Font("Arial",1,13));
domainAxis.setTickLabelFont(new Font("Arial",1,12));

domainAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);

// set the date ranges (the dates are not starting and ending at proper places otherwise)
Calendar startDate = new GregorianCalendar();
startDate.set(Calendar.DATE, 1);
startDate.set(Calendar.MONTH, 0);
startDate.set(Calendar.YEAR, 2007);
domainAxis.setMinimumDate(startDate.getTime());

Calendar endDate = new GregorianCalendar();
endDate.set(Calendar.DATE, 1);
endDate.set(Calendar.MONTH, 0);
endDate.set(Calendar.YEAR, 2008);
domainAxis.setMaximumDate(endDate.getTime());

forecastAxis.setLabelFont(new Font("Arial",1,13));
forecastAxis.setTickLabelFont(new Font("Arial",1,12));

deviationAxis.setLabelFont(new Font("Arial",1,13));
deviationAxis.setTickLabelFont(new Font("Arial",1,12));
}

/**
* This method will create the data set for the red bars
*/
private void setFctryShipDataSet(XYPlot xyPlot, List calendars) {
final TimeSeriesCollection barSet = new TimeSeriesCollection();
List factoryDta = new ArrayList();
factoryDta.add(new Double(10));
factoryDta.add(new Double(3));
factoryDta.add(new Double(9));
factoryDta.add(new Double(13));
factoryDta.add(new Double(15));
factoryDta.add(new Double(7));
factoryDta.add(new Double(6));
factoryDta.add(new Double(5));
factoryDta.add(new Double(14));
factoryDta.add(new Double(14));
factoryDta.add(new Double(3));
factoryDta.add(new Double(15));

barSet.addSeries(
convertToSeries(
factoryDta,
calendars,
"Factory Shipments"));
xyPlot.setDataset(1, barSet);
}

/**
* This method will create the data set for the green line
*/
private void setDeviationDataSet(XYPlot xyPlot, List calendars) {
final TimeSeriesCollection deviationSet = new TimeSeriesCollection();
List deviationDta = new ArrayList();
deviationDta.add(new Double(44.26470588235295));
deviationDta.add(new Double(24.264705882352942));
deviationDta.add(new Double(33.19327731092437));
deviationDta.add(new Double(33.63187380215244));
deviationDta.add(new Double(41.03928120955985));
deviationDta.add(new Double(31.83867789130947));
deviationDta.add(new Double(42.023863076494656));
deviationDta.add(new Double(45.35719640982799));
deviationDta.add(new Double(45.45640275903434));
deviationDta.add(new Double(41.229927479927476));
deviationDta.add(new Double(43.08177933177933));
deviationDta.add(new Double(48.851010101010104));

deviationSet.addSeries(
convertToSeries(
deviationDta, calendars,
"Deviation"));
xyPlot.setDataset(2, deviationSet);
}

/**
* This method will create the data set for the black line
*/
private void setTargetDataSet(XYPlot xyPlot, List calendars) {
final TimeSeriesCollection targetSet = new TimeSeriesCollection();
List targetCalendars = new ArrayList();
targetCalendars.add(calendars.get(9));
targetCalendars.add(calendars.get(10));
targetCalendars.add(calendars.get(11));

List targetDta = new ArrayList();
targetDta.add(new Double(20));
targetDta.add(new Double(20));
targetDta.add(new Double(20));
targetSet.addSeries(
convertToSeries(targetDta, targetCalendars, "Target"));
xyPlot.setDataset(3, targetSet);
}

private StandardXYItemRenderer getLineRenderer() {
StandardXYItemRenderer lineRenderer = new StandardXYItemRenderer();
lineRenderer.setSeriesStroke(0, new BasicStroke(3));
Color green = new Color(0, 155, 0);
lineRenderer.setSeriesPaint(0, green);

return lineRenderer;
}

private StandardXYItemRenderer getTargetRenderer() {
StandardXYItemRenderer targetRenderer = new StandardXYItemRenderer();
targetRenderer.setSeriesStroke(0, new BasicStroke(3));
targetRenderer.setSeriesPaint(0, Color.BLACK);

return targetRenderer;
}

private JFreeChart createChart(XYPlot xyPlot, String partialTitleTxt) {
StringBuffer titleTxt = new StringBuffer();
titleTxt.append("Chart");
titleTxt.append(" - ").append(partialTitleTxt);
final JFreeChart freeChart =
new JFreeChart(
titleTxt.toString(),
JFreeChart.DEFAULT_TITLE_FONT,
xyPlot,
true);
freeChart.getPlot().setDrawingSupplier(
new DefaultDrawingSupplier(
new Paint[] {
Color.BLACK,
Color.BLUE },
DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE));
freeChart.removeLegend();
LegendTitle title = new LegendTitle(xyPlot);
freeChart.addLegend(title);

return freeChart;
}

private TimeSeries convertToSeries(List unitList, List calendars, String seriesName) {
Calendar calendar = Calendar.getInstance();
TimeSeries timeSeries = new TimeSeries(seriesName, Month.class);
Iterator unitIter = unitList.iterator();
Double unit = null;
int calendarIndx = 0;
while (unitIter.hasNext()) {
unit = (Double) unitIter.next();
calendar.setTime(((Calendar)calendars.get(calendarIndx++)).getTime());
timeSeries.add(
new Month(
calendar.get(Calendar.MONTH) + 1,
calendar.get(Calendar.YEAR)),
new Double(unit.doubleValue()));
}

return timeSeries;
}

public static void main(final String[] args) {
final GenerateFrcstAccChart demo = new GenerateFrcstAccChart("Forecast Accuracy Chart Demo");
demo.execute();
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
**********************************************************

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

Post by paradoxoff » Fri Mar 28, 2008 8:36 pm

Finally figured out the reason...
First, I changed the renderer for the barSet to a normal XYLineAndShapeRenderer, and all of a sudden the data points of the barSet were aligned with the others. So the different visualization came from the renderer.
I then checked XYBarRenderer.drawItem because I wondered how the starting and ending x value for the rectangle representing the data point came from. They are retrieved by calling IntervalXYDataset.getStartXValue() and IntervalXYDataset.getEndXValue(). Next question: what is the return value of these two methods for a TimeSeriesCollection? The values are the results of the respective RegularTimePeriod.getFirstMilliSecond() and RegularTimePeriod.getLastMilliSecond(). And for an instance of Month, these are of course the first and last millisecond of a month.
So the bar is starting at the beginning of the month and ends at the end of a month and thus appears around the middle of the month instead around the beginning of the month, and thats were the strange offset is coming from.
I then tried to change your convertToSeries method to make it use days instead of months. As expected, that reduced the discrepancy between the areaSet datapoints and the other data point from half a month to half a day but also made the bars very thin.
I then implemented a second method convertToMonthSeries that would create a month-based TimeSeriesCollection and changed the old convertToSeries method to use days and used a Day-constructor with a fixed day value of 14. That made the thing look better but it was still somewhat misaligned.
At that point I was about to post this response, but finally had a look at the API because I wanted to know how the return value of the getXValue method is calculated. It turned out that this value is either the first or the last or the middle millisecond of the RegularTimePeriod depending on the xPosition value of the TimeSeriesCollection which is either TimePeriodAnchor.START, .MIDDLE or .END The default value is of course .START. So if we can´t shift the center of gravity of the bars to the beginning of the month we have to shift the data points of the remaining data points to the middle of the month by calling TimeSeriesCollection.setXPosition(TimePeriodAnchor.MIDDLE);
Can it be so simple? I guess yes. Here is the code. Enjoy. I think I learned a lot during the last hour :D
Regards, Paradoxoff
Note that I removed the Servlet and struts import statements and added other imports that may not be necessary in the final version. I also changed the format and fonts of the x-axis for better debugging. But I am sure that you will be able to revert these changes.

Code: Select all

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Paint;
import java.awt.Stroke;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.DefaultDrawingSupplier;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.renderer.xy.XYDifferenceRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.time.Month;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimePeriodAnchor;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

/**
* This class will be used to generate the Forecast Accuracy Chart
*
*/
public class GenerateFrcstAccChart extends ApplicationFrame {
	
	public GenerateFrcstAccChart(final String title) {
		super(title);
	}
	
	public void execute() {
		JFreeChart chart = generateFrcstAccChart();
		final ChartPanel chartPanel = new ChartPanel(chart);
		chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
		setContentPane(chartPanel);
	}
	
	/**
	* This method will populate calendars for year 2007
	* starting from January till December
	*/
	private List getCalendars() {
		List calendars = new ArrayList();
		Calendar startDtCalendar = new GregorianCalendar();
		startDtCalendar.set(Calendar.DATE,1);
		startDtCalendar.set(Calendar.MONTH, 0);
		startDtCalendar.set(Calendar.YEAR, 2007);
		Calendar tempCalendar = null;
		for (int indx = 1; indx <= 12; indx++) {
			tempCalendar = new GregorianCalendar();
			tempCalendar.setTimeInMillis(startDtCalendar.getTimeInMillis());
			calendars.add(tempCalendar);
			startDtCalendar.add(Calendar.MONTH, 1);
		}
		
		return calendars;
	}
	
	/**
	* This method will create the chart
	*/
	private JFreeChart generateFrcstAccChart() {
		List calendars = getCalendars();
		final TimeSeriesCollection areaSet = getFrcstAreaSet(calendars);
		areaSet.setXPosition(TimePeriodAnchor.MIDDLE);
		XYPlot plot = new XYPlot();
		setAxisValuesForPlot(plot);
		plot.setDataset(0, areaSet);
		plot.setRenderer(new XYLineAndShapeRenderer(true,true));
		plot.setRenderer(0, getAreaRenderer());
		
		setFctryShipDataSet(plot, calendars);
		
		final XYBarRenderer barRenderer = new XYBarRenderer();
		barRenderer.setMargin(0.5);
		Color historyColor = new Color(255, 0, 0);
		barRenderer.setSeriesPaint(0, historyColor);
		
		plot.setRenderer(1, barRenderer);
		plot.mapDatasetToRangeAxis(1, 0);
		
		setDeviationDataSet(plot, calendars);
		
		plot.setRenderer(2, getLineRenderer());
		plot.mapDatasetToRangeAxis(2, 1);
		
		setTargetDataSet(plot, calendars);
		
		plot.setRenderer(3, getTargetRenderer());
		plot.mapDatasetToRangeAxis(3, 1);
		
		plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
		
		plot.setOrientation(PlotOrientation.VERTICAL);
		
		// for the dotted horizontal lines in the chart area
		Stroke stroke =
		new BasicStroke(
		1.5f,
		BasicStroke.CAP_SQUARE,
		BasicStroke.JOIN_MITER,
		1,
		new float[] {5,4},
		0);
		plot.setRangeGridlineStroke(stroke);
		Paint paint = new Color(65, 65, 65);
		plot.setRangeGridlinePaint(paint);
		
		// to not display the vertical lines in the chart area
		plot.setDomainGridlinesVisible(false);
		
		final JFreeChart chart =
		createChart(plot, "");
		chart.removeLegend();
		chart.setBackgroundPaint(Color.WHITE);
		
		LegendTitle title = new LegendTitle(plot);
		chart.addLegend(title);
		title.setItemFont(new Font("Arial",1,15));
		title.setBorder(2,2,2,2);
		
		return chart;
	}
	
	private XYDifferenceRenderer getAreaRenderer() {
		final XYDifferenceRenderer areaRenderer = new XYDifferenceRenderer();
		areaRenderer.setSeriesVisibleInLegend(1, new Boolean(false));
		areaRenderer.setSeriesPaint(0, Color.BLACK);
		Color blue = new Color(136, 196, 255);
		areaRenderer.setPositivePaint(blue);
		areaRenderer.setSeriesPaint(1, Color.BLACK);
		
		return areaRenderer;
	}
	
	/**
	* This method will create the data set for the blue band
	*/
	private TimeSeriesCollection getFrcstAreaSet(List calendars) {
		final TimeSeriesCollection areaSet = new TimeSeriesCollection();
		List upperRangeFrcstDta = new ArrayList();
		upperRangeFrcstDta.add(new Double(12));
		upperRangeFrcstDta.add(new Double(16.8));
		upperRangeFrcstDta.add(new Double(22.8));
		upperRangeFrcstDta.add(new Double(10.8));
		upperRangeFrcstDta.add(new Double(15.6));
		upperRangeFrcstDta.add(new Double(21.6));
		upperRangeFrcstDta.add(new Double(6));
		upperRangeFrcstDta.add(new Double(28.8));
		upperRangeFrcstDta.add(new Double(13.2));
		upperRangeFrcstDta.add(new Double(10.8));
		upperRangeFrcstDta.add(new Double(7.2));
		upperRangeFrcstDta.add(new Double(9.6));
		
		List lowerRangeFrcstDta = new ArrayList();
		lowerRangeFrcstDta.add(new Double(8.0));
		lowerRangeFrcstDta.add(new Double(11.2));
		lowerRangeFrcstDta.add(new Double(15.2));
		lowerRangeFrcstDta.add(new Double(7.2));
		lowerRangeFrcstDta.add(new Double(10.4));
		lowerRangeFrcstDta.add(new Double(14.4));
		lowerRangeFrcstDta.add(new Double(4.0));
		lowerRangeFrcstDta.add(new Double(19.2));
		lowerRangeFrcstDta.add(new Double(8.8));
		lowerRangeFrcstDta.add(new Double(7.2));
		lowerRangeFrcstDta.add(new Double(4.8));
		lowerRangeFrcstDta.add(new Double(6.4));
		
		areaSet.addSeries(
		convertToSeries(upperRangeFrcstDta, calendars, "Forecast"));
		areaSet.addSeries(
		convertToSeries(lowerRangeFrcstDta, calendars, "Lower Bound"));
		
		return areaSet;
	}
	
	/**
	* This method will set the x-axis
	*/
	private void setAxisValuesForPlot(XYPlot xyPlot) {
		final DateAxis domainAxis = new DateAxis("Range");
		domainAxis.setDateFormatOverride(new SimpleDateFormat("dd.MM.yy HH:mm"));
		final NumberAxis deviationAxis =
		new NumberAxis("%".concat("deviation"));
		final NumberAxis forecastAxis =
		new NumberAxis("Planned Factory Shipments");
		
		xyPlot.setRangeAxis(0, forecastAxis);
		xyPlot.setDomainAxis(0, domainAxis);
		xyPlot.setRangeAxis(1, deviationAxis);
		
		domainAxis.setVerticalTickLabels(true);
		
		//domainAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
		
		// set the date ranges (the dates are not starting and ending at proper places otherwise)
		Calendar startDate = new GregorianCalendar();
		startDate.set(Calendar.DATE, 1);
		startDate.set(Calendar.MONTH, 0);
		startDate.set(Calendar.YEAR, 2007);
		domainAxis.setMinimumDate(startDate.getTime());
		
		Calendar endDate = new GregorianCalendar();
		endDate.set(Calendar.DATE, 1);
		endDate.set(Calendar.MONTH, 0);
		endDate.set(Calendar.YEAR, 2008);
		domainAxis.setMaximumDate(endDate.getTime());
		
		forecastAxis.setLabelFont(new Font("Arial",1,13));
		forecastAxis.setTickLabelFont(new Font("Arial",1,12));
		
		deviationAxis.setLabelFont(new Font("Arial",1,13));
		deviationAxis.setTickLabelFont(new Font("Arial",1,12));
	}
	
	/**
	* This method will create the data set for the red bars
	*/
	private void setFctryShipDataSet(XYPlot xyPlot, List calendars) {
		final TimeSeriesCollection barSet = new TimeSeriesCollection();
		barSet.setXPosition(TimePeriodAnchor.MIDDLE);
		List factoryDta = new ArrayList();
		factoryDta.add(new Double(10));
		factoryDta.add(new Double(3));
		factoryDta.add(new Double(9));
		factoryDta.add(new Double(13));
		factoryDta.add(new Double(15));
		factoryDta.add(new Double(7));
		factoryDta.add(new Double(6));
		factoryDta.add(new Double(5));
		factoryDta.add(new Double(14));
		factoryDta.add(new Double(14));
		factoryDta.add(new Double(3));
		factoryDta.add(new Double(15));
		
		barSet.addSeries(
		convertToSeries(
		factoryDta,
		calendars,
		"Factory Shipments"));
		xyPlot.setDataset(1, barSet);
	}
	
	/**
	* This method will create the data set for the green line
	*/
	private void setDeviationDataSet(XYPlot xyPlot, List calendars) {
		final TimeSeriesCollection deviationSet = new TimeSeriesCollection();
		deviationSet.setXPosition(TimePeriodAnchor.MIDDLE);
		List deviationDta = new ArrayList();
		deviationDta.add(new Double(44.26470588235295));
		deviationDta.add(new Double(24.264705882352942));
		deviationDta.add(new Double(33.19327731092437));
		deviationDta.add(new Double(33.63187380215244));
		deviationDta.add(new Double(41.03928120955985));
		deviationDta.add(new Double(31.83867789130947));
		deviationDta.add(new Double(42.023863076494656));
		deviationDta.add(new Double(45.35719640982799));
		deviationDta.add(new Double(45.45640275903434));
		deviationDta.add(new Double(41.229927479927476));
		deviationDta.add(new Double(43.08177933177933));
		deviationDta.add(new Double(48.851010101010104));
		
		deviationSet.addSeries(
		convertToSeries(
		deviationDta, calendars,
		"Deviation"));
		xyPlot.setDataset(2, deviationSet);
	}
	
	/**
	* This method will create the data set for the black line
	*/
	private void setTargetDataSet(XYPlot xyPlot, List calendars) {
		final TimeSeriesCollection targetSet = new TimeSeriesCollection();
		targetSet.setXPosition(TimePeriodAnchor.MIDDLE);

		List targetCalendars = new ArrayList();
		targetCalendars.add(calendars.get(9));
		targetCalendars.add(calendars.get(10));
		targetCalendars.add(calendars.get(11));
		
		List targetDta = new ArrayList();
		targetDta.add(new Double(20));
		targetDta.add(new Double(20));
		targetDta.add(new Double(20));
		targetSet.addSeries(
		convertToSeries(targetDta, targetCalendars, "Target"));
		xyPlot.setDataset(3, targetSet);
	}
	
	private StandardXYItemRenderer getLineRenderer() {
		StandardXYItemRenderer lineRenderer = new StandardXYItemRenderer();
		lineRenderer.setSeriesStroke(0, new BasicStroke(3));
		Color green = new Color(0, 155, 0);
		lineRenderer.setSeriesPaint(0, green);
		
		return lineRenderer;
	}
	
	private StandardXYItemRenderer getTargetRenderer() {
		StandardXYItemRenderer targetRenderer = new StandardXYItemRenderer();
		targetRenderer.setSeriesStroke(0, new BasicStroke(3));
		targetRenderer.setSeriesPaint(0, Color.BLACK);
		
		return targetRenderer;
	}
	
	private JFreeChart createChart(XYPlot xyPlot, String partialTitleTxt) {
		StringBuffer titleTxt = new StringBuffer();
		titleTxt.append("Chart");
		titleTxt.append(" - ").append(partialTitleTxt);
		final JFreeChart freeChart =
		new JFreeChart(
		titleTxt.toString(),
		JFreeChart.DEFAULT_TITLE_FONT,
		xyPlot,
		true);
		freeChart.getPlot().setDrawingSupplier(
		new DefaultDrawingSupplier(
		new Paint[] {
		Color.BLACK,
		Color.BLUE },
		DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE,
		DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
		DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
		DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE));
		freeChart.removeLegend();
		LegendTitle title = new LegendTitle(xyPlot);
		freeChart.addLegend(title);
		
		return freeChart;
	}
	
	private TimeSeries convertToDaySeries(List unitList, List calendars, String seriesName) {
		Calendar calendar = Calendar.getInstance();
		//TimeSeries timeSeries = new TimeSeries(seriesName, Month.class);
		TimeSeries timeSeries = new TimeSeries(seriesName, Day.class);
		Iterator unitIter = unitList.iterator();
		Double unit = null;
		int calendarIndx = 0;
			while (unitIter.hasNext()) {
			unit = (Double) unitIter.next();
			calendar.setTime(((Calendar)calendars.get(calendarIndx++)).getTime());
			timeSeries.add(
			/*new Month(
			calendar.get(Calendar.MONTH) + 1,
			calendar.get(Calendar.YEAR)),*/
			new Day(
			14,
			calendar.get(Calendar.MONTH) + 1,
			calendar.get(Calendar.YEAR)),
			new Double(unit.doubleValue()));
		}
	
	return timeSeries;
	}

	private TimeSeries convertToSeries(List unitList, List calendars, String seriesName) {
		Calendar calendar = Calendar.getInstance();
		TimeSeries timeSeries = new TimeSeries(seriesName, Month.class);
		//TimeSeries timeSeries = new TimeSeries(seriesName, Day.class);
		Iterator unitIter = unitList.iterator();
		Double unit = null;
		int calendarIndx = 0;
			while (unitIter.hasNext()) {
			unit = (Double) unitIter.next();
			calendar.setTime(((Calendar)calendars.get(calendarIndx++)).getTime());
			timeSeries.add(
			new Month(
			calendar.get(Calendar.MONTH) + 1,
			calendar.get(Calendar.YEAR)),
			/*new Day(
			calendar.get(Calendar.DAY_OF_MONTH),
			calendar.get(Calendar.MONTH) + 1,
			calendar.get(Calendar.YEAR)),*/
			new Double(unit.doubleValue()));
		}
	
	return timeSeries;
	}
	
	public static void main(final String[] args) {
		final GenerateFrcstAccChart demo = new GenerateFrcstAccChart("Forecast Accuracy Chart Demo");
		demo.execute();
		demo.pack();
		RefineryUtilities.centerFrameOnScreen(demo);
		demo.setVisible(true);
	}
} 

sri_krishni
Posts: 10
Joined: Thu Nov 15, 2007 10:36 pm

Post by sri_krishni » Mon Mar 31, 2008 8:40 pm

Paradoxoff,
I checked out the code and it works fine. I am at loss of words to express my thanks. However, thanks for the effort that you had taken to fix this. Really appreciate your help !!! Thanks !! Thanks !! Thanks !!

Regards


PS : Its not that important.. But, is it possible to make the chart look like the one in the given URL ? Of course, the data is different in the given chart. But check for the right & left extreme bars. They are shown only half and this makes the other lines start and end at the appropriate places.
http://farm3.static.flickr.com/2297/237 ... 19e105.jpg

Locked