JFreechart綜合
JFreeChart是一個Java開源項目,是一款優秀的Java圖表生成插件,它提供了在Java Application、Servlet和JSP下生成各種圖片格式的圖表,包括柱形圖、餅形圖、線圖、區域圖、時序圖和多軸圖等。本章將詳細介紹利用 JFreeChart生成各種圖表的技術要點。
14.1 JFreeChart基礎
本節將介紹JFreeChart插件的下載與使用方法,以及JFreeChart插件的核心類及其 功能。
14.1.1 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>元素顯示圖片。
14.1.2 JFreeChart核心類簡介
在使用JFreeChart插件之前,先介紹該插件的核心類及其功能,這對將來能夠得心應手地使用該插件是非常重要的,JFreeChart核心類及其功能如表14.1所示。
表14.1 JFreeChart核心類及其功能
類 名 |
功 能 |
JFreeChart |
圖表對象,生成任何類型的圖表都要通過該對象,JFreeChart插件提供了一個工廠類ChartFactory,用來創建各種類型的圖表對象 |
XXXDataset |
數據集對象,用來保存繪制圖表的數據,不同類型的圖表對應著不同類型的數據集對象 |
XXXPlot |
繪圖區對象,如果需要自行定義繪圖區的相關繪制屬性,需要通過該對象進行設置 |
XXXAxis |
坐標軸對象,用來定義坐標軸的繪制屬性 |
XXXRenderer |
圖片渲染對象,用于渲染和顯示圖表 |
XXXURLGenerator |
鏈接對象,用于生成Web圖表中項目的鼠標單擊鏈接 |
XXXToolTipGenerator |
圖表提示對象,用于生成圖表提示信息,不同類型的圖表對應著不同類型的圖表提示對象 |
通過表14.1,可以簡單了解JFreeChart插件中各個類的功能,下面將仔細講解利用JFreeChart生成各種圖表的技術要點。
14.2 利用JFreeChart生成柱形圖
14.2.1 利用DefaultCategoryDataset數據集繪制柱形圖
通過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;
14.2.2 利用XYDataset數據集繪制柱形圖
利用實現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);
14.3 利用JFreeChart生成餅形圖
通過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);
14.4 利用JFreeChart生成折線圖
通過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); // 設置坐標軸標題旋轉角度
14.5 利用JFreeChart生成區域圖
通過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);
14.6 利用JFreeChart生成時序圖
通過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);
14.7 利用JFreeChart生成多軸圖表
通過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);
注意:用來描述繪圖數據的圖形對象和繪圖數據集的索引是一一對應的。
14.8 利用JFreeChart生成組合圖表
實例位置:光盤\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軸的組合圖表。