Jasper reports 我们能在组堆叠条形图上画一个折线图吗

Jasper reports 我们能在组堆叠条形图上画一个折线图吗,jasper-reports,jfreechart,Jasper Reports,Jfreechart,我正在尝试创建一个GroupedStackBar图表,显示每个客户在过去三个月内每种产品的收入,并添加一个或多个折线图,描述在每个期间与客户进行的会议。我正在使用JasperReports创建一个PDF报告,使用常用的图表定制器来准备它 下面的快照推测了我试图创建的图表: 该报告需要描述每个客户的月度收入和会议情况。如中所示,Client1为Xmn提供了收入,并在11月召开了M会议,Ymn在收入上,在12月召开了N会议,依此类推 因此,我的X轴有两个分组——客户和上一季度的月份。此外,收入与产

我正在尝试创建一个
GroupedStackBar
图表,显示每个客户在过去三个月内每种产品的收入,并添加一个或多个折线图,描述在每个期间与客户进行的会议。我正在使用JasperReports创建一个PDF报告,使用常用的图表定制器来准备它

下面的快照推测了我试图创建的图表:

该报告需要描述每个客户的月度收入和会议情况。如中所示,
Client1
X
mn提供了收入,并在11月召开了
M
会议,
Y
mn在收入上,在12月召开了
N
会议,依此类推

因此,我的X轴有两个分组——客户和上一季度的月份。此外,收入与产品的比例进一步增加。所以,我有点合并了两个不同的数据集——每个客户的收入指标、月份、每个客户的产品与会议指标、月份来构建图表

我为生成图表而创建的示例程序:

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);
    }
}
上述程序的输出未按要求显示图表。相反,折线图显示了2013年1月与
Client1的
P
会议、2013年1月与
Client2的
Q
会议、2013年1月与
Client3的
R
会议和2013年2月与
Client2的
X
会议、2013年2月与
Client2的
Y
会议等等。。也就是说,不尊重客户机的分组。我尝试在折线图数据集中改变行键/列键,但没有结果

你能告诉我如何正确地得到折线图吗


谢谢。

我的第一个想法是实现一个定制的渲染器-一个由GroupStackedBlunderer和LineandShappenderer混合而成的渲染器-但是下面的伪分组更容易;)

因此,我用StackeBarRender替换了GroupedStackedBlanderer,并在组之间插入了一个虚拟列。 客户端的分组类别标签由第二个域轴归档- 幸运的是,无论使用多少个客户机/组,第二类轴的标签都集中在第一类轴的组中

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);
    }
}
导入java.awt.Graphics2D;
导入org.apache.commons.beanutils.PropertyUtilsBean;
导入org.jfree.chart.ChartFactory;
导入org.jfree.chart.ChartPanel;
导入org.jfree.chart.JFreeChart;
导入org.jfree.chart.axis.AxisLocation;
导入org.jfree.chart.axis.CategoryAxis;
导入org.jfree.chart.axis.NumberAxis;
导入org.jfree.chart.axis.ValueAxis;
导入org.jfree.chart.plot.CategoryPlot;
导入org.jfree.chart.plot.PlotOrientation;
导入org.jfree.chart.renderer.category.stackedblunderer;
导入org.jfree.data.category.CategoryDataset;
导入org.jfree.data.category.DefaultCategoryDataset;
导入org.jfree.text.g2textmasurer;
导入org.jfree.text.TextBlock;
导入org.jfree.text.TextUtilities;
导入org.jfree.ui.ApplicationFrame;
导入org.jfree.ui.RectangleEdge;
导入org.jfree.ui.RefineryUtilities;
公共类GroupedStackedBarLineChart扩展了ApplicationFrame{
public GroupedStackedBarLineChart(最终字符串标题){
超级(标题);
//最终JFreeChart图表=构造巴罗弗林查特();
最终JFreeChart图表=constructLineOverBarChart();
最终图表面板=新图表面板(图表);
设置内容窗格(面板);
}
私有JFreeChart constructLineOverBarChart()函数{
最终JFreeChart图表=ChartFactory.createLineChart(
“堆叠分组条形图”,“”,
“会议/月”,fetchMeetingDataSet(),
PlotOrientation.VERTICAL,true,true,false);
最终StackedBlunderer渲染器=新StackedBlunderer();
setItemMargin(0.076);
final CategoryPlot cp=chart.getCategoryPlot();
cp.setDataset(1,fetchRevenueDataSet());
最终价值轴收入轴=新数字轴(“收入”);
cp.setRangeAxis(1,revenueAxis);
cp.setRenderer(1,renderer);
分类标号(cp);
插入法分组(cp);
CategoryAxis ca=新的CategoryAxis(“产品/月份”);
cp.setDomainAxis(1,ca);
cp.setDataset(2,另一个DataSet());
cp.mapdatasetodomainaxis(2,1);
cp.setDomainAxisLocation(1,AxisLocation.BOTTOM_或_LEFT);
ca.setAxisLineVisible(假);
ca.setTickMarksVisible(假);
收益表;
}
私有void insertFakeGrouping(CategoryPlot cp){
for(int i=0;i rowKey=cd.getRowKey(row);
可比columnKey=cd.getColumnKey(col);
dcd.addValue(cd.getValue(rowKey,columnKey),rowKey,columnKey);
}
}
cp.setDataset(i,dcd);
}
}
私有无效印章类别标签(类别地块cp){
CategoryAxis caOld=cp.getDomainAxis();
CategoryAxis caNew=新的CategoryAxis(){
受保护的TextBlock createLabel(可比类别、浮动宽度、,
矩形边缘,图形2D(g2){
字符串cat=category.toString();
cat=(cat.contains(“”))
?类别子字符串(0,类别索引of(“”“))
: "";
TextBlock label=TextUtilities.createTextBlock(cat,
getTickLabelFont(类别)、getTickLabelPaint(类别)、宽度、,
getMaximumCategoryLabelLines(),新的G2TextMeasurer(g2));
退货标签;
}           
};
试一试{
新属性YutilsBean().copyProperties(caNew、caOld);
cp.setDomainAxis(0,caNew);
}捕获(例外e){
抛出新的RuntimeException(“不是真的?”,e);
}
}
private CategoryDataset anotherDataSet(){
最终DefaultCategoryDataset ds=新的DefaultCategoryDataset();
ds.addValue(1,“1