JFreeChart是一个Java开源项目,是一款优秀的Java图表生成插件,它提供了在Java Application、Servlet和JSP下生成各种图片格式的图表,包括柱形图、饼形图、线图、区域图、时序图和多轴图等。本章将详细介绍利用JFreeChart生成各种图表的技术要点。
本节将介绍JFreeChart插件的下载与使用方法,以及JFreeChart插件的核心类及其 功能。
在JFreeChart的官方网站(http://www.jfree.org/jfreechart/index.html)上可以下载到该插件,该插件有两个版本。
ll freechart-1.0.5.zip,该版本适用于Windows系统。
ll jfreechart-1.0.5.tar.gz,该版本适用于UNIX/Linux系统。
本书所有示例的开发环境均为Windows系统,解压缩jfreechart-1.0.5.zip后将得到一个名为jfreechart-1.0.5的文件夹,只需将lib子文件夹内的如下文件复制到Web应用程序目录中的/WEB-INF/lib目录下。
ll jfreechart-1.0.5.jar。
ll jcommon-1.0.9.jar。
ll junit.jar。
ll gnujaxp.jar。
ll servlet.jar。
并且在web.xml文件中添加如下代码:
<servlet>
<servlet-name>DisplayChart</servlet-name>
<servlet-class>org.jfree.chart.servlet.DisplayChart</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayChart</servlet-name>
<url-pattern>/servlet/DisplayChart</url-pattern>
</servlet-mapping>
这样,就可以利用JFreeChart插件生成动态统计图表了。利用JFreeChart插件生成动态统计图表的基本步骤如下。
(1)创建绘图数据集合。
(2)创建JFreeChart实例。
(3)自定义图表绘制属性,该步可选。
(4)生成指定格式的图片,并返回图片名称。
(5)组织图片浏览路径。
(6)通过HTML中的<img>元素显示图片。
在使用JFreeChart插件之前,先介绍该插件的核心类及其功能,这对将来能够得心应手地使用该插件是非常重要的,JFreeChart核心类及其功能如表14.1所示。
表14.1 JFreeChart核心类及其功能
类 名 |
功 能 |
JFreeChart |
图表对象,生成任何类型的图表都要通过该对象,JFreeChart插件提供了一个工厂类ChartFactory,用来创建各种类型的图表对象 |
XXXDataset |
数据集对象,用来保存绘制图表的数据,不同类型的图表对应着不同类型的数据集对象 |
XXXPlot |
绘图区对象,如果需要自行定义绘图区的相关绘制属性,需要通过该对象进行设置 |
XXXAxis |
坐标轴对象,用来定义坐标轴的绘制属性 |
XXXRenderer |
图片渲染对象,用于渲染和显示图表 |
XXXURLGenerator |
链接对象,用于生成Web图表中项目的鼠标单击链接 |
XXXToolTipGenerator |
图表提示对象,用于生成图表提示信息,不同类型的图表对应着不同类型的图表提示对象 |
通过表14.1,可以简单了解JFreeChart插件中各个类的功能,下面将仔细讲解利用JFreeChart生成各种图表的技术要点。
通过JFreeChart插件,既可以生成普通效果的柱形图,也可以生成3D效果的柱形图。如果想生成普通效果的柱形图,需要通过工厂类ChartFactory的createBarChart()方法获得JFreeChart类的实例;如果想生成3D效果的柱形图,需要通过工厂类ChartFactory的createBarChart3D()方法获得JFreeChart类的实例,这两个方法的入口参数是完全相同的,各个入口参数的类型及功能如表14.2所示。
表14.2 绘制柱形图方法的入口参数类型及功能
参 数 序 号 |
入 口 参 数 |
参 数 功 能 |
1 |
String title |
图表标题 |
2 |
String categoryAxisLabel |
统计种类轴标题,可以理解为X轴标题 |
3 |
String valueAxisLabel |
统计值轴标题,可以理解为Y轴标题 |
4 |
CategoryDataset dataset |
绘图数据集 |
5 |
PlotOrientation orientation |
用于设定柱形图的绘制方向 垂直:PlotOrientation.VERTICAL 水平:PlotOrientation.HORIZONTAL |
6 |
boolean legend |
用于设定是否显示图例 |
7 |
boolean tooltips |
用于设定是否采用标准生成器 |
8 |
boolean urls |
用于设定是否包生成链接 |
工厂类ChartFactory中的方法的返回值均为JFreeChart类的实例,通过返回的JFreeChart类的实例,可以设置绘图属性,也可以省略该步,直接生成图片,JFreeChart插件将采用默认的绘图属性进行绘制。
可以通过JFreeChart实例设置整个图片的绘制属性,例如通过setBackgroundPaint(Paint paint)方法设置图片的背景色,入口参数可以是Color类的实例,也可以是GradientPaint类的实例,通过GradientPaint类的实例可以实现渐变的背景色效果。
还可以通过JFreeChart实例的getCategoryPlot()方法获得CategoryPlot类的实例,通过CategoryPlot类的实例可以设置绘图区的绘图属性,例如设置绘图区的背景色,标准线的绘制属性等。通过CategoryPlot实例的getRenderer()方法可以获得BarRenderer类的实例,通过BarRenderer类的实例可以设置柱形的绘制属性,例如是否绘制柱形的轮廓线,以及柱形的填充色等,通过BarRenderer实例的setSeriesPaint(int series, Paint paint)方法设置柱形的填充色,第一个入口参数为图例的索引位置,从0开始,第二个入口参数为填充色,同样既可以接受Color类的实例,也可以接受GradientPaint类的实例。
示例14-01 利用DefaultCategoryDataset数据集绘制柱形图
下面来看一个绘制柱形图的完整例子,该例绘制的柱形图效果如图14.1和图14.2所示。
图14.1 当绘图数据全部为正数时绘制出的柱形图 图14.2 当绘图数据存在负数时绘制出的柱形图
代码14-01 光盘位置:光盘\mingrisoft\14\sl\01
绘图时需要用到的相关信息如下:
int width = 500; // 图像宽度
int height = 375; // 图像高度
String chartTitle = "编程类图书年销量柱形图分析"; // 图表标题
String subtitle = "------统计时间:2008年"; // 副标题
String xTitle = "销售时间:2008年"; // X轴标题
String yTitle = "销售量 单位:万册"; // Y轴标题
String[] cutline = new String[] { "ASP", "JSP", "PHP" }; // 图例名称
String category[] = new String[] {"第1季度","第2季度","第3季度","第4季度"}; // 统计种类
Double[][] data = new Double[cutline.length][category.length]; // 绘图数据
for (int m = 0; m < cutline.length; m++) { // 随机获取绘图数据
for (int n = 0; n < category.length; n++) {
data[m][n] = 1 + Math.random() * 100;
}
}
String servletURI = "/servlet/DisplayChart"; // 映射路径
注意:仔细观察上面的for循环代码,会发现外循环是根据图例个数循环的,内循环是根据数据类别个数循环的,所以,在向绘图数据集中添加数据时,是按照图例的顺序添加的,即添加一个图例所有类别数据后再添加另一个图例的数据(对于竖向柱形图来说,并不是按照柱形从左到右的顺序添加数据的)。
说明:上面给出的绘图数据为图14.1的绘图数据,限于篇幅,在这里就不给出图14.2的绘图数据了。
首先通过DefaultCategoryDataset类的实例封装绘图数据,代码如下:
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for (int m = 0; m < cutline.length; m++) {
for (int n = 0; n < category.length; n++) {
dataset.addValue(data[m][n], cutline[m], category[n]);
}
}
本示例绘制3D效果的柱形图,所以通过createBarChart3D()方法获得JFreeChart类的实例,只要改为createBarChart()方法,就可以绘制普通效果的柱形图,代码如下:
JFreeChart chart = ChartFactory.createBarChart3D(chartTitle, // 图表标题
xTitle, // X轴标题
yTitle, // Y轴标题
dataset, // 绘图数据集
PlotOrientation.VERTICAL, // 柱形图绘制方向
True, // 显示图例
True, // 显示图例名称
False // 生成链接
);
下面开始自定义绘图属性,没有下面的代码,同样可以得到漂亮的3D效果的柱形图。
为图片添加副标题,代码如下:
chart.addSubtitle(new TextTitle(subtitle));
将图片的背景色设置为渐变效果,代码如下:
GradientPaint chartGP = new GradientPaint(0, 0,
new Color(219, 227, 251), 0, height, Color.WHITE, False); // 创建渐变色对象
chart.setBackgroundPaint(chartGP); // 设置图片背景色
通过JFreeChart实例的getCategoryPlot()方法获得CategoryPlot类的实例,目的是设置绘图区的绘图属性,代码如下:
CategoryPlot plot = chart.getCategoryPlot();
设置绘图区的相关绘图属性,代码如下:
plot.setBackgroundPaint(new Color(241, 219, 127)); // 设置绘图区背景色
plot.setRangeGridlinePaint(Color.RED); // 设置水平方向背景线颜色
plot.setRangeGridlinesVisible(True); // 设置是否显示水平方向背景线,默认值为True
plot.setDomainGridlinePaint(Color.RED); // 设置垂直方向背景线颜色
plot.setDomainGridlinesVisible(True); // 设置是否显示垂直方向背景线,默认值为False
通过CategoryPlot实例的getRenderer()方法获得BarRenderer类的实例,目的是设置柱形的绘制属性,代码如下:
BarRenderer renderer = (BarRenderer) plot.getRenderer();
在这里不绘制柱形的轮廓线,JFreeChart默认为绘制,代码如下:
renderer.setDrawBarOutline(False);
下面设置柱形的填充颜色,同样采用渐变效果,代码如下:
Color color[] = new Color[cutline.length];
color[0] = new Color(99, 99, 0);
color[1] = new Color(255, 169, 66);
color[2] = new Color(33, 255, 66);
for (int i = 0; i < color.length; i++) {
GradientPaint gp = new GradientPaint(0, 0, color[i].brighter(), 0,
height, color[i].darker());
renderer.setSeriesPaint(i, gp);
}
下面通过CategoryPlot实例的getDomainAxis()方法获得CategoryAxis类的实例,目的是设置统计种类轴标题(X轴)的绘制属性,在这里设置为倾斜45°输出,代码如下:
CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
本示例中就定义了上述的这些绘图属性,读者可以尝试着定义其他属性。下面的代码是利用JFreeChart绘制图片时必须用到的,记住就可以了:
ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
通过ServletUtilities类的saveChartAsPNG()方法生成PNG格式的图片,并返回图片的名称,如果想生成JPG格式的图片,可以通过ServletUtilities类的saveChartAsJPEG()方法,代码如下:
String fileName = "";
try {
fileName = ServletUtilities.saveChartAsPNG(chart, width, height, info, session);
} catch (IOException e) {}
下面的代码是在组织图片的浏览路径,供显示到JSP页面时使用:
String graphURL = contextPath + servletURI + "?filename=" + fileName;
利用实现XYDataset接口的数据集,也可以绘制柱形图,XYDataset数据集主要用来绘制与日期相关的统计图。
在封装数据集时,首先需要通过TimeSeries类的实例进行封装,TimeSeries类提供了3个构造函数,在这里我们采用入口参数最多的一个,代码如下:
TimeSeries timeSeries = new TimeSeries(chartTitle, xTitle, yTitle, Month.class);
入口参数依次为图表标题、日期轴标题、数据轴标题和统计种类,第二个和第三个入口参数可以为空,第四个入口参数的可选类型如下。
ll Year.class,按年统计。
l Month.class,按月统计。
ll Day.class,按日统计。
ll Hour.class,按小时统计。
ll Minute.class,按分统计。
ll Second.class,按秒统计。
ll Millisecond.class,按毫秒统计。
ll Quarter.class,按一刻钟统计。
ll Week.class,按周统计。
ll FixedMillisecond.class,按指定时间段统计。
通过TimeSeries实例的add()方法向TimeSeries实例中添加统计数据,添加完成后以TimeSeries实例为入口参数创建一个TimeSeriesCollection类的实例,并将TimeSeriesCollection实例直接传给IntervalXYDataset类的实例,代码如下:
TimeSeriesCollection tsc = new TimeSeriesCollection(timeSeries);
IntervalXYDataset dataset = tsc;
说明:类TimeSeriesCollection和类IntervalXYDataset均为XYDataset接口的实现类。
在创建JFreeChart类的实例时,需要通过工厂类ChartFactory的createXYBarChart方法,createXYBarChart方法与14.2.1节使用的createBarChart3D()方法类似,请对照学习。
示例14-02 利用XYDataset数据集绘制与日期相关的柱形图
下面来看一个利用XYDataset数据集绘制柱形图的例子,该例绘制的柱形图效果如图14.3所示。
图14.3 利用XYDataset数据集绘制与日期相关的柱形图
代码14-02 光盘位置:光盘\mingrisoft\14\sl\02
在本示例中可以在前台向后台传入Map集合,Map集合元素的键为日期、值为统计值,本示例中用来创建数据集的代码如下:
Map data = new HashMap(); // 创建绘图数据集
for (int i = 1; i < 13; i++) { // 为绘图数据集赋值
data.put(i, 1 + Math.random() * 100);
}
TimeSeries timeSeries = new TimeSeries(chartTitle, xTitle, yTitle, Month.class);
Iterator it = data.keySet().iterator();
while (it.hasNext()) {
int key = (Integer) it.next();
timeSeries.add(new Month(key, new Year(2008)), (Double) data .get(key));
}
TimeSeriesCollection tsc = new TimeSeriesCollection(timeSeries);
IntervalXYDataset dataset = tsc;
本示例中用来创建JFreeChart实例的代码如下:
JFreeChart chart = ChartFactory.createXYBarChart(chartTitle, xTitle,
True, yTitle, dataset, PlotOrientation.VERTICAL, False, False, False);
通过JFreeChart插件,即可以生成普通效果的饼形图,也可以生成3D效果的饼形图;如果想生成普通效果的饼形图,需要通过工厂类ChartFactory的createPieChart()方法获得JFreeChart类的实例,如果想生成3D效果的饼形图,需要通过工厂类ChartFactory的createPieChart3D()方法获得JFreeChart类的实例,这两个方法的入口参数是完全相同的,各个入口参数的类型及功能如表14.3所示。
表14.3 绘制饼形图方法的入口参数类型及功能
参 数 序 号 |
入 口 参 数 |
参 数 功 能 |
1 |
String title |
图表标题 |
2 |
PieDataset dataset |
绘图数据集 |
3 |
boolean legend |
用于设定是否显示图例 |
4 |
boolean tooltips |
用于设定是否采用标准生成器 |
5 |
boolean urls |
用于设定是否包生成链接 |
绘制饼形图时,需要通过DefaultPieDataset数据集封装数据,该数据集中的每一个元素是由一组键值对组成的,这与Map集合有些类似,DefaultPieDataset数据集通过setValue()方法添加数据,setValue()方法有两个重载方法,均有两个入口参数,并且每个参数的含义是相同的,第一个入口参数为图例名称,第二个入口参数统计数据,它们的具体定义如下:
public void setValue(Comparable key, Number value) {
this.data.setValue(key, value);
fireDatasetChanged();
}
public void setValue(Comparable key, double value) {
setValue(key, new Double(value));
}
可以通过绘图区对象PiePlot的setForegroundAlpha(float alpha)方法,实现饼图的透明效果,入口参数alpha的取值范围在0.0和1.0之间,当为0.0时,将不显示饼图,当为1.0时,则不存在透明效果,当超出该范围时,将抛出如下异常:
java.lang.IllegalArgumentException: alpha value out of range
示例14-03 编程类图书年销售额百分比饼形图分析
下面来看一个绘制饼形图的例子,该例绘制的饼形图效果如图14.4和图14.5所示。
图14.4 普通效果的饼形图 图14.5 3D效果的饼形图
代码14-03 光盘位置:光盘\mingrisoft\14\sl\03
本示例使用的模拟绘图数据如下:
String[] cutline; // 图例
Double[] data; // 绘图数据
this.cutline = new String[] { "ASP", "JSP", "PHP", "Hibernate", "Spring", "数据库" };
this.data = new Double[cutline.length];
for (int i = 0; i < data.length; i++) {
data[i] = 1 + Math.random() * 100;
}
创建DefaultPieDataset数据集的代码如下:
DefaultPieDataset dataset = new DefaultPieDataset();
for (int i = 0; i < cutline.length; i++) {
dataset.setValue(cutline[i], data[i]);
}
创建绘制3D效果饼形图的JFreeChart实例,代码如下:
JFreeChart chart = ChartFactory.createPieChart3D(chartTitle, // 图表标题
dataset, // 绘图数据集
False, // 设定是否显示图例
False, // 设定是否显示图例名称
False); // 设定是否生成链接
说明:这里绘制的是图14.5所示的3D效果图,如果想绘制图14.4所示的普通效果图,只需将createPieChart3D()方法改为createPieChart()方法。
当需要在图片上显示中文时,建议不要使用反锯齿功能,这样能够保证汉字的清晰度,代码如下:
chart.setAntiAlias(False);
可以自行定义图表标题的字体、样式、大小和颜色等,代码如下:
TextTitle title = chart.getTitle();
title.setFont(new Font("汉真广标", Font.BOLD, 21));
title.setPaint(Color.RED);
下面通过绘图区对象设置饼状图的绘制方向,可以按顺时针方向绘制,也可以按逆时针方向绘制,以及开始绘制第一段圆弧的角度,关键代码如下:
plot.setDirection(Rotation.ANTICLOCKWISE);
plot.setStartAngle(90);
可以设置饼形图的外观效果,例如圆形(True)或椭圆形(False),默认为圆形,建议在绘制3D效果图时将其设为False,关键代码如下;
plot.setCircular(False);
下面让饼形图实现透明效果,代码如下:
plot.setForegroundAlpha(0.8f);
通过JFreeChart插件,既可以生成普通效果的折线图,也可以生成3D效果的折线图。如果想生成普通效果的折线图,需要通过工厂类ChartFactory的createLineChart()方法获得JFreeChart类的实例;如果想生成3D效果的折线图,需要通过工厂类ChartFactory的createLineChart3D()方法获得JFreeChart类的实例。这两个方法的入口参数是完全相同的,各个入口参数的类型及功能请参见14.2.1节的表14.2。
可以分别通过绘图区对象CategoryPlot的getDomainAxis()方法和getRangeAxis()方法,获得横轴对象和纵轴对象,通过得到的轴对象可以设置绘制坐标轴的相关属性,常用方法及实现功能如表14.4所示。
表14.4 设置坐标轴绘制属性的部分通用方法
通 用 方 法 |
实 现 功 能 |
setAxisLineStroke(Stroke stroke) |
通过该方法可以设置轴线的粗细 |
setAxisLinePaint(Paint paint) |
通过该方法可以设置轴线的颜色 |
setLabelFont(Font font) |
通过该方法可以设置坐标轴标题的字体 |
setLabelPaint(Paint paint) |
通过该方法可以设置坐标轴标题的颜色 |
纵轴对象还提供了设置坐标最大值的方法setUpperBound(double max),在默认情况下将最大值控制在能够正常绘制统计图的范围内。
通过java.awt.BasicStroke类可以绘制出各种各样的线段,大体分为实线段和虚线段,可控的绘制条件包括线条的宽度、线段端点的风格、折线段的折点风格、虚线段的绘制风格和虚线段的绘制偏移量,BasicStroke类提供的所有构造方法如表14.5所示。
表14.5 BasicStroke类提供的所有构造方法
构 造 方 法 |
使 用 说 明 |
BasicStroke() |
创建一个实线对象,各控制条件均采用默认值,宽度为1.0,端点风格为CAP_SQUARE,折点风格为JOIN_MITER,折点控制值为10.0 |
BasicStroke(float width) |
创建一个指定宽度的实线对象,其他参数仍采用默认值 |
BasicStroke(float width, int cap, int join) |
创建一个指定宽度、指定端点风格和指定折点风格的实线对象,折点控制值仍采用默认值10.0 |
BasicStroke(float width, int cap, int join, float miterlimit) |
创建一个指定宽度、指定端点风格、指定折点风格和指定折点控制值的实线对象 |
BasicStroke(float width, int cap, int join, float miterlimit, float dash[], float dash_phase) |
通过该构造方法,既可以创建实线对象,又可以创建虚线对象,当将参数dash设为null时,创建的即为实线对象,如果将其设为float型数组,创建的则为虚线对象,最后一个参数用来设置开始绘制虚线的偏移量 |
线段端点的修饰风格有3种,分别由3个常量表示,具体信息如表14.6所示。
表14.6 线段端点修饰风格简介
常 量 名 称 |
常 量 值 |
修 饰 办 法 |
BasicStroke.CAP_BUTT |
0 |
对线段端点不加任何修饰 |
BasicStroke.CAP_ROUND |
1 |
在线段端点加半圆进行修饰,半圆的直径为线段的宽度 |
BasicStroke.CAP_SQUARE |
2 |
在线段端点加矩形进行修饰,矩形的宽度为线段宽度的一半,矩形的高度为线段的宽度 |
线段折点的修饰风格同样有3种,也由3个常量表示,具体信息如表14.7所示。
表14.7 线段折点修饰风格简介
常 量 名 称 |
常 量 值 |
修 饰 办 法 |
BasicStroke.JOIN_MITER |
0 |
对线段折点不加任何修饰 |
BasicStroke.JOIN_ROUND |
1 |
在折线段的两端加半圆进行修饰,半圆的直径为线段的宽度 |
BasicStroke.JOIN_BEVEL |
2 |
将组成折点的两条线段的外侧延长至相交,然后填充被包的区域 |
入口参数dash用来定义虚线,为float型数组,当dash数组由偶数个元素组成时,索引值为偶数的元素值代表虚线段的长度,索引值为奇数的元素值代表两个虚线段之间的空白部分的长度,需要注意的是,数组的索引值是从0开始的;当数组中只有一个元素时,例如dash={6},等同于dash={6,6}。
注意:建议不要为dash数组设定奇数个元素,那样将无法把握虚线的绘制规律,为一个元素的情况除外。
入口参数dash_phase用来定义虚线开始绘制位置的偏移量。以dash={6}为例,如果dash_phase=0,则虚线正常绘制;如果dash_phase=3,则第一段短化线的长度为6-3,后面则正常绘制。
示例14-04 编程类图书年销量折线图分析
下面来看一个绘制折线图的例子,该例绘制的折线图效果如图14.6和图14.7所示。
图14.6 普通效果的折线图 图14.7 3D效果的折线图
代码14-04 光盘位置:光盘\mingrisoft\14\sl\04
下面的代码负责定义折线的绘制风格,并将指定的图例用实线绘制,代码如下:
BasicStroke realLine = new BasicStroke(1.6f);
float dashes[] = { 8.0f }; // 定义虚线数组
BasicStroke brokenLine = new BasicStroke(1.6f, // 线条粗细
BasicStroke.CAP_ROUND, // 端点风格
BasicStroke.JOIN_ROUND, // 折点风格
8.f, // 折点处理办法
dashes, // 虚线数组
0.0f); // 虚线偏移量
int special = 1; // 定义利用需线绘制的图例
for (int i = 0; i < cutline.length; i++) {
if (i == special) {
renderer.setSeriesStroke(i, realLine); // 利用实线绘制
} else {
renderer.setSeriesStroke(i, brokenLine); // 利用虚线绘制
}
}
下面的代码负责获得横轴对象,并设置相关的绘图属性,代码如下:
CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setAxisLineStroke(new BasicStroke(1.6f)); // 设置轴线粗细
domainAxis.setAxisLinePaint(Color.BLACK); // 设置轴线颜色
domainAxis.setCategoryLabelPositionOffset(5); // 设置统计种类与轴线的颜色
domainAxis.setLabelFont(new Font("黑体", Font.BOLD, 16)); // 设置坐标轴标题字体
domainAxis.setLabelPaint(Color.BLACK); // 设置坐标轴标题颜色
// 设置坐标轴标题旋转角度,这里并未旋转,目的是告诉读者这个方法
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
下面的代码负责获得纵轴对象,并设置相关的绘图属性,代码如下:
ValueAxis rangeAxis = plot.getRangeAxis();
rangeAxis.setAxisLineStroke(new BasicStroke(1.6f)); // 设置轴线粗细
rangeAxis.setAxisLinePaint(Color.BLACK); // 设置轴线颜色
rangeAxis.setUpperBound(100.0f); // 设置坐标最大值
rangeAxis.setTickMarkStroke(new BasicStroke(1.6f)); // 设置坐标标记大小
rangeAxis.setTickMarkPaint(Color.BLACK); // 设置坐标标记颜色
rangeAxis.setLabelFont(new Font("黑体", Font.BOLD, 16)); // 设置坐标轴标题字体
rangeAxis.setLabelPaint(Color.BLACK); // 设置坐标轴标题颜色
rangeAxis.setLabelAngle(Math.PI / 2); // 设置坐标轴标题旋转角度
通过JFreeChart插件只能生成普通效果的区域图,利用工厂类ChartFactory的createXYAreaChart()方法获得JFreeChart类的实例,在封装用来绘制区域图的数据时,既可以利用CategoryDataset数据集,也可以利用XYDataset数据集。
XYDataset数据集主要用来绘制与日期相关的统计图,这种统计图的横轴通常为日期标度,纵轴为数值标度,JFreeChart提供了格式化坐标轴标度的功能;在格式化横轴的日期标度时,可以通过java.text.SimpleDateFormat类格式化日期的输出格式,SimpleDateFormat类继承于java.text.DateFormat类。例如,通过下面的代码可以将日期和时间进行格式化:
DateFormat dateFormatDA = new SimpleDateFormat("yyyy-MM-dd"); // 年以4位显示
DateFormat dateFormatDB = new SimpleDateFormat("yy-MM-dd"); // 年以2位显示
DateFormat dateFormatTA = new SimpleDateFormat("HH:MM:SS"); // 24小时的形式显示
DateFormat dateFormatTB = new SimpleDateFormat("HH:MM:SS a"); // 12小时的形式显示
说明:这里只是给出了几个典型的格式化方式,读者可以在此基础上举一反三。
还可以通过org.jfree.chart.axis.DateTickUnit类定义日期标度的单位和间隔,其中一个构造函数的定义如下:
DateTickUnit(int unit, int count, DateFormat formatter)
参数说明
ll unit:日期标度的统计单位。
ll count:日期标度的输出间隔。
ll formatter:日期标度的格式化方式。
在格式化纵轴的数值标度时,可以通过java.text.DecimalFormat类格式化数值的输出格式,例如可以将数值进行如下格式化:
DecimalFormat decimalFormat = new DecimalFormat("0.00"); // 保留小数点后两位
DecimalFormat decimalFormat = new DecimalFormat("0%"); // 以百分比的形式输出
说明:这里只是给出了几个典型的格式化方式,读者可以在此基础上举一反三。
还可以通过org.jfree.chart.axis.NumberTickUnit类定义数值标度的间隔,其中一个构造函数的定义如下:
NumberTickUnit(double size, NumberFormat formatter)
参数说明
ll size:数值标度的输出间隔。
ll formatter:日期标度的格式化方式。
示例14-05 每日股票走势区域图分析
下面来看一个绘制区域图的例子,该例绘制的区域图效果如图14.8所示。
图14.8 每日股票走势区域图分析
代码14-05 光盘位置:光盘\mingrisoft\14\sl\05
定义日期轴,每隔两小时输出一个标记,代码如下:
DateAxis domainAxis = new DateAxis("统计时间" + date);
DateFormat dateFormat = new SimpleDateFormat("HH");
DateTickUnit unit = new DateTickUnit(DateTickUnit.HOUR, 2, dateFormat);
domainAxis.setTickUnit(unit);
plot.setDomainAxis(domainAxis);
定义数值轴,以百分比的形式输出,并且每隔5个百分比输出一个标记,代码如下:
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
DecimalFormat decimalFormat = new DecimalFormat("0%");
NumberTickUnit ntu = new NumberTickUnit(0.05, decimalFormat);
rangeAxis.setTickUnit(ntu);
通过JFreeChart插件只能生成普通效果的时序图,利用工厂类ChartFactory的createTimeSeriesChart()方法获得JFreeChart类的实例,在封装用来绘制时序图的数据时,只能利用XYDataset数据集,而不能利用CategoryDataset数据集。
时序图与折线图有些类似,不过时序图提供了绘制移动平均线的功能,通过给定的数据集对象,可以自动计算任意时间段的移动平均值,移动平均值的计算方法请参见表14.8。
表14.8 移动平均值的计算方法
时 间 |
零 售 价 |
2天内的移动平均值 |
3天内的移动平均值 |
||
值 |
移动平均值的计算方法 |
值 |
移动平均值的 |
||
2008-8-6 |
4 |
无 |
也可视为4 |
无 |
也可视为4 |
2008-8-7 |
6 |
5 |
(4+6)/2 |
无 |
也可视为5 |
2008-8-8 |
8 |
7 |
(6+8)/2 |
6 |
(4+6+8)/3 |
如果要绘制移动平均线,就要创建一个用来绘制移动平均线的数据集实例,MovingAverage类提供了多个重载的用来创建数据集对象的静态方法,其一的定义如下:
public static TimeSeries createMovingAverage(TimeSeries source,
String name, int periodCount, int skip)
参数说明
ll source:移动平均线对应的绘图数据集实例,移动平均线的绘制数据即根据该实例产生。
ll name:移动平均线图例的名称。
ll periodCount:移动平均值的计算周期。
ll skip:移动平均值的起始计算点。
然后通过TimeSeriesCollection类的addSeries()方法,将绘图数据集和移动平均线数据集添加到TimeSeriesCollection类的实例中。
示例14-06 每日股票走势时序图分析
下面来看一个绘制时序图的例子,该例绘制的时序图效果如图14.9所示。
图14.9 每日股票走势时序图分析
代码14-06 光盘位置:光盘\mingrisoft\sl\14\06
创建绘图数据集实例,代码如下:
TimeSeries timeSeries = new TimeSeries(chartTitle, xTitle, yTitle, Minute.class);
Iterator it = data.keySet().iterator();
Minute minute;
while (it.hasNext()) {
minute = (Minute) it.next();
timeSeries.add(minute, (Double) data.get(minute));
}
创建用来绘制移动平均线的数据集实例,代码如下:
TimeSeries average1 = MovingAverage.createMovingAverage(timeSeries,
"每1小时平均涨幅百分比", 60, 0); // 绘制1小时移动平均线
TimeSeries average2 = MovingAverage.createMovingAverage(timeSeries,
"每2小时平均涨幅百分比", 120, 0); // 绘制2小时移动平均线
TimeSeries average4 = MovingAverage.createMovingAverage(timeSeries,
"每4小时平均涨幅百分比", 240, 0); // 绘制4小时移动平均线
将数据集实例和移动平均线数据集实例添加到TimeSeriesCollection类的实例中,代码如下:
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(timeSeries);
dataset.addSeries(average1);
dataset.addSeries(average2);
dataset.addSeries(average4);
通过JFreeChart插件还可以生成拥有多个坐标轴的图表,简称多轴图表。在生成多轴图表时,必须通过绘图区对象,因为在JFreeChart中各种风格的统计图均是绘制在绘图区对象上的,一个绘图区对象可以接收多个坐标轴对象、数据集对象和绘图风格对象,向单轴图表中添加附加轴的基本步骤如下。
(1)创建一个坐标轴对象并添加到绘图区对象当中。
(2)将相应的绘图数据集对象添加到绘图区对象当中。
(3)通过绘图区对象将相应的绘图数据集对象和对应的坐标轴对象建立映射关系。
(4)创建一个用来描述绘图数据的图形对象,并添加到绘图区对象当中。
下面是一个多轴图表之双轴图表的典型应用,下面将以此讲解多轴图表的具体生成方法。
实例位置:光盘\mingrisoft\14\dxyy\01
该典型应用生成的多轴图表的效果如图14.10所示。
图14.10 利用JFreeChart生成多轴图表
因为在绘制多轴图表时,需要用到绘图区对象,所以在这里首先获得绘图区对象,代码如下:
CategoryPlot plot = chart.getCategoryPlot();
下面创建一个坐标轴对象,并添加到绘图区对象当中,代码如下:
ValueAxis axis1 = new NumberAxis("季度销售汇总 单位:万册");
plot.setRangeAxis(1, axis1);
在创建坐标轴对象时,入口参数为坐标轴的名称。在通过绘图区对象的setRangeAxis()方法将坐标轴对象添加到绘图区时,需要提供两个入口参数,第一个为坐标轴的索引位置,要求为正整数,绘图区默认的坐标轴索引为“0”,所以这里将其设为“1”;第二个为坐标轴对象。
下面的代码负责封装绘图数据集,并将其添加到绘图区对象当中,代码如下:
DefaultCategoryDataset dataset1 = new DefaultCategoryDataset();
// 封装绘图数据集的具体代码略
plot.setDataset(1, dataset1);
在通过绘图区对象的setDataset()方法将绘图数据集对象添加到绘图区时,同样需要提供两个入口参数,第一个为数据集的索引位置,要求为正整数,绘图区默认的绘图数据集索引为“0”,所以这里将其设为“1”;第二个为绘图数据集对象。
下面需要将绘图数据集对象和欲采用的坐标轴对象建立映射关系,方法如下:
plot.mapDatasetToRangeAxis(1, 1);
在通过绘图区对象的mapDatasetToRangeAxis()方法将绘图数据集对象和坐标轴对象建立映射关系时,同样需要提供两个入口参数,第一个为数据集的索引位置;第二个为坐标轴的索引位置。
注意:并不是索引位置相同的绘图数据集和坐标轴是一一对应的,如果不为索引位置为非0的绘图数据集映射对应的坐标轴,JFreeChart默认采用索引位置为0的坐标轴,所以,也可以利用一个坐标轴来描述图形对象的数据信息。
最后,创建一个用来描述绘图数据的图形对象,并添加到绘图区对象当中,代码如下:
CategoryItemRenderer renderer1 = new LineAndShapeRenderer();
renderer1.setSeriesPaint(0, Color.BLACK);
plot.setRenderer(1, renderer1);
注意:用来描述绘图数据的图形对象和绘图数据集的索引是一一对应的。
实例位置:光盘\mingrisoft\14\dxyy\02
通过JFreeChart插件还可以生成拥有多个绘图区的图表,简称组合图表,在生成组合图表时,必须通过绘图区对象,因为JFreeChart允许向绘图区对象中添加子绘图区对象。
下面是一个组合图表的典型应用,下面将以此讲解组合图表的具体生成方法。
分析一下图14.11中的两个绘图区,每个绘图区拥有各自的X轴,该图左侧的Y轴为两个绘图区共用的Y轴,使用该Y轴的图例有“涨幅百分比”和“今日涨幅之最”,图例“今日股价之最”使用右侧的Y轴,右侧的Y轴为右侧绘图区的附加轴,生成原理同14.7节,然后看一下图14.11的具体生成方法。
该典型应用生成的组合图表的效果如图14.11所示。
图14.11 利用JFreeChart生成组合图表
程序实现过程如下。
(1)首先定义右侧子绘图区,代码如下:
// 创建一个绘图区对象
XYPlot plot1 = new XYPlot();
// 定义独立的X轴
DateAxis axis1 = new DateAxis("今日之最");
DateTickUnit unit1 = new DateTickUnit(DateTickUnit.HOUR, 1, new SimpleDateFormat("HH"));
axis1.setTickUnit(unit1);
plot1.setDomainAxis(axis1);
// 因为共用Y轴,所以将其设为空
plot1.setRangeAxis(null);
// 设定绘图数据集,数据集在前面已经封装完毕,这里不再详细介绍
plot1.setDataset(dataset1);
// 定义绘图风格
XYLineAndShapeRenderer xyArea1 = new XYLineAndShapeRenderer();
plot1.setRenderer(xyArea1);
(2)在右侧的绘图区中添加一个附加轴,用来统计股票的具体价格,代码如下:
// 创建附加轴对象,并添加到绘图区
ValueAxis axis11 = new NumberAxis("股票价格(单位:元 / 股)");
axis11.setUpperBound(30.0); // 设置Y轴最大值
axis11.setLowerBound(10.0); // 设置Y轴最小值
plot1.setRangeAxis(1, axis11);
// 创建与附加轴对应的数据集,并添加到绘图区
TimeSeries timeSeries11 = new TimeSeries("今日股价之最", Minute.class);
timeSeries11.add(startMinute, yesterdayValue);
timeSeries11.add(minMinute, yesterdayValue + yesterdayValue * minPercent);
timeSeries11.add(maxMinute, yesterdayValue + yesterdayValue * maxPercent);
timeSeries11.addOrUpdate(endMinute, yesterdayValue + yesterdayValue * endPercent);
IntervalXYDataset dataset11 = new TimeSeriesCollection(timeSeries11);
plot1.setDataset(1, dataset11);
// 将绘图数据集映射到附加轴上
plot1.mapDatasetToRangeAxis(1, 1);
// 定义附加轴的绘图风格,这里为折线
XYLineAndShapeRenderer xyArea11 = new XYLineAndShapeRenderer();
plot1.setRenderer(1, xyArea11);
(3)定义左侧子绘图区,代码如下:
// 创建一个绘图区对象
XYPlot plot2 = new XYPlot();
// 定义独立的X轴
DateAxis axis2 = new DateAxis("统计时间");
DateTickUnit unit2 = new DateTickUnit(DateTickUnit.MINUTE, 30,
new SimpleDateFormat("HH:mm"));
axis2.setTickUnit(unit2);
plot2.setDomainAxis(axis2);
// 因为共用Y轴,所以将其设为空
plot2.setRangeAxis(null);
// 设定绘图数据集,数据集在前面已经封装完毕,这里不再详细介绍
plot2.setDataset(dataset2);
// 定义绘图风格
XYAreaRenderer xyArea2 = new XYAreaRenderer();
plot2.setRenderer(xyArea2);
(4)定义父绘图区,代码如下:
// 创建一个绘图区对象
CombinedRangeXYPlot plot = new CombinedRangeXYPlot();
// 定义共用坐标轴
NumberAxis axis = new NumberAxis("股票涨幅百分比");
axis.setTickUnit(new NumberTickUnit(0.025,new DecimalFormat("0.0%")));//定义度量值风格
plot.setRangeAxis(axis);
// 添加子绘图区
plot.add(plot2, 5);
plot.add(plot1, 2);
说明:在通过绘图区对象的add()方法添加子绘图区对象时,第一个入口参数为欲添加的子绘图区对象,第二个入口参数为该绘图区所占的比例,上面代码的意思是plot2占5/7,plot1占2/7,还需要注意的是,绘图区从左到右的排列顺序是由添加子绘图区的先后顺序决定的。
下面的代码是通过上面的父绘图区对象生成图表,并获得浏览路径:
// 创建图表
JFreeChart chart = new JFreeChart(chartTitle, plot);
// 添加图表副标题
chart.addSubtitle(new TextTitle(subtitle));
// 固定用法
ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
// 生成指定格式的图片,并返回图片名称
String fileName = ServletUtilities.saveChartAsPNG(chart, width, height, info, session);
// 返回图片浏览路径
return servletURI + "?filename=" + fileName;
至此,一个组合图表就绘制完成了,这里绘制的是共用Y轴的组合图表,同样也可以绘制出共用X轴的组合图表。
<!--EndFragment-->