1、簡介
1.1 概述
對於大多數的圖表類型來說,JFreeChart允許我們在圖表的每個條目上、或者內部、或者附近顯示條目標簽。例如,下圖在每個條形圖上顯示出了真實的值。
本文主要講述:
l如何讓條目標簽可視(僅限於支持條目標簽的圖表類型)
l如何改變條目標簽的外觀(字體和顏色)
l如何指定條目標簽的位置
l如何定制條目標簽的文本
忠告:我們使用上面的特征時,要謹慎。圖表是期望用來分析總結數據的——如果我們覺得在圖表上顯示真實數據是非常有必要的話,那我們的數據應使用一個表格格式顯示更為合適。
1.2 局限性
在當前版本JFreeChart中,條目標簽的使用是有很多局限性的:
l一些renderer不支持條目標簽
l軸范圍的自動調節,忽略了條目標簽的自動調整——如果圖表的周圍沒有足夠的空間(使用方法setUpperMargin()或setLowerMargin()進行了相應的調整),那么一些圖表條目標簽在圖表上顯示不出來。
相信,在以后的JFreeChart版本中,這些限制問題將被解決。
2、顯示條目標簽
2.1 概述
條目標簽默認是不顯示的,因此我們需要使用renderer進行創建和顯示條目標簽。這主要有以下兩個步驟:
l分配一個CategoryItemLabelGenerator或XYItemLabelGenerator給renderer—這是一個負責創建標簽的對象。
l在renderer里面設置一個標簽可視的標志。可以針對全部系列進行設置,也可以針對具體的每一個系列進行設置。
此外,我們可以定制條目標簽的位置、字體和顏色。在下面的章節里我們將詳細的介紹。
2.2 創建一個條目標簽並賦值
使用renderer分配的一個標簽產生器創建條目標簽(這與圖表工具條的機制是相同的)。
下面代碼說了將一個標簽產生器指派給CategoryItemRenderer:
CategoryItemRenderer renderer = categoryplot.getRenderer(); CategoryItemLabelGenerator generator = new StandardCategoryItemLabelGenerator("{2}", new DecimalFormat("0.00")); renderer.setBaseItemLabelGenerator(generator);
同樣的,將一個產生器指派給XYItemRenderer,代碼如下:
XYPlot plot = (XYPlot) jfreechart.getPlot(); XYItemRenderer renderer = plot.getRenderer(); XYItemLabelGenerator generator = new StandardXYItemLabelGenerator("{2}", new DecimalFormat("0.00"), new DecimalFormat("0.00")); renderer.setBaseItemLabelGenerator(generator);
我們可以在標准產生器的構造函數中定制不同的行為。當然了,我們也可以創建我們總計的產生器,詳見5.2章節。
2.3 所有的系列顯示條目標簽
方法renderer.setBaseItemLabelsVisible(false)是控制着條目標簽的顯示。對於CategoryItemRenderer:
CategoryItemRenderer renderer = categoryplot.getRenderer(); renderer.setBaseItemLabelsVisible(true);
同樣對於:XYItemRenderer
XYItemRenderer renderer = categoryplot.getRenderer(); renderer.setBaseItemLabelsVisible(true);
一旦設置,這個標志優先管理我們在所有地方對每一系列做的設置,主要為了應用每一系列的設置。我們可以設置個標志為null(見2.4章節)
2.4 為選擇的系列顯示條目標簽
我們可以控制圖表的每一個系列的條目標簽是否顯示。例如:如下圖僅顯示第一系列條目標簽。
v
下面代碼可以設置如上效果:
CategoryItemRenderer renderer = categoryplot.getRenderer(); renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator()); renderer.setBaseItemLabelsVisible(null); // clears the ALL series flag renderer.setSeriesItemLabelsVisible(0, true); renderer.setSeriesItemLabelsVisible(1, false);
注意:上面代碼中對全部的系列設置為null—這一點非常重要,因為全部系列的標志控制每一個系列的標志。
2.5 問題與解決
如果按照上面的步驟操作,你仍然未看見條目標簽顯示在圖表上,那么我們從以下幾個方面進行考慮:
lRenderere必須需要一個標簽產生器——這是一個用來創建每一個標簽的文本條目的對象。
l一些renderer不支持條目標簽(具體參考renderer相關的文檔)
3、條目標簽外觀
3.1 概述
我們可以通過改變條目的顏色、字體來改變圖表條目標簽的外觀。正如其他renderer屬性一樣,屬性的設置可以是全部的系列,可以是具體某一系列。
在JFreeChart目前的版本中,標簽是月年個一個透明的背景畫出來的。我們不能設置標簽的背景顏色,也不能指定標簽的邊框。這些在以后的版本中會得到解決。
3.2 改變條目標簽字體
為了在所有的系列中改變條目標簽的字體,我們可以使用下面的代碼:
CategoryItemRenderer renderer = categoryplot.getRenderer(); renderer.setBaseItemLabelFont(new Font("黑體", Font.PLAIN, 20));
同樣,也可以為單個系列設置字體:
//add settings for individual series... renderer.setSeriesItemLabelFont(0, new Font("SansSerif", Font.PLAIN, 20)); renderer.setSeriesItemLabelFont(1, new Font("SansSerif", Font.PLAIN, 10));
注意:renderer.setBaseItemLabelFont(null)方法會出錯。開發指南顯示的代碼有錯誤。
3.3 改變條目標簽的顏色
改變條目標簽的顏色,我們可以使用下面的代碼:
CategoryItemRenderer renderer = categoryplot.getRenderer();
renderer.setBaseItemLabelPaint(Color.red);
同樣的,可以為單獨每一系列設置顏色:
//add settings for individual series... renderer.setSeriesItemLabelPaint(0, Color.red); renderer.setSeriesItemLabelPaint(1, Color.blue);
注意:renderer.setBaseItemLabelPaint(null);方法會出錯。開發指南顯示的代碼有錯誤。
4、條目標簽的位置
4.1 概述
條目標簽的位置是通過ItemLabelPosition對象的四個屬性來控制的。
我們可以通過接口CategoryItemRenderer的方法來獨立定義條目標簽的正負點位置:
public void setBasePositiveItemLabelPosition(ItemLabelPosition position); public void setBaseNegativeItemLabelPosition(ItemLabelPosition position);
理解這些屬性如何影響獨立標簽的最終位置的關鍵是了解JFreeChart里面條目標簽的特征。四個特征是:
l條目標簽點——決定標簽的起始位置
l文本點——標簽里的文本相對於條目標簽的位置。
l旋轉點——標簽文本旋轉的點位置
l旋轉角度——標簽的旋轉角度。
這些的詳細描述在下一章詳細介紹。
4.2 條目標簽的位置
設置條目標簽位置的目的,主要是為了找出標簽在圖表上貼向數據條目的一個點(x,y)位置。同時在畫圖表時,該標簽也被畫在該點處。更多的信息可以參考ItemLabelAnchor文檔。
4.3 標簽文本的位置
標簽文本的位置,主要取決於上節講的標簽位置。我們可以講標簽文本在標簽里設置在右上部、或左下部等,更多的信息參見TextAnchor文檔。
運行JCommon包內的org.demo.package下面的DrawStringDemo應用,可以更好的理解標簽文本在標簽內是如何放置的。
4.4 標簽旋轉點
在標簽上定義了一個旋轉點,用於旋轉標簽。在DrawStringDemo實例中很好演示了這個特征。
4.5 標簽旋轉角度
旋轉角度定義了標簽沿旋轉點旋轉的角度。該角度為弧度。
5、定制條目標簽文本
5.1 概述
定制條目標簽文本,我們需要依賴用JFreeChart里的標簽產生器來為條目標簽創建文本。如果要想完全控制標簽文本的控制,我們就需要編寫自己的標簽產生器,需要實現接口CategoryItemLabelGenerator。
在本章節里,我們對自定義標簽器技術做了簡要的講述,然后用兩個實例來說明該技術過程。
5.2 實現一個自定義的標簽生成器
開發一個自定義標簽產生器,我們需要寫一個類,該類必須實現CategoryItemLabelGenerator接口里的方法。
public String generateLabel(CategoryDataset dataset, int series,int category)
該renderer調用該方法獲得一個標簽的字符串,並且將該字符串傳入到當前條目的CategoryDataset、序列和種類。這就意味着創建這個標簽時,我們擁有完全的訪問權限。
該方法可以返回任意字符串,因此我們格式化這個字符串。如果我們不想顯示標簽,可以設置為null。
在下面的兩個例子中很好的說明了這個特征。
6 實例一
本例實現一個當條目值大於某個限定值時就顯示標簽,效果如下圖:
做到這一點並不困難,需要做以下工作:
l寫一個實現接口CategoryItemLabelGenerator的類,並且實現generateItemLabel()方法。該方法實現如果條目的值小於限定值時,返回null。
l創建該類的實例,將該實例使用renderer的方法setLabelGenerator()設置到renderer中去。
代碼如下:
/** * 演示自定義ItemLabel生成器 * Item值大於某限定值時顯示標簽 * @author mervin(馬建新) * */ public class ItemLabelDemo1 extends ApplicationFrame { // 自定義的標簽生成器 static class LabelGenerator extends AbstractCategoryItemLabelGenerator implements CategoryItemLabelGenerator { private double threshold; public LabelGenerator(double d) { super("", NumberFormat.getInstance()); threshold = d; } public String generateLabel(CategoryDataset categorydataset, int i, int i_0_) { String string = null; Number number = categorydataset.getValue(i, i_0_); if (number != null) { double d = number.doubleValue(); if (d > threshold) string = number.toString(); } return string; } } public ItemLabelDemo1(String string) { super(string); CategoryDataset categorydataset = createDataset(); JFreeChart jfreechart = createChart(categorydataset); ChartPanel chartpanel = new ChartPanel(jfreechart); chartpanel.setPreferredSize(new Dimension(500, 270)); setContentPane(chartpanel); } private static CategoryDataset createDataset() { DefaultCategoryDataset defaultcategorydataset = new DefaultCategoryDataset(); defaultcategorydataset.addValue(11.0, "S1", "C1"); defaultcategorydataset.addValue(44.3, "S1", "C2"); defaultcategorydataset.addValue(93.0, "S1", "C3"); defaultcategorydataset.addValue(35.6, "S1", "C4"); defaultcategorydataset.addValue(75.1, "S1", "C5"); return defaultcategorydataset; } // 創建圖表 private static JFreeChart createChart(CategoryDataset categorydataset) { JFreeChart jfreechart = ChartFactory.createBarChart( "Item Label Demo 1", "Category", "Value", categorydataset, PlotOrientation.VERTICAL, false, true, false); jfreechart.setBackgroundPaint(Color.white); CategoryPlot categoryplot = (CategoryPlot) jfreechart.getPlot(); categoryplot.setBackgroundPaint(Color.lightGray); categoryplot.setDomainGridlinePaint(Color.white); categoryplot.setRangeGridlinePaint(Color.white); CategoryItemRenderer renderer = categoryplot.getRenderer(); //設置ItemLabel生成器 renderer.setBaseItemLabelGenerator(new LabelGenerator(50.0D)); //設置顯示ItemLabel renderer.setBaseItemLabelsVisible(true); NumberAxis numberaxis = (NumberAxis) categoryplot.getRangeAxis(); numberaxis.setUpperMargin(0.15); return jfreechart; } public static JPanel createDemoPanel() { JFreeChart jfreechart = createChart(createDataset()); return new ChartPanel(jfreechart); } public static void main(String[] strings) { ItemLabelDemo1 itemlabeldemo1 = new ItemLabelDemo1("Item Label Demo 1"); itemlabeldemo1.pack(); RefineryUtilities.centerFrameOnScreen(itemlabeldemo1); itemlabeldemo1.setVisible(true); } }
7 實例二
在本實例中,目的是在每個系列的標簽上顯示出值和百分比值(這個百分比值,這個系列在某一部分的條形直方圖或全部條形直方圖的總值中的比值)。如下圖所示。
該實現中,標簽產生器計算出百分比。如果傳入構造函數的是一個種類索引,那么這個百分比的基數就是指定種類的當前系列的值。如果種類索引是無效的,那么這個基數就是指定種類的全部系列總和。
標簽產生器會默認創建一個百分比格式——一種比較成熟的格式,提供格式化能力。
代碼:
/** * 自定義Item標簽生成器 * 生成百分比的ItemLabel * @author mervin(馬建新) * */ public class ItemLabelDemo2 extends ApplicationFrame { /** * 自定義標簽生成器 */ static class LabelGenerator extends AbstractCategoryItemLabelGenerator implements CategoryItemLabelGenerator { private Integer category; private NumberFormat formatter = NumberFormat.getPercentInstance(); public LabelGenerator(int i) { this(new Integer(i)); } public LabelGenerator(Integer integer) { super("", NumberFormat.getInstance()); category = integer; } public String generateLabel(CategoryDataset categorydataset, int i, int i_0_) { String string = null; double d = 0.0; if (category != null) { Number number = categorydataset.getValue(i, category.intValue()); d = number.doubleValue(); } else d = calculateSeriesTotal(categorydataset, i); Number number = categorydataset.getValue(i, i_0_); if (number != null) { double d_1_ = number.doubleValue(); string = (number.toString() + " (" + formatter.format(d_1_ / d) + ")"); } return string; } //計算總計 private double calculateSeriesTotal(CategoryDataset categorydataset,int i) { double d = 0.0; for (int i_2_ = 0; i_2_ < categorydataset.getColumnCount(); i_2_++) { Number number = categorydataset.getValue(i, i_2_); if (number != null) d += number.doubleValue(); } return d; } } public ItemLabelDemo2(String string) { super(string); CategoryDataset categorydataset = createDataset(); JFreeChart jfreechart = createChart(categorydataset); ChartPanel chartpanel = new ChartPanel(jfreechart); chartpanel.setPreferredSize(new Dimension(500, 270)); setContentPane(chartpanel); } private static CategoryDataset createDataset() { DefaultCategoryDataset defaultcategorydataset = new DefaultCategoryDataset(); defaultcategorydataset.addValue(100.0, "S1", "C1"); defaultcategorydataset.addValue(44.3, "S1", "C2"); defaultcategorydataset.addValue(93.0, "S1", "C3"); defaultcategorydataset.addValue(80.0, "S2", "C1"); defaultcategorydataset.addValue(75.1, "S2", "C2"); defaultcategorydataset.addValue(15.1, "S2", "C3"); return defaultcategorydataset; } private static JFreeChart createChart(CategoryDataset categorydataset) { JFreeChart jfreechart = ChartFactory.createBarChart( "Item Label Demo 2", "Category", "Value", categorydataset, PlotOrientation.HORIZONTAL, true, true, false); jfreechart.setBackgroundPaint(Color.white); CategoryPlot categoryplot = (CategoryPlot) jfreechart.getPlot(); categoryplot.setBackgroundPaint(Color.lightGray); categoryplot.setDomainGridlinePaint(Color.white); categoryplot.setRangeGridlinePaint(Color.white); categoryplot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT); NumberAxis numberaxis = (NumberAxis) categoryplot.getRangeAxis(); numberaxis.setUpperMargin(0.25); CategoryItemRenderer categoryitemrenderer = categoryplot.getRenderer(); categoryitemrenderer.setBaseItemLabelsVisible(true); categoryitemrenderer.setBaseItemLabelGenerator(new LabelGenerator( (Integer) null)); return jfreechart; } public static JPanel createDemoPanel() { JFreeChart jfreechart = createChart(createDataset()); return new ChartPanel(jfreechart); } public static void main(String[] strings) { ItemLabelDemo2 itemlabeldemo2 = new ItemLabelDemo2("Item Label Demo 2"); itemlabeldemo2.pack(); RefineryUtilities.centerFrameOnScreen(itemlabeldemo2); itemlabeldemo2.setVisible(true); } }