Search code examples
bar-chartdocx4j

Editing charts in a docx file using docx4j


I'm trying to edit charts in a docx file using docx4j. I can't seem to increase the number of rows (as in, the number of bars in a bar chart) in the chart. I can decrease the number of rows, that works fine. When I try to increase the number of rows, the values in the variables are changed correctly (ctNumvals and ctStrVals in the code). But when I open the edited doc, the chart only shows the original number of rows (before editing), with the last sets of data I entered.

Here is the code:

WordprocessingMLPackage template = WordprocessingMLPackage.load(new File(resultFile));

        Chart chart = (Chart) template.getParts().get(new PartName(chartPartName));
        List<Object> objects = chart.getJaxbElement().getChart().getPlotArea()
                .getAreaChartOrArea3DChartOrLineChart();

        //update chart values in doc

        for (Object object : objects) {

            if (object instanceof CTBarChart) {

                List<CTBarSer> ctBarSers = ((CTBarChart) object).getSer();

                for (CTBarSer ctBarSer : ctBarSers) {

                    List<CTNumVal> ctNumVals = ctBarSer.getVal().getNumRef().getNumCache().getPt();
                    List<CTStrVal> ctStrVals = ctBarSer.getCat().getStrRef().getStrCache().getPt();

                    while (data.size() < ctNumVals.size()) {
                        ctNumVals.remove(data.size());
                    }

                    while (data.size() < ctStrVals.size()) {
                        ctStrVals.remove(data.size());
                    }

                    while (data.size() > ctNumVals.size()) {
                        CTNumVal numVal = new CTNumVal();
                        ctNumVals.add(ctNumVals.size(), numVal);
                    }

                    while (data.size() > ctStrVals.size()) {
                        CTStrVal strVal = new CTStrVal();
                        ctStrVals.add(ctStrVals.size(), strVal);
                    }

                    ctBarSer.getVal().getNumRef().getNumCache().getPtCount().setVal(data.size());
                    ctBarSer.getCat().getStrRef().getStrCache().getPtCount().setVal(data.size());

                    for (CTNumVal ctNumVal : ctNumVals) {
                        ctNumVal.setV(valItr.next());
                    }

                    for (CTStrVal ctStrVal : ctStrVals) {
                        ctStrVal.setV(keyItr.next());
                    }
                }
            }
        }
        template.save(new File(resultFile));

The variable 'data' is a LinkedHashMap


Solution

  • I have found out what I am doing wrong.

    When I create new bars,

    while (data.size() > ctNumVals.size()) {
        CTNumVal numVal = new CTNumVal();
        ctNumVals.add(ctNumVals.size(), numVal);
    }
    
    while (data.size() > ctStrVals.size()) {
        CTStrVal strVal = new CTStrVal();
        ctStrVals.add(ctStrVals.size(), strVal);
    }
    

    the idx values of the new bar are set to 0 by default. This makes any bar you create the first bar of the chart (overwriting the actual first bar). Simply set the idx values to the appropriate values as below.

    while (data.size() > ctNumVals.size()) {
        CTNumVal numVal = new CTNumVal();
        numVal.setIdx(ctNumVals.size());
        ctNumVals.add(ctNumVals.size(), numVal);
    }
    
    while (data.size() > ctStrVals.size()) {
        CTStrVal strVal = new CTStrVal();
        strVal.setIdx(ctStrVals.size());
        ctStrVals.add(ctStrVals.size(), strVal);
    }