Wednesday, April 23, 2008

Customizing JFreeChart – Pie Chart






Introduction


Dynamic representation of data in picture format is inevitable in this programming era. JFreeChart is one of the best open sources in Java World in providing APIs to display dynamic charts viz., Line Chart, Bar Chart, Pie Chart etc., A wide collection of APIs are available under LGPL license not only to generate different charts but also to customize the generated charts with our own look and feel. My projects are basically Portal Applications that involve displaying a Pie Chart for the backend data. As the creation of pie chart just takes two or three lines, I felt it is important to explore more ways to customize the chart generated and the result is this blog. Following section briefly describes various ways to customize pie chart generated using JFreeChart.


Getting Started


For generating and displaying JFreeCharts we need to include certain libraries which are available in JFreeChart web page.
Place these jar files in your WEB-INF/lib folder:



1.jfreechart-*.jar
2.jcommon-*.jar


Creating a Pie Chart using JFreeChart libraries



Creation of pie chart won’t take you too many lines as it mainly needs the dataset for which you need to generate the chart apart from other details like Chart Title, Flag to say whether we need Legend or not etc., Following code shows a way to create a pie chart with available dataset and customize it in many available ways.



1: import java.awt.Color;
2: import java.text.AttributedString;
3: import java.util.List;
4: import org.jfree.chart.ChartFactory;
5: import org.jfree.chart.JFreeChart;
6: import org.jfree.chart.labels.PieSectionLabelGenerator;
7: import org.jfree.chart.plot.PiePlot;
8: import org.jfree.chart.plot.Plot;
9: import org.jfree.chart.title.TextTitle;
10: import org.jfree.data.general.DefaultPieDataset;
11: import org.jfree.data.general.PieDataset;
12: import org.jfree.ui.RectangleInsets;
13: import org.jfree.util.UnitType;

/*
* This class is used to create a sample pie chart using JFreeChart and customize it
*/

14: public class CustomizePieChart {
15: public static JFreeChart customizeSamplePieChart( ) {
/* Creating a sample Pie Dataset */
16: final DefaultPieDataset data =
new DefaultPieDataset ( );

/* Storing the sample Pie Chart Data in Pie dataset */
17: data.setValue("Software Engineer",50);
18: data.setValue("Programmer Analyst",20);
19: data.setValue("Technical Specialist",25);
20: data.setValue("Project Manager",10);

/* Create a Pie Chart */
/* Let the Legend be present */

21: final boolean withLegend = true;
22: final JFreeChart chart =
ChartFactory.createPieChart("Employee Survey",
data, withLegend, true, true );

/* Creating a pieplot so as to customize the chart generated */
23: final PiePlot plot = (PiePlot)chart.getPlot( );

/* Customizing Label using an inner class */
24: plot.setLabelGenerator(new CustomLabelGenerator( ));

/* Setting the BackGround Paint for Label */
25: plot.setLabelBackgroundPaint(Color.WHITE);

Customizing a Pie Chart by creating a PiePlot



In order to customize a pie chart we need to create a plot of type PiePlot. PiePlot extends basic Plot and this plot instance is provided by a static method of JFreeChart. Once a plot is obtained we can do dozens of customizations.


Customizing Pie Chart’s label



If you have a view at dataset for which the chart will be generated, it is just a collection of (name, value) pairs. Pie chart is generated for value parameter (which must be parsable into double) whereas labels and legends are displayed based on the name given. In order to customize label, we need to create an inner class within the class in which the pie chart is generated and pass an instance of that inner class (where we set some rules of how to display the label) to a method in PiePlot which displays the label the way we defined it in the inner class. See Line no. 24 for the PiePlot’s set method and Line no. 39 for static inner class that defines how label should be displayed.



We can also customize other properties of label using PiePlot. This includes,



1.Setting Label Background
2.Setting Label outline
3.Setting Label shadow
4.Disabling label links etc.,


Customizing Pie Chart’s legend



A pie chart’s legend is optional and if we wish to have, we can also customize it the way we did for label. See Line no. 28 for PiePlot’s set method and line no. 46 for static inner class that defines how legend should be displayed. We can also set the Legend items’ shape to pre-defined shapes and the default one is circle.



/* Setting the Outline paint for the labels */
23: plot.setLabelOutlinePaint(Color.WHITE);

/* Setting the Label Shadow Paint */
24: plot.setLabelShadowPaint(Color.WHITE);

/* Setting Legend Item Shape (Default is Circle Shape) */
25: plot.setLegendItemShape(Plot.DEFAULT_LEGEND_ITEM_BOX);

26: plot.setBaseSectionOutlinePaint(Color.LIGHT_GRAY);
27: plot.setShadowPaint(Color.WHITE);


/* Customizing Label using an inner class */
28: plot.setLegendLabelGenerator(new CustomLegendGenerator());


/* Creating a Title Object and setting its value */
29: TextTitle title =
new TextTitle("Employee Survey");

/* Setting the Background Paint for the title */
30: title.setBackgroundPaint(new Color(0.294f, 0.0f, 0.513f));

/* Setting the font paint for the title */
31: title.setPaint(new
Color(1.0f, 0.549f, 0.0f));

/* Expanding the title to the entire width of the pie chart image */
32: title.setExpandToFitSpace(true);

/* Setting the title instance to the chart, atlast */
33: chart.setTitle(title);


/* Setting insets to the pie chart image */
34: plot.setInsets(new
RectangleInsets(UnitType.ABSOLUTE, 0.0, 0.0,1.0, 1.0));


/* Specifying list of colors from which a Pie Section should be painted based on our choice */
35: Color[] colors = {Color.blue, Color.yellow,
Color.green, Color.GRAY};

/* Delegating the choice of color to an inner class */
36: PieRenderer renderer = new PieRenderer(colors);
37: renderer.setColor(plot, data);

/* Returns the chart with customization */
38: return chart;
}

Customizing Pie Chart’s Title



A pie chart’s title is defined when a new JFreeChart instance is created. We can also customize the same by creating an instance of type TextTitle and setting properties on created instance. See line no. 29 to 33 for details.


Customizing Pie section colors



When you create a default pie chart, all pie sections will be painted in system selected colors which are random. If you wish to define which pie section should be painted on which color, well, you can do that by creating another inner class that defines the exact selection of colors. See line no. 36 for 54 for more details.


Miscellaneous customizations



Apart from aforementioned customizations, following are the miscellaneous ones that I hope will be helpful for you.



  1. Setting insets

    Insets for a pie chart can be customized and we can even set ZERO inset.
    See line no. 34 for ZERO insets.

  2. Setting paints for BaseSection and Shadow.



39: static class CustomLabelGenerator implements PieSectionLabelGenerator {
/**
* Set customized label in the pie chart
*
* @param dataset PieChart DataSet
* @param key Comparable Key
* @return String Result String to be displayed
*/

40: public String generateSectionLabel(final PieDataset dataset,
final Comparable key) {
/* Creating a temporary string to hold value defined by us */
41: String temp = null;
42: if (dataset != null) {
/* Assigning the Value from dataset as a label for display */
43: temp = dataset.getValue(key).toString();
/* Modifying a particular label based on the Key name */
44: if(key.toString().equalsIgnoreCase("Software

Engineer"
)) {
temp = temp + "(Trainees Not Included)";
}
}
/* Returning the formatted string back to set the label */
45: return temp;
}
}


46: static class CustomLegendGenerator
implements PieSectionLabelGenerator {
/**
* Set customized legend in the pie chart
*
* @param dataset PieChart DataSet
* @param key Comparable Key
* @return Result String to be displayed
*/

47: public String

generateSectionLabel(final PieDataset dataset,
final Comparable key) {
/* Creating a temporary string to hold value defined by us */
48: String temp = null;
49: if (dataset != null) {
/* Assigning the Value from dataset as a legend item for display */
50: temp = key.toString();
/* Modifying a particular legend item based on the Key name */
51: if(key.toString().equalsIgnoreCase("Software

Engineer"
)) {
52: temp = temp + "(Trainees

Not Included)"
;
}
}
/* Returning the formatted string back to set the label */
53: return temp;
}
}



54: static class PieRenderer
{
/* Declaring an array of Color variables for storing a list of Colors */
55: private Color[ ]

color;

/* Constructor to initialize PieRenderer class */
56: public PieRenderer(Color[ ] color)
{
57: this.color = color;
}

/**
* Set Method to set colors for pie sections based on our choice
* @param plot PiePlot of PieChart
* @param dataset PieChart DataSet
*/

58: public void setColor(PiePlot plot,
DefaultPieDataset dataset)
{
59: List keys = dataset.getKeys();
60: int aInt;

61: for (int i =

0; i <

keys.size(); i++)
{
62: aInt = i % this.color.length;
63: plot.setSectionPaint(
keys.get(i).toString(),this.color[aInt]);
}
}
}
}

Generated Output



Following are the sample outputs that will show differences between a generic and customized chart. Since the project I involved is basically a web application I used a servlet to display all these charts.



Fig 1: Generic Chart – Not Customized Fig 2: Chart with customized label



Fig 3: Chart with customized legend Fig 4: Chart with customized title



Fig 5: Chart with ZERO insets Fig 6: Chart with custom pie section colors


Note: Copy the war file into the webapps folder of the Tomcat. Start the Tomcat server & view the charts (JSP) through a browser. [In the address bar give: http://localhost:/CustomizePieChart]

17 comments:

vicky said...

Hi,
I have gone through your bolg, and i m also working on jFreeCharts right now.i have been facing a problem , i hope you may help me in this. Problem is :

i m creating a XYPlot using XYDataseries, i m trying to save the generated chart to a file as an image. But the generated image has the orange color background.
i Hvae tried all the methods of JFreeCharts like :
/*Paint p= new GradientPaint(0,0,Color.white,0,0,Color.WHITE);
lineChart.setBackgroundPaint(p);
//myaxis.setAxisLinePaint(Color.WHITE);
Plot aplot = lineChart.getPlot();
aplot.setBackgroundPaint(Color.white);
//Image image = new ImageIO.();
aplot.setBackgroundImage(new Image("c:\\untitled.JPG"));*/
//lineChart.setBackgroundPaint(Color.WHITE);
//lineChart.setBackgroundPaint(null);

But still the background is some other color when the image is saved. i m trying to make an image with white background.

Can u help me in this.
My email id is : vikaspnra@gmail.com

Balaji Natarajan said...

Hi, i have not extensively worked in charts other than pie chart. but i tried of displaying XYLineChart, but it was generated with white background in default. can you please send your code to my mail so that i can have a look at it and help you. thanks for your comments. you can send the sample code to balajeenatarajan at gmail dot com. please also send sample output.

Best Regards,
Balaji

deepshikha said...

thanks ... ur blog helped a lot.
can u let me know how to display data labels in percentage?

Balaji Natarajan said...

Hi deepshikha,
Fig 2 displays Actual Values. In a special case, if the sum of values of all pie sections equals 100, all individual values are nothing but their percentages.

But, if we have, say three pie sections with values 3,4 and 3 respectively, all you wanted is to display 30%, 40% and 30%. i have not found any API help from jfreechart to help display values in percentages. But we can hack generateSectionLabel method of static class CustomLabelGenerator to display values in percentages.

Ex:
1. Instead of setting direct values in dataset, set as percentages as shown below
int totalEmployees = 50+20+25+10;
final HashMap percentMap = new HashMap();
data.setValue("Software Engineer",50/totalEmployees*100);

data.setValue("Programmer Analyst",20/totalEmployees*100);

data.setValue("Technical Specialist",25/totalEmployees*100);

data.setValue("Project Manager",10/totalEmployees*100);

2. Change generateSectionLabel method of static class CustomLabelGenerator to display values in percentages.

Instead of,

43: temp = dataset.getValue(key).toString();

Add a percentage sign,

43: temp = dataset.getValue(key).toString()+"%";

Hope that helps. i will later add an example including percentages

Nagaraj said...

Can we control the space between the pie chart and the label.

Actually I have to create image of size 130 X 150 pixel and I am noticing that there is lot of gap between the pie chart and the label.

Balaji Natarajan said...

Hi Nagaraj,
In my another blog, Displaying Dynamically Generated JFreeChart, i have used to write the generated chart in outputstream,
ChartUtilities.writeChartAsPNG(out, chart, 200,200);
Last two argument specifies the size of the chart. when u have very few pie sections, you may get a large white backround and your labels displace widely. i have got stucked into samething. as i had no time to explore things at that time, i just dynamically controlled the size of the chart being generated by the no. of items to be displayed. for 5 items, it may fit good for 200X200, more than 5 to 10, may be 300X300 do like tat...
if i get into find something related to this, i will add here.thanks

puneet said...

Hey, I am getting a same issue of having an orange background on the entire chart. So if I were to show a blue piece it is now a mix of blue and orange.

did you guys get a solution to it. if yes can you post it on here.

appreciate your help

puneet said...

hey got the answer jfreechart has a bug in release 1.0.9 which they fixed in 1.0.10

nara said...

I have gone through your blog,It is very help to me, adn i am also working on the jfree chsrt right now.I have a problem with pie chart.I hope u may help on this.
Problem is :

In one page i am having two charts.No problem If the all are bar charts.If one is pie chart and other one is bar chart means the legend of the pie chart is getting displayed as legend for second bar chart.

Balaji Natarajan said...

thanks puneet....

Balaji Natarajan said...

hi nara,
thanks for your encouraging comments.

please post your code samples, let me get more idea from it and will help you....

Demon said...

I have found your blog. Good post.

But I see that the items labels for your examples is not pretty (I mean string dividing, the words has been cut).

I have the same problem on my small service chartgizmo.com, and I can't find simple solutions. Do you have any ideas?

vikram said...

Hi,
I think jfreecharts still does not support exploding 3D Pie charts. Any work-arounds or tips on how to get it done?
Regards,
Vikram.

Abhay Singh said...

Hi,

I want to change font of label, how can i do that?

Vincent said...

Hi,

I am very happy with your blog, you helped lot.

I have one more doubt....

How can I increase the legend size,
Can you please some one help me.

Thanks,
Vincent Louis.

Anonymous said...

I seldom leave comments on blog, but I have been to this post which was recommended by my friend, lots of valuable details, thanks again.

Raghu said...

hi

i need to change the legend shapes in bar chart from rectangle to circular
since category plot doest not have setLegendItemShape() method how to achive this