2013-02-22 74 views
4

我正在嘗試創建一個GroupedStackBar圖表,其中顯示了每個客戶在過去三個月對每種產品的收入,並添加了描繪與客戶在每個時間段內完成的會議的折線圖。我正在使用JasperReports創建一個PDF報告,使用通常的圖表定製工具來準備它。我們可以通過GroupedStackedBarChart繪製折線圖

下面的快照猜測我試圖創建圖表:

chart image

該報告需要描繪每個客戶的月收入和會議。正如,表明Client1收入提供了X Mn和曾在十一月M會議,Y百萬的收入和12月N會議等..

所以,我的X軸有兩個集團 - 客戶和月(s)在最後一個季度。此外,收入還與產品進行了堆疊。因此,我有點合併了兩個不同的數據集 - 每個客戶的收入度量,幾個月,每個客戶的產品與會議的度量值,月份來構建圖表。

,我會用於產生圖表創建的示例程序:

import org.jfree.chart.ChartFactory; 
import org.jfree.chart.ChartPanel; 
import org.jfree.chart.JFreeChart; 
import org.jfree.chart.axis.AxisLocation; 
import org.jfree.chart.axis.NumberAxis; 
import org.jfree.chart.axis.SubCategoryAxis; 
import org.jfree.chart.axis.ValueAxis; 
import org.jfree.chart.plot.CategoryPlot; 
import org.jfree.chart.plot.PlotOrientation; 
import org.jfree.chart.renderer.category.GroupedStackedBarRenderer; 
import org.jfree.chart.renderer.category.LineAndShapeRenderer; 
import org.jfree.data.KeyToGroupMap; 
import org.jfree.data.category.CategoryDataset; 
import org.jfree.data.category.DefaultCategoryDataset; 
import org.jfree.ui.ApplicationFrame; 
import org.jfree.ui.RefineryUtilities; 

public class GroupedStackedBarLineChart extends ApplicationFrame { 

    public GroupedStackedBarLineChart(final String title) { 
     super(title); 
     // final JFreeChart chart = constructBarOverLineChart(); 
     final JFreeChart chart = constructLineOverBarChart(); 
     final ChartPanel panel = new ChartPanel(chart); 
     setContentPane(panel); 
    } 

    private JFreeChart constructLineOverBarChart() { 
     final JFreeChart chart = ChartFactory.createLineChart(
       "Stacked Grouped Bar Line Chart", "Products/Month", 
       "Meetings/Month", fetchMeetingDataSet(), 
       PlotOrientation.VERTICAL, true, true, false); 


     final KeyToGroupMap map = new KeyToGroupMap("Jan13"); 
     map.mapKeyToGroup("Jan13 (Product1)", "Jan13"); 
     map.mapKeyToGroup("Jan13 (Product2)", "Jan13"); 
     map.mapKeyToGroup("Jan13 (Product3)", "Jan13"); 

     map.mapKeyToGroup("Feb13 (Product1)", "Feb13"); 
     map.mapKeyToGroup("Feb13 (Product2)", "Feb13"); 
     map.mapKeyToGroup("Feb13 (Product3)", "Feb13"); 

     map.mapKeyToGroup("Mar13 (Product1)", "Mar13"); 
     map.mapKeyToGroup("Mar13 (Product2)", "Mar13"); 
     map.mapKeyToGroup("Mar13 (Product3)", "Mar13"); 

     final GroupedStackedBarRenderer renderer = new GroupedStackedBarRenderer(); 
     renderer.setSeriesToGroupMap(map); 
     renderer.setItemMargin(0.076); 

     final SubCategoryAxis domainAxis = new SubCategoryAxis("Products/Month"); 
     domainAxis.addSubCategory("Jan13"); 
     domainAxis.addSubCategory("Feb13"); 
     domainAxis.addSubCategory("Mar13"); 

     domainAxis.setCategoryMargin(0.28); 

     final CategoryPlot subPlot1 = (CategoryPlot) chart.getPlot(); 
     subPlot1.setDataset(1, fetchRevenueDataSet()); 
     subPlot1.setDomainAxis(domainAxis); 
     final ValueAxis revenueAxis = new NumberAxis("Revenue"); 
     subPlot1.setRangeAxis(1, revenueAxis); 
     subPlot1.setRenderer(1, renderer); 

     return chart; 
    } 

    private JFreeChart constructBarOverLineChart() { 
     final JFreeChart chart = ChartFactory.createStackedBarChart(
       "Stacked Grouped Bar Line Chart", "Clients", "Revenue", 
       fetchRevenueDataSet(), PlotOrientation.VERTICAL, true, true, 
       false); 

     final KeyToGroupMap map = new KeyToGroupMap("Jan13"); 
     map.mapKeyToGroup("Jan13 (Product1)", "Jan13"); 
     map.mapKeyToGroup("Jan13 (Product2)", "Jan13"); 
     map.mapKeyToGroup("Jan13 (Product3)", "Jan13"); 

     map.mapKeyToGroup("Feb13 (Product1)", "Feb13"); 
     map.mapKeyToGroup("Feb13 (Product2)", "Feb13"); 
     map.mapKeyToGroup("Feb13 (Product3)", "Feb13"); 

     map.mapKeyToGroup("Mar13 (Product1)", "Mar13"); 
     map.mapKeyToGroup("Mar13 (Product2)", "Mar13"); 
     map.mapKeyToGroup("Mar13 (Product3)", "Mar13"); 

     final GroupedStackedBarRenderer renderer = new GroupedStackedBarRenderer(); 
     renderer.setSeriesToGroupMap(map); 
     renderer.setItemMargin(0.076); 

     final SubCategoryAxis domainAxis = new SubCategoryAxis("Products/Month"); 
     domainAxis.addSubCategory("Jan13"); 
     domainAxis.addSubCategory("Feb13"); 
     domainAxis.addSubCategory("Mar13"); 

     domainAxis.setCategoryMargin(0.28); 

     final CategoryPlot subPlot1 = (CategoryPlot) chart.getPlot(); 
     subPlot1.setDomainAxis(domainAxis); 
     subPlot1.setRenderer(renderer); 

     final ValueAxis meetingAxis = new NumberAxis("Meetings"); 
     subPlot1.setDataset(1, fetchMeetingDataSet()); 
     // subPlot1.mapDatasetToDomainAxis(1, 1); 
     subPlot1.setRangeAxis(1, meetingAxis); 
     subPlot1.setRangeAxisLocation(0, AxisLocation.BOTTOM_OR_LEFT); 
     subPlot1.setRangeAxisLocation(1, AxisLocation.TOP_OR_RIGHT); 
     subPlot1.setRenderer(1, new LineAndShapeRenderer(true, false)); 


     return chart; 
    } 

    private CategoryDataset fetchRevenueDataSet() { 

     final DefaultCategoryDataset revenueDataSet = new DefaultCategoryDataset(); 

     revenueDataSet.addValue(20.3, "Jan13 (Product1)", "Client1"); 
     revenueDataSet.addValue(27.2, "Jan13 (Product2)", "Client1"); 
     revenueDataSet.addValue(19.7, "Jan13 (Product3)", "Client1"); 

     revenueDataSet.addValue(19.4, "Feb13 (Product1)", "Client1"); 
     revenueDataSet.addValue(10.9, "Feb13 (Product2)", "Client1"); 
     revenueDataSet.addValue(18.4, "Feb13 (Product3)", "Client1"); 

     revenueDataSet.addValue(16.5, "Mar13 (Product1)", "Client1"); 
     revenueDataSet.addValue(15.9, "Mar13 (Product2)", "Client1"); 
     revenueDataSet.addValue(16.1, "Mar13 (Product3)", "Client1"); 

     revenueDataSet.addValue(23.3, "Jan13 (Product1)", "Client2"); 
     revenueDataSet.addValue(16.2, "Jan13 (Product2)", "Client2"); 
     revenueDataSet.addValue(28.7, "Jan13 (Product3)", "Client2"); 

     revenueDataSet.addValue(12.7, "Feb13 (Product1)", "Client2"); 
     revenueDataSet.addValue(17.9, "Feb13 (Product2)", "Client2"); 
     revenueDataSet.addValue(12.6, "Feb13 (Product3)", "Client2"); 

     revenueDataSet.addValue(15.4, "Mar13 (Product1)", "Client2"); 
     revenueDataSet.addValue(21.0, "Mar13 (Product2)", "Client2"); 
     revenueDataSet.addValue(11.1, "Mar13 (Product3)", "Client2"); 

     revenueDataSet.addValue(23.8, "Jan13 (Product1)", "Client3"); 
     revenueDataSet.addValue(23.4, "Jan13 (Product2)", "Client3"); 
     revenueDataSet.addValue(19.3, "Jan13 (Product3)", "Client3"); 

     revenueDataSet.addValue(11.9, "Feb13 (Product1)", "Client3"); 
     revenueDataSet.addValue(31.0, "Feb13 (Product2)", "Client3"); 
     revenueDataSet.addValue(22.7, "Feb13 (Product3)", "Client3"); 

     revenueDataSet.addValue(15.3, "Mar13 (Product1)", "Client3"); 
     revenueDataSet.addValue(14.4, "Mar13 (Product2)", "Client3"); 
     revenueDataSet.addValue(25.3, "Mar13 (Product3)", "Client3"); 

     return revenueDataSet; 
    } 

    private CategoryDataset fetchMeetingDataSet() { 
     final DefaultCategoryDataset meetingDataSet = new DefaultCategoryDataset(); 

     meetingDataSet.addValue(20, "Jan13", "Client1"); 
     meetingDataSet.addValue(8, "Feb13", "Client1"); 
     meetingDataSet.addValue(35, "Mar13", "Client1"); 

     meetingDataSet.addValue(7, "Jan13", "Client2"); 
     meetingDataSet.addValue(20, "Feb13", "Client2"); 
     meetingDataSet.addValue(12, "Mar13", "Client2"); 

     meetingDataSet.addValue(25, "Jan13", "Client3"); 
     meetingDataSet.addValue(17, "Feb13", "Client3"); 
     meetingDataSet.addValue(7, "Mar13", "Client3"); 

     return meetingDataSet; 
    } 

    public static void main(String[] args) { 
     GroupedStackedBarLineChart demo = new GroupedStackedBarLineChart(
       "Client Revenue and Meetings"); 
     demo.pack(); 
     RefineryUtilities.centerFrameOnScreen(demo); 
     demo.setVisible(true); 
    } 
} 

上述程序的輸出不顯示圖表作爲是必需的。相反,線圖表顯示JAN13Client1Client2Client2P會議,QClient2會議,JAN13RClient3會議,JAN13X會議Feb13,爲Y會議Feb13等等。也就是說,對於客戶端的分組是不被尊重的。我嘗試改變折線圖數據集中的row-key/column-key而沒有收益率。

請您指點一下,以正確獲取折線圖?

謝謝。

+0

我無法上傳一個簡單的jpg顯示圖表 - 我正在開發的圖表,因爲我沒有10個信譽點:( – saiyyer 2013-02-22 13:33:32

+0

也許引用[示例](http://www.jfree.org/jfreechart /samples.html),按名稱,發佈圖片鏈接,或者編輯你的問題以包含[sscce](http://sscce.org/) – trashgod 2013-02-22 20:02:02

+0

你可以用Ireport創建一個多軸圖表,我有這個類似的要求 – Sharad 2013-02-23 03:36:35

回答

2

我首先想到的是要實現自定義渲染器 - 出GroupStackedBarRenderer和LineAndShapeRenderer的混合物 - 但下面的僞分組是比較容易;)

所以我把它換成了GroupedStackedBarRenderer用StackeBarRenderer並插入一個虛擬列之間的組。 客戶的分組類別標籤由第二個域軸完成 - 幸運的是,無論使用多少個客戶端/組,第二個類別軸的標籤都集中在第一個軸的組中...

import java.awt.Graphics2D; 
import org.apache.commons.beanutils.PropertyUtilsBean; 
import org.jfree.chart.ChartFactory; 
import org.jfree.chart.ChartPanel; 
import org.jfree.chart.JFreeChart; 
import org.jfree.chart.axis.AxisLocation; 
import org.jfree.chart.axis.CategoryAxis; 
import org.jfree.chart.axis.NumberAxis; 
import org.jfree.chart.axis.ValueAxis; 
import org.jfree.chart.plot.CategoryPlot; 
import org.jfree.chart.plot.PlotOrientation; 
import org.jfree.chart.renderer.category.StackedBarRenderer; 
import org.jfree.data.category.CategoryDataset; 
import org.jfree.data.category.DefaultCategoryDataset; 
import org.jfree.text.G2TextMeasurer; 
import org.jfree.text.TextBlock; 
import org.jfree.text.TextUtilities; 
import org.jfree.ui.ApplicationFrame; 
import org.jfree.ui.RectangleEdge; 
import org.jfree.ui.RefineryUtilities; 

public class GroupedStackedBarLineChart extends ApplicationFrame { 

    public GroupedStackedBarLineChart(final String title) { 
     super(title); 
     // final JFreeChart chart = constructBarOverLineChart(); 
     final JFreeChart chart = constructLineOverBarChart(); 
     final ChartPanel panel = new ChartPanel(chart); 
     setContentPane(panel); 
    } 

    private JFreeChart constructLineOverBarChart() { 
     final JFreeChart chart = ChartFactory.createLineChart(
       "Stacked Grouped Bar Line Chart", "", 
       "Meetings/Month", fetchMeetingDataSet(), 
       PlotOrientation.VERTICAL, true, true, false); 
     final StackedBarRenderer renderer = new StackedBarRenderer(); 
     renderer.setItemMargin(0.076); 

     final CategoryPlot cp = chart.getCategoryPlot(); 
     cp.setDataset(1, fetchRevenueDataSet()); 
     final ValueAxis revenueAxis = new NumberAxis("Revenue"); 
     cp.setRangeAxis(1, revenueAxis); 
     cp.setRenderer(1, renderer); 

     chopCategoryLabels(cp); 
     insertFakeGrouping(cp); 

     CategoryAxis ca = new CategoryAxis("Products/Month"); 
     cp.setDomainAxis(1, ca); 
     cp.setDataset(2, anotherDataSet()); 
     cp.mapDatasetToDomainAxis(2, 1); 
     cp.setDomainAxisLocation(1, AxisLocation.BOTTOM_OR_LEFT); 
     ca.setAxisLineVisible(false); 
     ca.setTickMarksVisible(false); 


     return chart; 
    } 

    private void insertFakeGrouping(CategoryPlot cp) { 
     for (int i=0; i<cp.getDatasetCount(); i++) { 
      assert(cp.getDataset(i) instanceof DefaultCategoryDataset); 
      CategoryDataset cd = cp.getDataset(i); 
      Comparable<?> firstRow = cd.getRowKey(0); 

      DefaultCategoryDataset dcd = new DefaultCategoryDataset(); 
      for (int col=0; col<cd.getColumnCount(); col++) { 
       if (col > 0) { 
        String c1 = cd.getColumnKey(col-1).toString(); 
        c1 = c1.substring(c1.indexOf('_')); 
        String c2 = cd.getColumnKey(col).toString(); 
        c2 = c2.substring(c2.indexOf('_')); 
        if (!c1.equals(c2)) { 
         dcd.addValue(null, firstRow, "dummy"+col); 
        } 
       } 
       for (int row=0; row<cd.getRowCount(); row++) { 
        Comparable<?> rowKey = cd.getRowKey(row); 
        Comparable<?> columnKey = cd.getColumnKey(col); 
        dcd.addValue(cd.getValue(rowKey, columnKey), rowKey, columnKey); 
       } 
      } 

      cp.setDataset(i, dcd); 
     } 
    } 


    private void chopCategoryLabels(CategoryPlot cp) { 
     CategoryAxis caOld = cp.getDomainAxis(); 
     CategoryAxis caNew = new CategoryAxis(){ 
      protected TextBlock createLabel(Comparable category, float width, 
       RectangleEdge edge, Graphics2D g2) { 
       String cat = category.toString(); 
       cat = (cat.contains("_")) 
        ? cat.substring(0, cat.indexOf('_')) 
        : ""; 
       TextBlock label = TextUtilities.createTextBlock(cat, 
       getTickLabelFont(category), getTickLabelPaint(category), width, 
       getMaximumCategoryLabelLines(), new G2TextMeasurer(g2)); 
       return label; 
      }   
     }; 

     try { 
      new PropertyUtilsBean().copyProperties(caNew, caOld); 
      cp.setDomainAxis(0, caNew); 
     } catch (Exception e) { 
      throw new RuntimeException("not really?", e); 
     } 
    } 

    private CategoryDataset anotherDataSet() { 
     final DefaultCategoryDataset ds = new DefaultCategoryDataset(); 
     ds.addValue(1, "1", "Client 1"); 
     ds.addValue(1, "2", "Client 2"); 
     ds.addValue(1, "3", "Client 3"); 
     return ds; 
    } 

    private CategoryDataset fetchRevenueDataSet() { 

     final DefaultCategoryDataset revenueDataSet = new DefaultCategoryDataset(); 

     revenueDataSet.addValue(20.3, "Product 1", "Jan13_1"); 
     revenueDataSet.addValue(27.2, "Product 2", "Jan13_1"); 
     revenueDataSet.addValue(19.7, "Product 3", "Jan13_1"); 

     revenueDataSet.addValue(19.4, "Product 1", "Feb13_1"); 
     revenueDataSet.addValue(10.9, "Product 2", "Feb13_1"); 
     revenueDataSet.addValue(18.4, "Product 3", "Feb13_1"); 

     revenueDataSet.addValue(16.5, "Product 1", "Mar13_1"); 
     revenueDataSet.addValue(15.9, "Product 2", "Mar13_1"); 
     revenueDataSet.addValue(16.1, "Product 3", "Mar13_1"); 

     revenueDataSet.addValue(23.3, "Product 1", "Jan13_2"); 
     revenueDataSet.addValue(16.2, "Product 2", "Jan13_2"); 
     revenueDataSet.addValue(28.7, "Product 3", "Jan13_2"); 

     revenueDataSet.addValue(12.7, "Product 1", "Feb13_2"); 
     revenueDataSet.addValue(17.9, "Product 2", "Feb13_2"); 
     revenueDataSet.addValue(12.6, "Product 3", "Feb13_2"); 

     revenueDataSet.addValue(15.4, "Product 1", "Mar13_2"); 
     revenueDataSet.addValue(21.0, "Product 2", "Mar13_2"); 
     revenueDataSet.addValue(11.1, "Product 3", "Mar13_2"); 

     revenueDataSet.addValue(23.8, "Product 1", "Jan13_3"); 
     revenueDataSet.addValue(23.4, "Product 2", "Jan13_3"); 
     revenueDataSet.addValue(19.3, "Product 3", "Jan13_3"); 

     revenueDataSet.addValue(11.9, "Product 1", "Feb13_3"); 
     revenueDataSet.addValue(31.0, "Product 2", "Feb13_3"); 
     revenueDataSet.addValue(22.7, "Product 3", "Feb13_3"); 

     revenueDataSet.addValue(15.3, "Product 1", "Mar13_3"); 
     revenueDataSet.addValue(14.4, "Product 2", "Mar13_3"); 
     revenueDataSet.addValue(25.3, "Product 3", "Mar13_3"); 

     return revenueDataSet; 
    } 

    private CategoryDataset fetchMeetingDataSet() { 
     final DefaultCategoryDataset meetingDataSet = new DefaultCategoryDataset(); 

     meetingDataSet.addValue(20, "Meetings", "Jan13_1"); 
     meetingDataSet.addValue(8, "Meetings", "Feb13_1"); 
     meetingDataSet.addValue(35, "Meetings", "Mar13_1"); 

     meetingDataSet.addValue(7, "Meetings", "Jan13_2"); 
     meetingDataSet.addValue(20, "Meetings", "Feb13_2"); 
     meetingDataSet.addValue(12, "Meetings", "Mar13_2"); 

     meetingDataSet.addValue(25, "Meetings", "Jan13_3"); 
     meetingDataSet.addValue(17, "Meetings", "Feb13_3"); 
     meetingDataSet.addValue(7, "Meetings", "Mar13_3"); 

     return meetingDataSet; 
    } 

    public static void main(String[] args) { 
     GroupedStackedBarLineChart demo = new GroupedStackedBarLineChart(
       "Client Revenue and Meetings"); 
     demo.pack(); 
     RefineryUtilities.centerFrameOnScreen(demo); 
     demo.setVisible(true); 
    } 
} 
+0

嗯,我們重新審視了我們的報告設計並調整了一下以適應Jasper的報告。但@kiwiwings,你的黑客完美的作品。非常感謝您的解決方案。 – saiyyer 2013-04-25 17:21:12