profile
viewpoint

Ask questionsPhpspreadsheet Charts don't work when adding multiple sheets - demo code works fine one worksheet, blank for 2+

This is:

- [x] a bug report
- [ ] a feature request
- [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpspreadsheet or https://gitter.im/PHPOffice/PhpSpreadsheet)

What is the expected behavior?

Creating charts with multiple worksheets should not be different from creating charts with just one worksheet

What is the current behavior?

I can create one or 2 charts happily so long as I stick to the first worksheet, but as soon as I add multiple worksheets the charts written are corrupted or just blank.

What are the steps to reproduce?

Please provide a Minimal, Complete, and Verifiable example of code that exhibits the issue without relying on an external Excel file or a web server:

If you run the code below with $stickToOneSheet set to true, the code runs fine.

There are several options for adding a worksheet and 2 (different?) $writers and none of them produce working charts if there is more than one worksheet.

<?php

require __DIR__ . '/vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;



$stickToOneSheet = true;
$useNewWriterFactory = false;
$cloneNewWorksheet = true; // Only relevant if multiple sheets
$multipleCharts = true;
$title = 'newworksheet';

$spreadsheet = new Spreadsheet();

if ($stickToOneSheet) {
    $worksheet = $spreadsheet->getActiveSheet();

} elseif ($cloneNewWorksheet) {
    $worksheet1 = $spreadsheet->getActiveSheet();
    $worksheet = clone $worksheet1;
    $worksheet->setTitle($title);
    $spreadsheet->addSheet($worksheet,1);
} elseif ($useNewWriterFactory) {

    $worksheet = new Worksheet($spreadsheet, $title);
    $spreadsheet->addSheet($worksheet,1);
} else {
    echo "Sorry, no idea what you want to test";
    die;
}


// Todo generate data in this format
$data = [  // Note this data need to be transposed
    ['Tutor Dashboard Report for someone@example.com'],
    [''],
    ['','Course Minutes','Quiz Minutes','Book Minutes','Other Minutes','Panopto Minutes','Total Minutes', 'Graded Activities', '# Vidoes Watched', '# Watched Completely', 'Quartile Rank'],
    ['Sep20',22,23,65,60,37,256,2,3,2,1],
    ['Oct20',18,39,47,68,38,256,2,3,2,1],
    ['Nov20',12,15,43,67,38,256,4,3,2,3],
    ['Dec20',4,1,154,0,21,256,2,3,2,1],
    ['Jan21',22,15,38,18,10,256,4,4,2,4],
    ['Feb21',18,39,47,68,38,256,2,3,2,1],
    ['Mar21',12,15,43,67,38,256,2,5,2,1],
    ['Apr21',4,1,154,14,21,256,2,1,1,1],
    ['May21',18,39,47,68,38,256,2,3,2,2],
];


$worksheet->fromArray($data);


$num_columns = count($data[2]);
$num_rows = count($data)-3;
echo "\n\nColumns: $num_columns, Rows: $num_rows\n\n";

// Set the Labels for each data series we want to plot
//     Datatype
//     Cell reference for data
//     Format Code
//     Number of datapoints in series
//     Data values
//     Data Marker
//Todo set start values to calculations
$dataSeriesLabels = [
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$3', null, 1), // Course
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$3', null, 1), // Quiz
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$3', null, 1), // Books
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$E$3', null, 1), // Other
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$F$3', null, 1), // Panopto
];
// Set the X-Axis Labels
//     Datatype
//     Cell reference for data
//     Format Code
//     Number of datapoints in series
//     Data values
//     Data Marker
$xAxisTickValues = [
    //Todo set values to calculations
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$4:$A$12', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
//     Datatype
//     Cell reference for data
//     Format Code
//     Number of datapoints in series
//     Data values
//     Data Marker
//Todo set start and end values to calculations
$dataSeriesValues = [
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$4:$B$12', null, 4),
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$4:$C$12', null, 4),
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$4:$D$12', null, 4),
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$E$4:$E$12', null, 4),
    new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$F$4:$F$12', null, 4),
];

// Build the dataseries
$series = new DataSeries(
    DataSeries::TYPE_BARCHART, // plotType
    DataSeries::GROUPING_STACKED, // plotGrouping
    range(0, count($dataSeriesValues) - 1), // plotOrder
    $dataSeriesLabels, // plotLabel
    $xAxisTickValues, // plotCategory
    $dataSeriesValues        // plotValues
);
// Set additional dataseries parameters
//     Make it a vertical column rather than a horizontal bar graph
$series->setPlotDirection(DataSeries::DIRECTION_COL);

// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
$legend = new Legend(Legend::POSITION_RIGHT, null, false);

$title = new Title('Tutor Dashboard - brmerritt@rvc.ac.uk'); // Todo add student email
$yAxisLabel = new Title('Learning Minutes');

// Create the chart
$chart = new Chart(
    'chart1', // name
    $title, // title
    $legend, // legend
    $plotArea, // plotArea
    true, // plotVisibleOnly
    DataSeries::EMPTY_AS_GAP, // displayBlanksAs
    null, // xAxisLabel
    $yAxisLabel  // yAxisLabel
);

// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A'.($num_rows + 7));
$chart->setBottomRightPosition('M'.($num_rows + 22));

// Add the chart to the worksheet
$worksheet->addChart($chart);

if ($multipleCharts) {


    // OK, try adding another chart!
    $dataSeriesLabels2 = [
        //new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$G$3', null, 1), // Total Minutes - ignore!
        new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$H$3', null, 1), // Graded Activities
        new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$I$3', null, 1), // Videos Watched
        new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$J$3', null, 1), // Watched Completely
        new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$K$3', null, 1), // Quartile Ranking
    ];
    $xAxisTickValues2 = [
        //Todo set values to calculations
        new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$4:$A$12', null, 4), // Q1 to Q4
    ];

    //Todo set start and end values to calculations
    $dataSeriesValues2 = [
        new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$H$4:$H$12', null, 4),
        new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$I$4:$I$12', null, 4),
        new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$J$4:$J$12', null, 4),
        new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$K$4:$K$12', null, 4),
        //new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$F$4:$F$12', null, 4),
    ];

    // Build the dataseries
    $series2 = new DataSeries(
        DataSeries::TYPE_BARCHART, // plotType
        DataSeries::GROUPING_CLUSTERED, // plotGrouping
        range(0, count($dataSeriesValues2) - 1), // plotOrder
        $dataSeriesLabels2, // plotLabel
        $xAxisTickValues2, // plotCategory
        $dataSeriesValues2        // plotValues
    );
    // Set additional dataseries parameters
    //     Make it a vertical column rather than a horizontal bar graph
    $series2->setPlotDirection(DataSeries::DIRECTION_COL);

    // Set the series in the plot area
    $plotArea2 = new PlotArea(null, [$series2]);
    // Set the chart legend
    $legend2 = new Legend(Legend::POSITION_RIGHT, null, false);

    $title2 = new Title('Graded Activities, Videos Watched, and Quartile Ranking'); // Todo add student email
    $yAxisLabel2 = new Title('Number of Each');


    $chart2 = new Chart(
        'chart2', // name
        $title2, // title
        $legend2, // legend
        $plotArea2, // plotArea
        true, // plotVisibleOnly
        DataSeries::EMPTY_AS_GAP, // displayBlanksAs
        null, // xAxisLabel
        $yAxisLabel2  // yAxisLabel
    );
    // Set the position where the chart should appear in the worksheet
    $chart2->setTopLeftPosition('A' . ($num_rows + 29));
    $chart2->setBottomRightPosition('M' . ($num_rows + 44));

    // Add the chart to the worksheet
    $worksheet->addChart($chart2);
}

// Save Excel file

$filename = "test_col1_stacked_7.xlsx";
if ($useNewWriterFactory) {
    $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
} else {
    $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
}

$writer->setIncludeCharts(true);
$callStartTime = microtime(true);
$writer->save($filename);
return 0;

// add code that show the issue here...

$stickToOneSheet = false; // Change the code above and the charts will not have visible data or be corrupted.

Which versions of PhpSpreadsheet and PHP are affected?

PHP 7.4.12 Phpspreadsheet versions 1.16 and 1.18 Excel version 2105 build 14026...

PHPOffice/PhpSpreadsheet

Answer questions brianlmerritt

Looking at the chart1.xml (after unzipping the sheet) the main items missing completely are the DataSeriesLables. For example

<c:f>Worksheet!$B$3</c:f><c:strCache><c:ptCount val="1"/><c:pt idx="0"><c:v>Course Minutes</c:v></c:pt></c:strCache></c:strRef></c:tx><c:invertIfNegative val="0"/><c:cat><c:strRef>

The $xAxisTickValues are there but missing their values

The rest of the .xml looks ok although series data xml ends with <c:tx><c:strRef> on the good chart but <c:invertIfNegative val="0"/><c:val><c:numRef> when the spreadsheet has multiple worksheets which may or may not be relevant.

useful!
source:https://uonfu.com/
Github User Rank List