PHPWord icon indicating copy to clipboard operation
PHPWord copied to clipboard

Define custom pie chart colors

Open SSchwaiger opened this issue 9 years ago • 6 comments

Inspired by http://stackoverflow.com/questions/24866280/pie-chart-colors-in-opendocument, I want to define the color of each pie chart segment. For that I wrote the following code. I'm not familiar with the coding conventions but wanted to share the code asap.

Btw., if my plan can also be achieved by specifying a ChartStyle object, I'm happy to get informed! After spending some time trying to figure out the purpose of the ChartStyle class, I decided to implement the following snippets:

PhpWord\Element\Chart.php line 57ff:

private $colors = null;

/**
 * Create new instance
 *
 * @param string $type
 * @param array $categories
 * @param array $values
 * @param array $style
 */
public function __construct($type, $categories, $values, $style = null, $colors = null)
{
    $this->setType($type);
    $this->addSeries($categories, $values);
    $this->style = $this->setNewStyle(new ChartStyle(), $style, true);

    $this->setColors($colors);
}

public function getColors() {
    return $this->colors;
}

public function setColors($value) {
    $this->colors = $value;
}

PhpWord\Writer\Word2007\Part.Chart.php line 209ff:

$this->writeSeriesItem($xmlWriter, 'cat', $categories); $this->writeSeriesItem($xmlWriter, 'val', $values);

            $elementColors = $this->element->getColors();
            //based on http://stackoverflow.com/questions/24866280/pie-chart-colors-in-opendocument
            if($elementColors !== null) {
                $colorIndex = 0;
                foreach ($elementColors as $color) {
                    $xmlWriter->startElement('c:dPt');

                    $xmlWriter->writeElementBlock('c:idx', 'val', $colorIndex);

                    $xmlWriter->startElement('c:spPr');

                    $xmlWriter->startElement('a:solidFill');

                    $xmlWriter->writeElementBlock('a:srgbClr', 'val', $color);

                    $xmlWriter->endElement(); // a:solidFill

                    $xmlWriter->endElement(); // c:spPr

                    $xmlWriter->endElement(); // c:dPt

                    $colorIndex++;
                }
            }

Usage:

$section = $phpWord->addSection();

$chart = $section->addChart('pie', array('Red', 'Yellow', 'Green'), array(1, 2, 3), null, array("FF0000", "FFFF00", "00FF00"));

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

SSchwaiger avatar Mar 14 '15 16:03 SSchwaiger

But now this not work. (fourth param is style -- not working) Any ideas?

xpyctum avatar Jun 16 '17 14:06 xpyctum

In version 0.15.0 it looks like you can change the colors with chart->getStyle()->setColors():

$categories = array('A', 'B', 'C', 'D', 'E');
$series1 = array(1, 3, 2, 5, 4);`
$chartType = 'pie';
$section->addTitle(ucfirst($chartType), 2);
$chart = $section->addChart($chartType, $categories, $series1);
$chart->getStyle()->setColors( array( 'FFFFFF', '000000', 'FF0000', '00FF00', '0000FF' ) );
$chart->getStyle()->setWidth(Converter::inchToEmu(2.5))->setHeight(Converter::inchToEmu(2));

coreyt808 avatar Oct 23 '18 20:10 coreyt808

Is it possible to customize colors for line chart, because I tested that but I got no changes in the graphic

ramziyahya avatar Feb 25 '19 17:02 ramziyahya

@ramziyahya indeed, it seems setting the colors has no effect on line charts. For Pie, Donut, Column, ... it is working.

troosan avatar Mar 07 '19 21:03 troosan

@troosan thank you for replying. I've solved this case by adding some changes in the code of PHPWord and I've added other features for exemple combined chart , advanced styles and others.

ramziyahya avatar Mar 08 '19 09:03 ramziyahya

@troosan thank you for replying. I've solved this case by adding some changes in the code of PHPWord and I've added other features for exemple combined chart , advanced styles and others.

setColors works on Pie,but...no effect on radar

q97585248 avatar Apr 17 '22 14:04 q97585248

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this is still an issue for you, please try to help by debugging it further and sharing your results. Thank you for your contributions.

github-actions[bot] avatar Nov 18 '22 02:11 github-actions[bot]

The above logic only makes sense for Pie and Donut charts. It will not work properly for any others.

If you want it to work for the others, add this logic under where the series name is defined. I will include the full if statement for the series. I suppose one can put it outside the if as well, I just placed it there because I always have the series name defined for my use cases. I also added a bit onto the series name element area. (Also note, I did not touch the vendor code, I extended the Chart Part in the Writer namespace and then overrode the applicable function).

This is in the writeSeries function:

        if (null !== $seriesItem['name'] && $seriesItem['name'] != '') {
                $xmlWriter->startElement('c:tx');
                $xmlWriter->startElement('c:strRef');
                $xmlWriter->startElement('c:strCache');
                $xmlWriter->writeElementBlock('c:ptCount', 'val', 1);
                $xmlWriter->startElement('c:pt');
                $xmlWriter->writeAttribute('idx', 0);
                $xmlWriter->startElement('c:v');
                $xmlWriter->writeRaw($seriesItem['name']);
                $xmlWriter->endElement(); // c:v
                $xmlWriter->endElement(); // c:pt
                $xmlWriter->endElement(); // c:strCache
                $xmlWriter->endElement(); // c:strRef
                $xmlWriter->endElement(); // c:tx

                // Add series colours if defined
                if (is_array($colors) && count($colors) > 0) {
                    $xmlWriter->startElement('c:spPr');
                    // Line charts require an a:ln element
                    if (strcmp($this->element->getType(), 'line') == 0) $xmlWriter->startElement('a:ln');
                    $xmlWriter->startElement('a:solidFill');
                    $xmlWriter->writeElementBlock('a:srgbClr', 'val', $colors[$index]);
                    $xmlWriter->endElement(); // a:solidFill
                    if (strcmp($this->element->getType(), 'line') == 0) $xmlWriter->endElement(); // a:ln
                    $xmlWriter->endElement(); // c:spPr
                }
            }

Later on, where the above colours are looped over to create data points, add a third condition into the If Block:

if (is_array($colors) && count($colors) > 0 && $this->options['colors'] == 1) { ... }

I'm sure some more work can be done, like I said, currently this was only done for my usage case. I'll update later on once I've finalised other aspects to make this logic more dynamic for all chart types.

CyferZ avatar Feb 10 '23 13:02 CyferZ