Skip to content

Commit

Permalink
Support for managing missing values in Chart
Browse files Browse the repository at this point in the history
  • Loading branch information
Progi1984 committed Jul 26, 2021
1 parent 543e19a commit a730ee3
Show file tree
Hide file tree
Showing 11 changed files with 319 additions and 55 deletions.
3 changes: 3 additions & 0 deletions docs/changes/1.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
- Support for rotation for axis label - @Progi1986 GH-410
- ODPresentation Writer
- PowerPoint2007 Writer
- Support for managing missing values in Chart - @TonisOrmisson GH-581 & @Progi1986 GH-659
- ODPresentation Writer
- PowerPoint2007 Writer

## Project Management
- Migrated from Travis CI to Github Actions - @Progi1984 GH-635
Expand Down
Binary file added docs/images/libreoffice_chart_displayblankas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/usage/presentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ $state = $presentation->isMarkedAsFinal();

You can define the type of slideshow you can with the method `setSlideshowType`.

![Slideshow type](/PHPPresentation/images/presentation_slideshow_type.png)
![Slideshow type](/images/presentation_slideshow_type.png)

Differents types are available:

Expand Down
25 changes: 25 additions & 0 deletions docs/usage/shapes/chart.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,31 @@ To create a chart, use `createChartShape` method of Slide.
$chartShape = $slide->createChartShape();
```

## Customization

### Manage how blank values are displayed

You can define how blank values are displayed with the method `setDisplayBlankAs`.

![Slideshow type](/images/libreoffice_chart_displayblankas.png)

Differents types are available:

* `Chart::BLANKAS_GAP` for **Leave a gap**
* `Chart::BLANKAS_ZERO` for **Assume zero** (default)
* `Chart::BLANKAS_SPAN` for **Continue line**

``` php
<?php

use PhpOffice\PhpPresentation\Shape\Chart;

// Set the behavior
$chart->setDisplayBlankAs(Chart::BLANKAS_GAP);
// Get the behavior
echo $chart->getDisplayBlankAs();
```

## Parts

### Axis
Expand Down
38 changes: 31 additions & 7 deletions samples/Sample_05_Chart_Line.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
include_once 'Sample_Header.php';

use PhpOffice\PhpPresentation\PhpPresentation;
use PhpOffice\PhpPresentation\Shape\Chart;
use PhpOffice\PhpPresentation\Shape\Chart\Gridlines;
use PhpOffice\PhpPresentation\Shape\Chart\Marker;
use PhpOffice\PhpPresentation\Shape\Chart\Series;
use PhpOffice\PhpPresentation\Shape\Chart\Type\Line;
use PhpOffice\PhpPresentation\Style\Border;
use PhpOffice\PhpPresentation\Style\Color;
use PhpOffice\PhpPresentation\Style\Fill;
use PhpOffice\PhpPresentation\Style\Outline;
use PhpOffice\PhpPresentation\Style\Shadow;

// Create new PHPPresentation object
Expand Down Expand Up @@ -73,7 +77,7 @@
$currentSlide = createTemplatedSlide($objPHPPresentation);

// Create a line chart (that should be inserted in a shape)
$oOutline = new \PhpOffice\PhpPresentation\Style\Outline();
$oOutline = new Outline();
$oOutline->getFill()->setFillType(Fill::FILL_SOLID);
$oOutline->getFill()->setStartColor(new Color(Color::COLOR_YELLOW));
$oOutline->setWidth(2);
Expand All @@ -82,7 +86,7 @@
$lineChart1 = clone $lineChart;
$series1 = $lineChart1->getSeries();
$series1[0]->setOutline($oOutline);
$series1[0]->getMarker()->setSymbol(\PhpOffice\PhpPresentation\Shape\Chart\Marker::SYMBOL_DIAMOND);
$series1[0]->getMarker()->setSymbol(Marker::SYMBOL_DIAMOND);
$series1[0]->getMarker()->setSize(7);
$lineChart1->setSeries($series1);

Expand All @@ -106,7 +110,7 @@
$lineChart2 = clone $lineChart;
$series2 = $lineChart2->getSeries();
$series2[0]->getFont()->setSize(25);
$series2[0]->getMarker()->setSymbol(\PhpOffice\PhpPresentation\Shape\Chart\Marker::SYMBOL_TRIANGLE);
$series2[0]->getMarker()->setSymbol(Marker::SYMBOL_TRIANGLE);
$series2[0]->getMarker()->setSize(10);
$lineChart2->setSeries($series2);

Expand All @@ -129,11 +133,11 @@
echo date('H:i:s') . ' Create a line chart (that should be inserted in a chart shape)' . EOL;
$lineChart3 = clone $lineChart;

$oGridLines1 = new \PhpOffice\PhpPresentation\Shape\Chart\Gridlines();
$oGridLines1 = new Gridlines();
$oGridLines1->getOutline()->setWidth(10);
$oGridLines1->getOutline()->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_BLUE));

$oGridLines2 = new \PhpOffice\PhpPresentation\Shape\Chart\Gridlines();
$oGridLines2 = new Gridlines();
$oGridLines2->getOutline()->setWidth(1);
$oGridLines2->getOutline()->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKGREEN));

Expand All @@ -156,12 +160,12 @@
echo date('H:i:s') . ' Create a line chart (that should be inserted in a chart shape)' . EOL;
$lineChart4 = clone $lineChart;

$oOutlineAxisX = new \PhpOffice\PhpPresentation\Style\Outline();
$oOutlineAxisX = new Outline();
$oOutlineAxisX->setWidth(2);
$oOutlineAxisX->getFill()->setFillType(Fill::FILL_SOLID);
$oOutlineAxisX->getFill()->getStartColor()->setRGB('012345');

$oOutlineAxisY = new \PhpOffice\PhpPresentation\Style\Outline();
$oOutlineAxisY = new Outline();
$oOutlineAxisY->setWidth(5);
$oOutlineAxisY->getFill()->setFillType(Fill::FILL_SOLID);
$oOutlineAxisY->getFill()->getStartColor()->setRGB('ABCDEF');
Expand Down Expand Up @@ -190,6 +194,26 @@
$shape5->getPlotArea()->getAxisY()->setMinBounds(5);
$shape5->getPlotArea()->getAxisY()->setMaxBounds(20);
$currentSlide->addShape($shape5);

// Create templated slide
echo EOL . date('H:i:s') . ' Create templated slide #6' . EOL;
$currentSlide = createTemplatedSlide($objPHPPresentation);

// Create a shape (chart)
echo date('H:i:s') . ' Create a shape (chart6)' . EOL;
echo date('H:i:s') . ' Feature : DisplayBlankAs' . EOL;
$shape6 = clone $shape;
$lineChart6 = clone $lineChart;
$series6 = clone $series;
$seriesData6 = $seriesData;
$seriesData6['Thursday'] = null;

$series6->setValues($seriesData6);
$lineChart6->setSeries([$series6]);
$shape6->getPlotArea()->setType($lineChart6);
$shape6->setDisplayBlankAs(Chart::BLANKAS_GAP);
$currentSlide->addShape($shape6);

// Save file
echo EOL . write($objPHPPresentation, basename(__FILE__, '.php'), $writers);

Expand Down
34 changes: 34 additions & 0 deletions src/PhpPresentation/Shape/Chart.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
*/
class Chart extends AbstractGraphic implements ComparableInterface
{
public const BLANKAS_GAP = 'gap';
public const BLANKAS_ZERO = 'zero';
public const BLANKAS_SPAN = 'span';

/**
* Title.
*
Expand Down Expand Up @@ -64,6 +68,12 @@ class Chart extends AbstractGraphic implements ComparableInterface
*/
private $includeSpreadsheet = false;

/**
* How to display blank (missing) values? Not set by default.
* @var string
*/
private $displayBlankAs = self::BLANKAS_ZERO;

/**
* Create a new Chart.
*/
Expand All @@ -89,6 +99,16 @@ public function __clone()
$this->view3D = clone $this->view3D;
}

/**
* How missing/blank values are displayed on chart (dispBlanksAs property)
*
* @return string
*/
public function getDisplayBlankAs(): string
{
return $this->displayBlankAs;
}

/**
* Get Title.
*
Expand Down Expand Up @@ -139,6 +159,20 @@ public function hasIncludedSpreadsheet(): bool
return $this->includeSpreadsheet;
}

/**
* Define a way to display missing/blank values (dispBlanksAs property)
*
* @param string $value
* @return self
*/
public function setDisplayBlankAs(string $value): self
{
if (in_array($value, [self::BLANKAS_GAP, self::BLANKAS_SPAN, self::BLANKAS_ZERO])) {
$this->displayBlankAs = $value;
}
return $this;
}

/**
* Is the spreadsheet included for editing data ?
*
Expand Down
78 changes: 44 additions & 34 deletions src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,17 @@ private function writePlotAreaStyle(Chart $chart): void
$this->xmlContent->writeAttribute('chart:three-dimensional', 'true');
$this->xmlContent->writeAttribute('chart:right-angled-axes', 'true');
}
switch ($chart->getDisplayBlankAs()) {
case Chart::BLANKAS_ZERO:
$this->xmlContent->writeAttribute('chart:treat-empty-cells', 'use-zero');
break;
case Chart::BLANKAS_GAP:
$this->xmlContent->writeAttribute('chart:treat-empty-cells', 'leave-gap');
break;
case Chart::BLANKAS_SPAN:
$this->xmlContent->writeAttribute('chart:treat-empty-cells', 'ignore');
break;
}
if ($chartType instanceof AbstractTypeBar) {
$chartVertical = 'false';
if (AbstractTypeBar::DIRECTION_HORIZONTAL == $chartType->getBarDirection()) {
Expand Down Expand Up @@ -809,40 +820,6 @@ private function writeTable(): void
// > table:table-header-columns
$this->xmlContent->endElement();

// table:table-rows
$this->xmlContent->startElement('table:table-rows');
if (empty($this->arrayData)) {
$this->xmlContent->startElement('table:table-row');
$this->xmlContent->startElement('table:table-cell');
$this->xmlContent->endElement();
$this->xmlContent->endElement();
} else {
foreach ($this->arrayData as $row) {
// table:table-row
$this->xmlContent->startElement('table:table-row');
foreach ($row as $cell) {
// table:table-cell
$this->xmlContent->startElement('table:table-cell');

$cellNumeric = is_numeric($cell);
$this->xmlContent->writeAttributeIf(!$cellNumeric, 'office:value-type', 'string');
$this->xmlContent->writeAttributeIf($cellNumeric, 'office:value-type', 'float');
$this->xmlContent->writeAttributeIf($cellNumeric, 'office:value', $cell);
// text:p
$this->xmlContent->startElement('text:p');
$this->xmlContent->text($cell);
// > text:p
$this->xmlContent->endElement();
// > table:table-cell
$this->xmlContent->endElement();
}
// > table:table-row
$this->xmlContent->endElement();
}
}
// > table:table-rows
$this->xmlContent->endElement();

// table:table-header-rows
$this->xmlContent->startElement('table:table-header-rows');
// table:table-row
Expand Down Expand Up @@ -874,6 +851,39 @@ private function writeTable(): void
// > table:table-header-rows
$this->xmlContent->endElement();

// table:table-rows
$this->xmlContent->startElement('table:table-rows');
if (empty($this->arrayData)) {
$this->xmlContent->startElement('table:table-row');
$this->xmlContent->startElement('table:table-cell');
$this->xmlContent->endElement();
$this->xmlContent->endElement();
} else {
foreach ($this->arrayData as $row) {
// table:table-row
$this->xmlContent->startElement('table:table-row');
foreach ($row as $cell) {
// table:table-cell
$this->xmlContent->startElement('table:table-cell');

$cellValueTypeFloat = is_null($cell) ? true : is_numeric($cell);
$this->xmlContent->writeAttributeIf(!$cellValueTypeFloat, 'office:value-type', 'string');
$this->xmlContent->writeAttributeIf($cellValueTypeFloat, 'office:value-type', 'float');
$this->xmlContent->writeAttributeIf($cellValueTypeFloat, 'office:value', is_null($cell) ? 'NaN' : $cell);
// text:p
$this->xmlContent->startElement('text:p');
$this->xmlContent->text(is_null($cell) ? 'NaN' : $cell);
$this->xmlContent->endElement();
// > table:table-cell
$this->xmlContent->endElement();
}
// > table:table-row
$this->xmlContent->endElement();
}
}
// > table:table-rows
$this->xmlContent->endElement();

// > table:table
$this->xmlContent->endElement();
}
Expand Down
5 changes: 5 additions & 0 deletions src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ public function writeChart(Chart $chart): string
$objWriter->writeAttribute('val', '1');
$objWriter->endElement();

// c:dispBlanksAs
$objWriter->startElement('c:dispBlanksAs');
$objWriter->writeAttribute('val', $chart->getDisplayBlankAs());
$objWriter->endElement();

$objWriter->endElement();

// c:spPr
Expand Down
39 changes: 27 additions & 12 deletions tests/PhpPresentation/Tests/Shape/ChartTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ public function testConstruct(): void
{
$object = new Chart();

$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Title', $object->getTitle());
$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Legend', $object->getLegend());
$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->getPlotArea());
$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\View3D', $object->getView3D());
$this->assertInstanceOf(Chart\Title::class, $object->getTitle());
$this->assertInstanceOf(Chart\Legend::class, $object->getLegend());
$this->assertInstanceOf(Chart\PlotArea::class, $object->getPlotArea());
$this->assertInstanceOf(Chart\View3D::class, $object->getView3D());
}

public function testClone(): void
Expand All @@ -44,23 +44,38 @@ public function testClone(): void

$oClone = clone $object;

$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart', $oClone);
$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Title', $oClone->getTitle());
$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Legend', $oClone->getLegend());
$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $oClone->getPlotArea());
$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\View3D', $oClone->getView3D());
$this->assertInstanceOf(Chart::class, $oClone);
$this->assertInstanceOf(Chart\Title::class, $oClone->getTitle());
$this->assertInstanceOf(Chart\Legend::class, $oClone->getLegend());
$this->assertInstanceOf(Chart\PlotArea::class, $oClone->getPlotArea());
$this->assertInstanceOf(Chart\View3D::class, $oClone->getView3D());
}

public function testDisplayBlankAs(): void
{
$object = new Chart();

$this->assertEquals(Chart::BLANKAS_ZERO, $object->getDisplayBlankAs());
$this->assertInstanceOf(Chart::class, $object->setDisplayBlankAs(Chart::BLANKAS_GAP));
$this->assertEquals(Chart::BLANKAS_GAP, $object->getDisplayBlankAs());
$this->assertInstanceOf(Chart::class, $object->setDisplayBlankAs(Chart::BLANKAS_ZERO));
$this->assertEquals(Chart::BLANKAS_ZERO, $object->getDisplayBlankAs());
$this->assertInstanceOf(Chart::class, $object->setDisplayBlankAs(Chart::BLANKAS_SPAN));
$this->assertEquals(Chart::BLANKAS_SPAN, $object->getDisplayBlankAs());
$this->assertInstanceOf(Chart::class, $object->setDisplayBlankAs('Unauthorized value'));
$this->assertEquals(Chart::BLANKAS_SPAN, $object->getDisplayBlankAs());
}

public function testIncludeSpreadsheet(): void
{
$object = new Chart();

$this->assertFalse($object->hasIncludedSpreadsheet());
$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart', $object->setIncludeSpreadsheet());
$this->assertInstanceOf(Chart::class, $object->setIncludeSpreadsheet());
$this->assertFalse($object->hasIncludedSpreadsheet());
$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart', $object->setIncludeSpreadsheet(false));
$this->assertInstanceOf(Chart::class, $object->setIncludeSpreadsheet(false));
$this->assertFalse($object->hasIncludedSpreadsheet());
$this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart', $object->setIncludeSpreadsheet(true));
$this->assertInstanceOf(Chart::class, $object->setIncludeSpreadsheet(true));
$this->assertTrue($object->hasIncludedSpreadsheet());
}
}
Loading

0 comments on commit a730ee3

Please sign in to comment.