查看文章
 
JFreeChart详解
2008年05月14日 星期三 上午 10:46
一:jfreechart介绍
jfreechart是一个免费创建图片的java工具.可以创建如下图形:
饼图(pie charts;)
曲线图(line charts )
柱状图(horizontal/vertical bar charts)
甘特图(Gantt charts; )
XY plots and scatter plots;
time series, high/low/open/close charts and candle stick charts;
combination charts;
Pareto charts;
bubble charts;
wind plots, meter charts and symbol charts;
从以下地址可以看到jfreechart可以创建的图形类型
http://www.jfree.org/jfreechart/samples.html
sourceforge有一个基于jfreechart的项目Cewolf可以很方便的在jsp/servlet中创建图片
jfreechart目前(2003-05-08)版本为0.98
希望得到详细的信息或下载jfreechart请访问如下站点:
http://www.jfree.org/jfreechart/

二:特别说明:
jfreechart是一个开源项目,但是文档是需要40美金去购买的。
还有一个很重要的问题,jfreechart如果使用中文,他使用的默认字体
显示出来的中文会很模糊,你可能需要修改源代码。
下面我就举几个简单的例子说明一下如何使用jfreechart创建图片
在开发中有可能会导入以下的类
import com.jrefinery.chart.ChartFactory;
import com.jrefinery.chart.ChartUtilities;
import com.jrefinery.chart.JFreeChart;
import com.jrefinery.chart.TextTitle;
import com.jrefinery.chart.axis.NumberAxis;
import com.jrefinery.chart.plot.CategoryPlot;
import com.jrefinery.chart.plot.PiePlot;
import com.jrefinery.data.Day;
import com.jrefinery.data.DefaultCategoryDataset;
import com.jrefinery.data.DefaultPieDataset;
import com.jrefinery.data.TimeSeries;
import com.jrefinery.data.TimeSeriesCollection;
import com.jrefinery.data.TimeSeriesDataPair;
在0.98以后包由com.jrefinery.*改变为:org.jfree

三:创建饼图
//图片标题
String title = "空调2002年市场占有率";
//设定数据源
DefaultPieDataset piedata = new DefaultPieDataset();
//第一个参数为名称,第二个参数是double数
piedata.setValue("联想", 27.3);
piedata.setValue("长城", 12.2);
piedata.setValue("海尔", 5.5);
piedata.setValue("美的", 17.1);
piedata.setValue("松下", 9.0);
piedata.setValue("科龙", 19.0);
//创建JFreeChart,都使用ChartFactory来创建JFreeChart,很标准的工厂设计模式
JFreeChart chart =
ChartFactory.createPieChart(title, piedata, true, true, true);
//设定图片标题
chart.setTitle(new TextTitle(title, new Font("隶书", Font.ITALIC, 15)));
//chart.addSubtitle(new TextTitle("2002财年分析", new Font("隶书", Font.ITALIC, 12)));
//设定背景
chart.setBackgroundPaint(Color.white);
//chart.s
//饼图使用一个PiePlot
PiePlot pie = (PiePlot)chart.getPlot();
//pie.setSectionLabelType(PiePlot.NAME_AND_PERCENT_LABELS);
pie.setSectionLabelType(PiePlot.NAME_AND_VALUE_LABELS);
//设定显示格式(名称加百分比或数值)
pie.setPercentFormatString("#,###0.0#%");
//设定百分比显示格式
pie.setBackgroundPaint(Color.white);
pie.setSectionLabelFont(new Font("黑体", Font.TRUETYPE_FONT, 12));
//设定背景透明度(0-1.0之间)
pie.setBackgroundAlpha(0.6f);
//设定前景透明度(0-1.0之间)
pie.setForegroundAlpha(0.90f);
//输出文件到指定目录
String rfname = MathUtil.getRoundCode(12) + ".jpeg";
String fileName = "d:/test/" + rfname;
try {
//可以保存文件为jpg或png格式。
ChartUtilities.saveChartAsJPEG(new File(fileName), 100, chart, 600, 600);
//第一个参数为文件名
//第二个参数质量
//第三个参数为哪个chart创建图片
//第四个宽度
//第五个高度
} catch (IOException exz) {
System.out.print("....Cant't Create image File");
}

其实使用JFreeChart创建图片很简单,不同的的图片类型区别在于设置数据集

四:创建曲线图
// create a default chart based on some sample data...
//曲线图标题
String title = "趋势分析";
//曲线图X轴提示
String domain = "月份走势";
//曲线图Y轴提示
String range = "应收余额";
//曲线图自标题
String subtitleStr = "2003财年分析";
//创建时间数据源
//每一个TimeSeries在图上是一条曲线
TimeSeries ca = new TimeSeries("用友");
for (int i = 1999; i < 2005; i++) {
for (int mon = 0; mon < 12; mon++) {
//ca.add(new Month(mon + 1, i), new Double(500 + Math.random() * 100));
//TimeSeriesDataPair是一个时间点的数值体现
ca.add(
new TimeSeriesDataPair(
new Day(1, mon + 1, i),
new Double(500 + Math.random() * 100)));
}
}

TimeSeries ibm = new TimeSeries("金碟");
for (int i = 1999; i < 2005; i++) {
for (int mon = 0; mon < 12; mon++) {
//ibm.add(new Month(mon+1,i),new Double(400-Math.random()*100));
ibm.add(
new TimeSeriesDataPair(
new Day(1, mon + 1, i),
new Double(400 - Math.random() * 100)));
}
}

TimeSeries king = new TimeSeries("东软");
for (int i = 1999; i < 2005; i++) {
for (int mon = 0; mon < 12; mon++) {
//ibm.add(new Month(mon+1,i),new Double(400-Math.random()*100));
king.add(
new TimeSeriesDataPair(
new Day(1, mon + 1, i),
new Double(300 - Math.random() * 100)));
}
}
//时间曲线数据集合
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(ca);
dataset.addSeries(ibm);
dataset.addSeries(king);
//dataset.addSeries(jpy);
//dataset.addSeries(mav);
//时间曲线元素
JFreeChart chart =
ChartFactory.createTimeSeriesChart(
title,
domain,
range,
dataset,
true,
true,
false);
// then customise it a little...
TextTitle subtitle =
new TextTitle(subtitleStr, new Font("黑体", Font.BOLD, 12));
chart.addSubtitle(subtitle);
chart.setTitle(new TextTitle(title, new Font("隶书", Font.ITALIC, 15)));
//pie.setSeriesLabelFont(new Font("黑体", Font.BOLD, 15));
chart.setBackgroundPaint(
new GradientPaint(0, 0, Color.white, 0, 1000, Color.blue));
//sysout
//输出文件到指定目录
String rfname = MathUtil.getRoundCode(22) + ".jpeg";
String fileName = "d:/test/" + rfname;
try {
//for
//System.out.println();
ChartUtilities.saveChartAsJPEG(new File(fileName), 100, chart, 600, 600);
// log.info("....Create image File:" + fileName);
} catch (IOException exz) {
System.out.print("....Cant't Create image File");
}


五:创建柱状图
String title = "柱状图测试";
String domain = "单位比较";
String range = "数值";
//CategoryDataset data = DemoDatasetFactory.createCategoryDataset();
DefaultCategoryDataset data = new DefaultCategoryDataset();
for (int r = 0; r < 5; r++) {
String rowKey = "单位 [" + (r + 1)+"]" ;
//第一层循环:分析对象
for (int c = 0; c < 6; c++) {
//第二层循环:分析对象在时间点上的数据
String columnKey = "2001年" + (c + 1) + "月";
data.addValue(new Double(r * c + 5), rowKey, columnKey);
}
}

JFreeChart chart =
ChartFactory.createVerticalBarChart(
title,
domain,
range,
data,
true,
true,
false);
// then customise it a little...
chart.setBackgroundPaint(
new GradientPaint(0, 0, Color.white, 1000, 0, Color.red));
chart.setTitle(new TextTitle(title, new Font("隶书", Font.ITALIC, 15)));
CategoryPlot plot = (CategoryPlot)chart.getPlot();
plot.setForegroundAlpha(0.9f);
plot.setValueLabelFont(new Font("黑体", Font.TRUETYPE_FONT, 12));
//plot.setSectionLabelFont(new Font("黑体", Font.TRUETYPE_FONT, 12));
//注意以下代码
NumberAxis verticalAxis = (NumberAxis)plot.getRangeAxis();
verticalAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
// 输出文件到指定目录
String rfname = MathUtil.getRoundCode(22) + "b.jpeg";
String fileName = "d:/test/" + rfname;
try {
ChartUtilities.saveChartAsJPEG(new File(fileName), 100, chart, 600, 600);
// log.info("....Create image File:" + fileName);
} catch (IOException exz) {
System.out.print("....Cant't Create image File");
}

六:结束语
个人感觉JFreeChart可以满足大部分图片创建的需要,美中不足的是:对字体的设置做的
不 够好,特别是使用中文的时候字体很不清晰。因为这个原因建议你自己去修改他的源代码,最好使用properties文件去设置字体.还有就是文档要钱所以 要多花点时间去看源代码。或多上社区.因为时间等原因我只介绍了三种图片的创建,其他类型的图片可以参考jfreechart提供的例子。

JFreeChart核心类库介绍:

jfreechart主要由两个大的包组成:org.jfree.chart,org.jfree.data。其中前者主要与图形

本身有关,后者与图形显示的数据有关。

核心类主要有:

org.jfree.chart.JFreeChart:图表对象,任何类型的图表的最终表现形式都是在该对象进行一些属性的定制。JFreeChart引擎本身提供了一个工厂类用于创建不同类型的图表对象

org.jfree.data.category.XXXDataSet:数据集对象,用于提供显示图表所用的数据。根据不同类型的图表对应着很多类型的数据集对象类

org.jfree.chart.plot.XXXPlot:图表区域对象,基本上这个对象决定着什么样式的图表,创建该对象的时候需要Axis、Renderer以及数据集对象的支持

org.jfree.chart.axis.XXXAxis:用于处理图表的两个轴:纵轴和横轴

org.jfree.chart.render.XXXRender:负责如何显示一个图表对象

org.jfree.chart.urls.XXXURLGenerator:用于生成Web图表中每个项目的鼠标点击链接

XXXXXToolTipGenerator:用于生成图象的帮助提示,不同类型图表对应不同类型的工具提示类

对于常用的饼图阖柱状图,比较简单而且网上有很多的文章介绍,在这里就不再一一复述了,

主要说明下另一种常见的报表,时序图,首先声明一个曲线数据集合对象和曲线对象

TimePeriodValuesCollection timeseriescollection = new TimePeriodValuesCollection();

//声明具体是曲线对象,(可根据实际情况在同一张图中显示多条曲线进行数据比对,根据实际应用情况当超过4条曲线时,就会有些乱。)

TimePeriodValues timeperiod1 = new TimePeriodValues("服务器A在线用户数量");

TimePeriodValues timeperiod2 = new TimePeriodValues("服务器B在线用户数量");

我在使用TimeSeriesCollection tsc = new TimeSeriesCollection();

TimeSeries ts = new TimeSeries();

在生成数据集时(ts.add(new Day(day, month, year),10)))只能生成最小单位为天的横轴所以改用了TimePeriodValuesCollection

//根据当前时间取得横轴坐标,时间间隔为1小时

Calendar cal = Calendar.getInstance();

int year = cal.get(Calendar.YEAR);

int month = cal.get(Calendar.MONTH) + 1;

int day = cal.get(Calendar.DAY_OF_MONTH);

//这里改为根据自己程序得到的需要显示的时间点和对应的数据的集合;

List objectList1 = dao.getList1();

List objectList2 = dao.getList2();

//使用循环,把x轴,y轴的值赋给timeseries1

for (int i =0;i<objecthash1.size();i++) {

     int hour = objecthash1[i].getHours();

     int count = objecthash1[i].getCount();

//将每一对数据(时间,数值)添加到数据集合1(曲线对象1)中

     timeseries1.add(new Hour(hour, day, month, year),count);

}

for (int i =0;i<objecthash2.size();i++) {

     int hour = objecthash2[i].getHours();

     int count = objecthash2[i].getCount();

//将每一对数据(时间,数值)添加到数据集合2(曲线对象2)中

     timeseries2.add(new Hour(hour, day, month, year),count);

}

//将曲线对象添加到曲线数据集合对象中

timeseriescollection.addSeries(timeseries1);

timeseriescollection.addSeries(timeseries2);

//绘制报表

String title = "日在线用户统计"; //报表标题

String domain = "时间";     //x轴

String range = "用户在线数量";    //y轴

//创建时间序列图对象

JFreeChart chart = ChartFactory.createTimeSeriesChart(

title,   //报表标题

domain, //报表横轴标签

range,   //报表纵轴标签

timeseriescollection, //数据集合

true,   //是否显示图例,在这里如果为true则会在图表的下方显示各条数据曲线的名称和颜色

false, // 是否生成工具

false    // 是否生成URL链接);

//将报表保存为jpg文件

ChartUtilities.saveChartAsJPEG(file, //文件保存物理路径包括路径和文件名

100,    //图片质量

chart, //图表对象

1024,   //图像宽度

768,    //图像高度

null); //显示信息

//将报表直接在页面输出

ChartUtilities.writeChartAsJPEG(res.getOutputStream(),100,chart,1024,768,null);

String title="月在线用户统计";   //标题

String domain="时间(天)";//x轴

String range="用户在线数量";//y轴

TimePeriodValuesCollection    timeseriescollection    =    new    TimePeriodValuesCollection();

TimePeriodValues timeseries = new TimePeriodValues( "用户数量");

timeseries.add(new Minute(0, 1, 1, 1, 2006), 100);

timeseries.add(new Minute(10, 1, 1, 1, 2006), 500);

timeseries.add(new Minute(20, 1, 1, 1, 2006), 300);

timeseries.add(new Minute(30, 1, 1, 1, 2006), 800);

JFreeChart chart =ChartFactory.createTimeSeriesChart(title,domain,range,timeseriescollection,true,false,false);

当我们生成了一个报表对象时,可能需要根据实际情况来决定报表的横轴和纵轴的数值间隔,显示方式等。

可以用XYPlot xyplot = (XYPlot)chart.getPlot();来得到所有数据点的集合。(其它形状图表得到的数据集对象根据实际情况造型)

得到数据点集合后,我们就可以设置各条曲线的颜色,和坐标轴的距离,x轴、y轴的显示方式等等属性

xyplot.setBackgroundPaint(Color.lightGray); //设定图表数据显示部分背景色

xyplot.setAxisOffset(new RectangleInsets(5D, 5D, 5D, 5D)); //设定坐标轴与图表数据显示部分距离

xyplot.setDomainGridlinePaint(Color.white); //网格线纵向颜色

xyplot.setRangeGridlinePaint(Color.white); //网格线横向颜色

数据点的调整

XYLineAndShapeRenderer xylineandshaperenderer = (XYLineAndShapeRenderer)xyplot.getRenderer();

xylineandshaperenderer.setDefaultShapesVisible(true);   //数据点可见

xylineandshaperenderer.setSeriesFillPaint(0, Color.red);   //设置第一条曲线数据点填充为红色,如果一个图表有多条曲线可分别设置

xylineandshaperenderer.setUseFillPaint(true);     //应用

使用xyplot.getRangeAxis()得到纵轴,xyplot.getDomainAxis()得到横轴,得到后可以根据实际情况造型为自己所需要的类型。

我的图表纵轴为数值类型,横轴为时间类型,使用如下方式

NumberAxis numAxis = (NumberAxis)xyplot.getRangeAxis();

DateAxis   dateaxis =    (DateAxis)xyplot.getDomainAxis();

//设置y显示方式

numAxis.setAutoTickUnitSelection(false);//数据轴的数据标签是否自动确定

double   rangetick = 0.1D;

numAxis.setTickUnit(new NumberTickUnit(rangetick));   //y轴单位间隔为0.1

//设置x轴显示方式

dateaxis.setAutoTickUnitSelection(false);//数据轴的数据标签是否自动确定

dateaxis.setTickUnit(new DateTickUnit(DateTickUnit.DAY,1));//x轴单位间隔为1天

我们还可以是将数据格式化以后显示,比如y轴显示百分比(10%~100%),x轴显示为×月×日

NumberFormat nf =NumberFormat.getPercentInstance();

numAxis.setNumberFormatOverride(nf);//设置y轴以百分比方式显示

SimpleDateFormat format = new SimpleDateFormat("MM月dd");

dateaxis.setDateFormatOverride(format);//设置x轴数据单位以×月×日方式显示

时序图中还有一个很重要的方法

timeseriescollection.setDomainIsPointsInTime(true); //x轴上的刻度点代表的是时间点而不是时间段

最开始我没有设置这个属性,结果画出来的图,老是差半格不能在这个刻度的时候准确显示,往后移了半格,就是因为JFreeChart默认这个刻度是

一个时间段,它把这个刻度和下个刻度的中间点认为是显示数据点最佳位置。

其他一些关于AXIS类的方法:

Axis类:

void setVisible(boolean flag)坐标轴是否可见

void setAxisLinePaint(Paint paint)坐标轴线条颜色(3D轴无效)

void setAxisLineStroke(Stroke stroke)坐标轴线条笔触(3D轴无效)

void setAxisLineVisible(boolean visible)坐标轴线条是否可见(3D轴无效)

void setFixedDimension(double dimension)(用于复合表中对多坐标轴的设置)

void setLabel(String label)坐标轴标题

void setLabelFont(Font font)坐标轴标题字体

void setLabelPaint(Paint paint)坐标轴标题颜色

void setLabelAngle(double angle)`坐标轴标题旋转角度(纵坐标可以旋转)

void setTickLabelFont(Font font)坐标轴标尺值字体

void setTickLabelPaint(Paint paint)坐标轴标尺值颜色

void setTickLabelsVisible(boolean flag)坐标轴标尺值是否显示

void setTickMarkPaint(Paint paint)坐标轴标尺颜色

void setTickMarkStroke(Stroke stroke)坐标轴标尺笔触

void setTickMarksVisible(boolean flag)坐标轴标尺是否显示

ValueAxis(Axis)类:

void setAutoRange(boolean auto)自动设置数据轴数据范围

void setAutoRangeMinimumSize(double size)自动设置数据轴数据范围时数据范围的最小跨度

void setAutoTickUnitSelection(boolean flag)数据轴的数据标签是否自动确定(默认为true)

void setFixedAutoRange(double length)数据轴固定数据范围(设置100的话就是显示MAXVALUE到MAXVALUE-100那段数据范围)

void setInverted(boolean flag)数据轴是否反向(默认为false)

void setLowerMargin(double margin)数据轴下(左)边距

void setUpperMargin(double margin)数据轴上(右)边距

void setLowerBound(double min)数据轴上的显示最小值

void setUpperBound(double max)数据轴上的显示最大值

void setPositiveArrowVisible(boolean visible)是否显示正向箭头(3D轴无效)

void setNegativeArrowVisible(boolean visible)是否显示反向箭头(3D轴无效)

void setVerticalTickLabels(boolean flag)数据轴数据标签是否旋转到垂直

void setStandardTickUnits(TickUnitSource source)数据轴的数据标签(可以只显示整数标签,需要将AutoTickUnitSelection设false)

NumberAxis(ValueAxis)类:

void setAutoRangeIncludesZero(boolean flag)是否强制在自动选择的数据范围中包含0

void setAutoRangeStickyZero(boolean flag)是否强制在整个数据轴中包含0,即使0不在数据范围中

void setNumberFormatOverride(NumberFormat formatter)数据轴数据标签的显示格式

void setTickUnit(NumberTickUnit unit)数据轴的数据标签(需要将AutoTickUnitSelection设false)

DateAxis(ValueAxis)类:

void setMaximumDate(Date maximumDate)日期轴上的最小日期

void setMinimumDate(Date minimumDate)日期轴上的最大日期

void setRange(Date lower,Date upper)日期轴范围

void setDateFormatOverride(DateFormat formatter)日期轴日期标签的显示格式

void setTickUnit(DateTickUnit unit)日期轴的日期标签(需要将AutoTickUnitSelection设false)

void setTickMarkPosition(DateTickMarkPosition position)日期标签位置(参数常量在org.jfree.chart.axis.DateTickMarkPosition类中定义)

CategoryAxis(Axis)类:

void setCategoryMargin(double margin)分类轴边距

void setLowerMargin(double margin)分类轴下(左)边距

void setUpperMargin(double margin)分类轴上(右)边距

void setVerticalCategoryLabels(boolean flag)分类轴标题是否旋转到垂直

void setMaxCategoryLabelWidthRatio(float ratio)分类轴分类标签的最大宽度



类别:web技术||添加到搜藏 |分享到i贴吧|浏览(690)|评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu