JFreeChart之堆叠柱形图(StackedBar)

JFreeChart之堆叠柱形图(StackedBar)

最近的项目使用有个功能需要使用到堆叠柱形图,看了项目以前的代码实现没有想要的结果。所以自己就先到官网下载了 DemoDemo里有个打包好的Jar包,直接运行看到效果,但是坑爹的是貌似没有对应的源码,所以只能根据class名称直接google了,所幸在github里找到对应的源码。
点我下载 访问密码 f62b
这是运行Demo找到想要实现的效果的大致图:
JFreeChart之堆叠柱形图(StackedBar)_第1张图片
我最终想要实现的效果是这样的:
JFreeChart之堆叠柱形图(StackedBar)_第2张图片
如果想要实现这个效果,可以使用

  1. extendedstackedbarrenderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator("{3}"
  2. NumberFormat.getPercentInstance(), new DecimalFormat("#0.0%"))); 
  3.  

但是柱体的返回的值是10.1/50.1=20.2%,40.1/50.1=79.8%
JFreeChart之堆叠柱形图(StackedBar)_第3张图片
这不符合预期目标,所以就去看了一下源码,在StandardCategoryItemLabelGenerator的父类AbstractCategoryItemLabelGenerator中发现有createItemArray这么一个方法:
JFreeChart之堆叠柱形图(StackedBar)_第4张图片
可以发现柱体的标签值应该是由这个方法进行返回的,因此自己就对StandardCategoryItemLabelGenerator进行了继承,并重写了这个方法。
ExtendedStandardCategoryItemLabelGeneratory中增加了isPercent作为标签值是显示百分比还是仅仅格式化的判断参数,并重写了createItemArray这个方法。
JFreeChart之堆叠柱形图(StackedBar)_第5张图片
此时得到的效果如图:
JFreeChart之堆叠柱形图(StackedBar)_第6张图片
然而,柱体的总值还是没有格式化。再看了一下ExtendedStackedBarRenderer这个类的代码,找到了totalFormat这个属性,将其值赋为new DecimalFormat("#0.0%")。测试:
JFreeChart之堆叠柱形图(StackedBar)_第7张图片
基本是想要的最终结果,下面是测试代码

  1. <dependency> 
  2. <groupId>jfree</groupId> 
  3. <artifactId>jfreechart</artifactId> 
  4. <version>1.0.13</version> 
  5. </dependency> 

ExtendedStackedBarRenderer

  1. package com.springapp.jfreechar; 
  2.  
  3. import java.awt.Color; 
  4. import java.awt.Font; 
  5. import java.awt.Graphics2D; 
  6. import java.awt.geom.Rectangle2D; 
  7. import java.text.DecimalFormat; 
  8. import java.text.NumberFormat; 
  9.  
  10. import org.jfree.chart.axis.CategoryAxis; 
  11. import org.jfree.chart.axis.ValueAxis; 
  12. import org.jfree.chart.entity.CategoryItemEntity; 
  13. import org.jfree.chart.entity.EntityCollection; 
  14. import org.jfree.chart.labels.CategoryToolTipGenerator; 
  15. import org.jfree.chart.plot.CategoryPlot; 
  16. import org.jfree.chart.plot.PlotOrientation; 
  17. import org.jfree.chart.renderer.category.CategoryItemRendererState; 
  18. import org.jfree.chart.renderer.category.StackedBarRenderer; 
  19. import org.jfree.data.category.CategoryDataset; 
  20. import org.jfree.text.TextUtilities; 
  21. import org.jfree.ui.TextAnchor; 
  22.  
  23. public class ExtendedStackedBarRenderer extends StackedBarRenderer
  24.  
  25. private static final long serialVersionUID = 1L
  26. private boolean showPositiveTotal; 
  27. private boolean showNegativeTotal; 
  28. private Font totalLabelFont; 
  29. private NumberFormat totalFormatter; 
  30. public ExtendedStackedBarRenderer()
  31. showPositiveTotal = true
  32. showNegativeTotal = true
  33. totalLabelFont = new Font("SansSerif", 1, 12); 
  34. totalFormatter = new DecimalFormat("#0.0%"); 
  35.  
  36. /** 
  37. * StackedBarRenderer 没有这个构造方法的,传入一个NumberFormat类,可以自定义实现每个柱体值显示格式 
  38. * @param totalFormatter 
  39. */ 
  40. public ExtendedStackedBarRenderer(NumberFormat totalFormatter)
  41. showPositiveTotal = true
  42. showNegativeTotal = true
  43. totalLabelFont = new Font("SansSerif", 1, 12); 
  44. this.totalFormatter = totalFormatter; 
  45.  
  46. public NumberFormat getTotalFormatter()
  47. return totalFormatter; 
  48.  
  49. public void setTotalFormatter(NumberFormat numberformat)
  50. if (numberformat == null) { 
  51. throw new IllegalArgumentException("Null format not permitted."); 
  52. } else
  53. totalFormatter = numberformat; 
  54. return
  55.  
  56. public void drawItem(Graphics2D graphics2d, CategoryItemRendererState categoryitemrendererstate, Rectangle2D rectangle2d, CategoryPlot categoryplot, CategoryAxis categoryaxis, 
  57. ValueAxis valueaxis, CategoryDataset categorydataset, int i, int j, int k)
  58. Number number = categorydataset.getValue(i, j); 
  59. if (number == null
  60. return
  61. double d = number.doubleValue(); 
  62. PlotOrientation plotorientation = categoryplot.getOrientation(); 
  63. double d1 = categoryaxis.getCategoryMiddle(j, getColumnCount(), rectangle2d, categoryplot.getDomainAxisEdge()) - categoryitemrendererstate.getBarWidth() / 2D; 
  64. double d2 = 0.0D; 
  65. double d3 = 0.0D; 
  66. for (int l = 0; l < i; l++) { 
  67. Number number1 = categorydataset.getValue(l, j); 
  68. if (number1 == null
  69. continue
  70. double d5 = number1.doubleValue(); 
  71. if (d5 > 0.0D) 
  72. d2 += d5; 
  73. else 
  74. d3 += d5; 
  75.  
  76. org.jfree.ui.RectangleEdge rectangleedge = categoryplot.getRangeAxisEdge(); 
  77. double d4; 
  78. double d6; 
  79. if (d > 0.0D) { 
  80. d4 = valueaxis.valueToJava2D(d2, rectangle2d, rectangleedge); 
  81. d6 = valueaxis.valueToJava2D(d2 + d, rectangle2d, rectangleedge); 
  82. } else
  83. d4 = valueaxis.valueToJava2D(d3, rectangle2d, rectangleedge); 
  84. d6 = valueaxis.valueToJava2D(d3 + d, rectangle2d, rectangleedge); 
  85. double d7 = Math.min(d4, d6); 
  86. double d8 = Math.max(Math.abs(d6 - d4), getMinimumBarLength()); 
  87. Rectangle2D.Double double1 = null
  88. if (plotorientation == PlotOrientation.HORIZONTAL) 
  89. double1 = new Rectangle2D.Double(d7, d1, d8, categoryitemrendererstate.getBarWidth()); 
  90. else 
  91. double1 = new Rectangle2D.Double(d1, d7, categoryitemrendererstate.getBarWidth(), d8); 
  92. java.awt.Paint paint = getItemPaint(i, j); 
  93. graphics2d.setPaint(paint); 
  94. graphics2d.fill(double1); 
  95. if (isDrawBarOutline() && categoryitemrendererstate.getBarWidth() > 3D) { 
  96. graphics2d.setStroke(getItemStroke(i, j)); 
  97. graphics2d.setPaint(getItemOutlinePaint(i, j)); 
  98. graphics2d.draw(double1); 
  99. org.jfree.chart.labels.CategoryItemLabelGenerator categoryitemlabelgenerator = getItemLabelGenerator(i, j); 
  100. if (categoryitemlabelgenerator != null && isItemLabelVisible(i, j)) 
  101. drawItemLabel(graphics2d, categorydataset, i, j, categoryplot, categoryitemlabelgenerator, double1, d < 0.0D); 
  102. if (d > 0.0D) { 
  103. if (showPositiveTotal && isLastPositiveItem(categorydataset, i, j)) { 
  104. graphics2d.setPaint(Color.black); 
  105. graphics2d.setFont(totalLabelFont); 
  106. double d9 = calculateSumOfPositiveValuesForCategory(categorydataset, j); 
  107. float f = (float) double1.getCenterX(); 
  108. float f2 = (float) double1.getMinY() - 4F
  109. TextAnchor textanchor = TextAnchor.BOTTOM_CENTER; 
  110. if (plotorientation == PlotOrientation.HORIZONTAL) { 
  111. f = (float) double1.getMaxX() + 4F
  112. f2 = (float) double1.getCenterY(); 
  113. textanchor = TextAnchor.CENTER_LEFT; 
  114. TextUtilities.drawRotatedString(totalFormatter.format(d9), graphics2d, f, f2, textanchor, 0.0D, TextAnchor.CENTER); 
  115. } else if (showNegativeTotal && isLastNegativeItem(categorydataset, i, j))
  116. graphics2d.setPaint(Color.black); 
  117. graphics2d.setFont(totalLabelFont); 
  118. double d10 = calculateSumOfNegativeValuesForCategory(categorydataset, j); 
  119. float f1 = (float) double1.getCenterX(); 
  120. float f3 = (float) double1.getMaxY() + 4F
  121. TextAnchor textanchor1 = TextAnchor.TOP_CENTER; 
  122. if (plotorientation == PlotOrientation.HORIZONTAL) { 
  123. f1 = (float) double1.getMinX() - 4F
  124. f3 = (float) double1.getCenterY(); 
  125. textanchor1 = TextAnchor.CENTER_RIGHT; 
  126. TextUtilities.drawRotatedString(totalFormatter.format(d10), graphics2d, f1, f3, textanchor1, 0.0D, TextAnchor.CENTER); 
  127. if (categoryitemrendererstate.getInfo() != null) { 
  128. EntityCollection entitycollection = categoryitemrendererstate.getEntityCollection(); 
  129. if (entitycollection != null) { 
  130. String s = null
  131. CategoryToolTipGenerator categorytooltipgenerator = getToolTipGenerator(i, j); 
  132. if (categorytooltipgenerator != null
  133. s = categorytooltipgenerator.generateToolTip(categorydataset, i, j); 
  134. String s1 = null
  135. if (getItemURLGenerator(i, j) != null
  136. s1 = getItemURLGenerator(i, j).generateURL(categorydataset, i, j); 
  137. CategoryItemEntity categoryitementity = new CategoryItemEntity(double1, s, s1, categorydataset, categorydataset.getRowKey(i), categorydataset.getColumnKey(j)); 
  138. entitycollection.add(categoryitementity); 
  139.  
  140. private boolean isLastPositiveItem(CategoryDataset categorydataset, int i, int j)
  141. boolean flag = true
  142. Number number = categorydataset.getValue(i, j); 
  143. if (number == null
  144. return false
  145. for (int k = i + 1; k < categorydataset.getRowCount(); k++) { 
  146. Number number1 = categorydataset.getValue(k, j); 
  147. if (number1 != null
  148. flag = flag && number1.doubleValue() <= 0.0D; 
  149.  
  150. return flag; 
  151.  
  152. private boolean isLastNegativeItem(CategoryDataset categorydataset, int i, int j)
  153. boolean flag = true
  154. Number number = categorydataset.getValue(i, j); 
  155. if (number == null
  156. return false
  157. for (int k = i + 1; k < categorydataset.getRowCount(); k++) { 
  158. Number number1 = categorydataset.getValue(k, j); 
  159. if (number1 != null
  160. flag = flag && number1.doubleValue() >= 0.0D; 
  161.  
  162. return flag; 
  163.  
  164. private double calculateSumOfPositiveValuesForCategory(CategoryDataset categorydataset, int i)
  165. double d = 0.0D; 
  166. for (int j = 0; j < categorydataset.getRowCount(); j++) { 
  167. Number number = categorydataset.getValue(j, i); 
  168. if (number == null
  169. continue
  170. double d1 = number.doubleValue(); 
  171. if (d1 > 0.0D) 
  172. d += d1; 
  173.  
  174. return d; 
  175.  
  176. private double calculateSumOfNegativeValuesForCategory(CategoryDataset categorydataset, int i)
  177. double d = 0.0D; 
  178. for (int j = 0; j < categorydataset.getRowCount(); j++) { 
  179. Number number = categorydataset.getValue(j, i); 
  180. if (number == null
  181. continue
  182. double d1 = number.doubleValue(); 
  183. if (d1 < 0.0D) 
  184. d += d1; 
  185.  
  186. return d; 
  187.  
  188.  

ExtendedStandardCategoryItemLabelGeneratory

  1. package com.springapp.jfreechar; 
  2.  
  3. import org.jfree.chart.HashUtilities; 
  4. import org.jfree.chart.labels.AbstractCategoryItemLabelGenerator; 
  5. import org.jfree.chart.labels.StandardCategoryItemLabelGenerator; 
  6. import org.jfree.data.DataUtilities; 
  7. import org.jfree.data.category.CategoryDataset; 
  8. import org.jfree.util.ObjectUtilities; 
  9. import org.jfree.util.PublicCloneable; 
  10.  
  11. import java.io.Serializable; 
  12. import java.text.DateFormat; 
  13. import java.text.MessageFormat; 
  14. import java.text.NumberFormat; 
  15.  
  16. public class ExtendedStandardCategoryItemLabelGeneratory extends StandardCategoryItemLabelGenerator implements PublicCloneable, Cloneable, Serializable
  17.  
  18. private static final long serialVersionUID = -7108591260223293197L
  19. private String labelFormat; 
  20. private String nullValueString; 
  21. private NumberFormat numberFormat; 
  22. private DateFormat dateFormat; 
  23. private NumberFormat percentFormat; 
  24. //新增加了参数,柱体series的值是否是总值的百分比,还是仅仅将原来的小数转化为百分数 
  25. private boolean isPercent = false
  26.  
  27. public ExtendedStandardCategoryItemLabelGeneratory(String labelFormat, NumberFormat formatter, NumberFormat percentFormatter,boolean isPercent)
  28. super(labelFormat, formatter, percentFormatter); 
  29. if(labelFormat == null) { 
  30. throw new IllegalArgumentException("Null \'labelFormat\' argument."); 
  31. } else if(formatter == null)
  32. throw new IllegalArgumentException("Null \'formatter\' argument."); 
  33. } else if(percentFormatter == null)
  34. throw new IllegalArgumentException("Null \'percentFormatter\' argument."); 
  35. } else
  36. this.labelFormat = labelFormat; 
  37. this.numberFormat = formatter; 
  38. this.percentFormat = percentFormatter; 
  39. this.dateFormat = null
  40. this.nullValueString = "-"
  41. if (isPercent) 
  42. this.isPercent = isPercent; 
  43.  
  44.  
  45. @Override 
  46. protected String generateLabelString(CategoryDataset dataset, int row, int column)
  47. if(dataset == null) { 
  48. throw new IllegalArgumentException("Null \'dataset\' argument."); 
  49. } else
  50. String result = null
  51. Object[] items = this.createItemArray(dataset, row, column); 
  52. result = MessageFormat.format(this.labelFormat, items); 
  53. return result; 
  54. @Override 
  55. protected Object[] createItemArray(CategoryDataset dataset, int row, int column) { 
  56. Object[] result = new Object[]{dataset.getRowKey(row).toString(), dataset.getColumnKey(column).toString(), null, null}; 
  57. Number value = dataset.getValue(row, column); 
  58. if(value != null) { 
  59. if(this.numberFormat != null) { 
  60. result[2] = this.numberFormat.format(value); 
  61. } else if(this.dateFormat != null)
  62. result[2] = this.dateFormat.format(value); 
  63. } else
  64. result[2] = this.nullValueString; 
  65.  
  66. if(value != null) { 
  67. double total = DataUtilities.calculateColumnTotal(dataset, column); 
  68. // 
  69. double percent = 0D;// / total; 
  70. if (this.isPercent) 
  71. //StandardCategoryItemLabelGenerator 返回的值是百分比 
  72. percent = value.doubleValue() / total; 
  73. else 
  74. //返回自己原来的值 
  75. percent = value.doubleValue(); 
  76. //格式化 
  77. result[3] = this.percentFormat.format(percent); 
  78.  
  79. return result; 
  80.  
  81.  
  82.  

StackedBarChartDemo3

  1. package com.springapp.jfreechar; 
  2.  
  3. import java.awt.*; 
  4. import java.text.DecimalFormat; 
  5. import java.text.NumberFormat; 
  6. import java.util.Iterator; 
  7.  
  8. import javax.swing.*; 
  9.  
  10. import com.sun.javafx.charts.Legend; 
  11. import org.jfree.chart.*; 
  12. import org.jfree.chart.axis.*; 
  13. import org.jfree.chart.labels.*; 
  14. import org.jfree.chart.plot.CategoryPlot; 
  15. import org.jfree.chart.plot.PlotOrientation; 
  16. import org.jfree.chart.title.LegendTitle; 
  17. import org.jfree.data.category.CategoryDataset; 
  18. import org.jfree.data.category.DefaultCategoryDataset; 
  19. import org.jfree.ui.ApplicationFrame; 
  20. import org.jfree.ui.RectangleEdge; 
  21. import org.jfree.ui.RefineryUtilities; 
  22. import org.jfree.ui.TextAnchor; 
  23.  
  24. // Referenced classes of package demo: 
  25. // ExtendedStackedBarRenderer 
  26.  
  27. public class StackedBarChartDemo3 extends ApplicationFrame
  28.  
  29. private static final long serialVersionUID = 1L
  30.  
  31. public StackedBarChartDemo3(String s)
  32. super(s); 
  33. JPanel jpanel = createDemoPanel(); 
  34. jpanel.setPreferredSize(new Dimension(500, 270)); 
  35. setContentPane(jpanel); 
  36.  
  37. private static CategoryDataset createDataset()
  38. DefaultCategoryDataset defaultcategorydataset = new DefaultCategoryDataset(); 
  39. defaultcategorydataset.addValue(.101D, "Series 1", "Cross Contamination (4.3)"); 
  40. defaultcategorydataset.addValue(.4D, "Series 2", "Cross Contamination (4.3)"); 
  41. return defaultcategorydataset; 
  42.  
  43. private static JFreeChart createChart(CategoryDataset categorydataset)
  44.  
  45. JFreeChart jfreechart = ChartFactory.createStackedBarChart("Stacked Bar Chart Demo 3", "Category", "Value", categorydataset, PlotOrientation.VERTICAL, true, true, false); 
  46.  
  47. CategoryPlot categoryplot = (CategoryPlot) jfreechart.getPlot(); 
  48. //柱体 
  49. ExtendedStackedBarRenderer extendedstackedbarrenderer = new ExtendedStackedBarRenderer(new DecimalFormat("#0.0%")); 
  50. //柱体标签是否可见 
  51. extendedstackedbarrenderer.setBaseItemLabelsVisible(true); 
  52. Font labelFont = new Font("Arial", Font.PLAIN, 12); 
  53. extendedstackedbarrenderer.setBaseItemLabelPaint(new GradientPaint(0.0f, 0.0f, new Color(255, 255, 255), 0.0f, 0.0f, new Color(0, 0, 0))); 
  54. //设置柱体标签值的格式 
  55. ExtendedStandardCategoryItemLabelGeneratory generator = new ExtendedStandardCategoryItemLabelGeneratory("{3}"
  56. NumberFormat.getPercentInstance(), new DecimalFormat("#0.0%"),false); 
  57. extendedstackedbarrenderer.setBaseItemLabelGenerator(generator); 
  58. //自定义柱体颜色 
  59. Paint p0 = new GradientPaint(0.0f, 0.0f, new Color(237, 125, 49), 0.0f, 0.0f, new Color(237, 125, 49)); 
  60. extendedstackedbarrenderer.setSeriesPaint(0, p0); 
  61. Paint p1 = new GradientPaint(0.0f, 0.0f, new Color(91, 155, 213), 0.0f, 0.0f, new Color(91, 155, 213)); 
  62. extendedstackedbarrenderer.setSeriesPaint(1, p1); 
  63.  
  64. categoryplot.setRenderer(extendedstackedbarrenderer); 
  65.  
  66. //Y 轴 
  67. NumberAxis numberaxis = (NumberAxis) categoryplot.getRangeAxis(); 
  68. //不设置是自动显示步长 
  69. numberaxis.setTickUnit(new NumberTickUnit(0.05)); 
  70. numberaxis.setLowerMargin(0.14999999999999999D); 
  71. numberaxis.setUpperMargin(0.14999999999999999D); 
  72. //设置是否是百分率 
  73. numberaxis.setNumberFormatOverride(NumberFormat.getPercentInstance()); 
  74.  
  75. //X 辆 
  76. CategoryAxis categoryAxis = categoryplot.getDomainAxis(); 
  77. //x轴旋转 
  78. categoryAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 6.0)); 
  79.  
  80. //标注 
  81. LegendTitle legendtitle = (LegendTitle)jfreechart.getLegend(); 
  82. legendtitle.setBorder(0, 0, 0, 0); 
  83. return jfreechart; 
  84.  
  85. public static JPanel createDemoPanel()
  86. JFreeChart jfreechart = createChart(createDataset()); 
  87. return new ChartPanel(jfreechart); 
  88.  
  89. public static void main(String args[])
  90. StackedBarChartDemo3 stackedbarchartdemo3 = new StackedBarChartDemo3("Stacked Bar Chart Demo 3"); 
  91. stackedbarchartdemo3.pack(); 
  92. RefineryUtilities.centerFrameOnScreen(stackedbarchartdemo3); 
  93. stackedbarchartdemo3.setVisible(true); 
  94.  
  95.  

你可能感兴趣的:(JFreeChart之堆叠柱形图(StackedBar))