Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Charts - Missing ability to modify Chart Settings #957

Closed
phpdave opened this issue Dec 14, 2016 · 17 comments
Closed

Charts - Missing ability to modify Chart Settings #957

phpdave opened this issue Dec 14, 2016 · 17 comments

Comments

@phpdave
Copy link

phpdave commented Dec 14, 2016

Missing ability to modify Chart Settings

Data Labels above line graph points

  1. Data Label Position (http:https://www.datypic.com/sc/ooxml/t-draw-chart_ST_DLblPos.html)
  2. Show Value of Label (http:https://www.datypic.com/sc/ooxml/e-draw-chart_showVal-1.html)

Location of where these values are set:

<c:chart>
<c:plotArea>
<c:lineChart>
<c:dLbls>
	<c:dLblPos val="t"/>
	<c:showVal val="1"/>
</c:dLbls>
</c:lineChart>
</c:lineChart>

Other Missing XML data that I'd like to help get working

Note I removed xml data that already is being set and just showing tags that appear to not be set
3. Set Axis Number Format (http:https://www.datypic.com/sc/ooxml/e-draw-chart_numFmt-1.html)
4. Set Axis Tick Label Position (http:https://www.datypic.com/sc/ooxml/e-draw-chart_tickLblPos-1.html)
5. Set Axis Shape Properties Shape Properties (http:https://www.datypic.com/sc/ooxml/e-draw-chart_spPr-1.html)
6. Set Axis No Multi-level Labels (http:https://www.datypic.com/sc/ooxml/e-draw-chart_noMultiLvlLbl-1.html)
7. Set Axis Major Gridlines (http:https://www.datypic.com/sc/ooxml/e-draw-chart_majorGridlines-1.html)
8. Set Legend Position (http:https://www.datypic.com/sc/ooxml/t-draw-chart_CT_LegendPos.html)
9. Set Legend Overlay http:https://www.datypic.com/sc/ooxml/e-draw-chart_overlay-1.html
10. Set Display Blanks As http:https://www.datypic.com/sc/ooxml/e-draw-chart_dispBlanksAs-1.html
11. Show Data Labels over Maximum http:https://www.datypic.com/sc/ooxml/e-draw-chart_showDLblsOverMax-1.html
12. Set External Data Relationship http:https://www.datypic.com/sc/ooxml/e-draw-chart_externalData-1.html

<pkg:part>
<pkg:xmlData> 
<c:chart>
		<c:plotArea>
			<c:layout/>
			<c:lineChart>
				<c:ser>
					<c:catAx>
						<c:numFmt formatCode="General" sourceLinked="1"/>
						<c:tickLblPos val="nextTo"/>
						<c:spPr>
							<a:ln>
								<a:solidFill/>
							</a:ln>
						</c:spPr>
						<c:noMultiLvlLbl val="0"/>
					</c:catAx>
					<c:valAx>
						<c:majorGridlines/>
						<c:numFmt formatCode="General" sourceLinked="1"/>
						<c:tickLblPos val="nextTo"/>
						<c:spPr>
							<a:ln w="9525">
								<a:noFill/>
							</a:ln>
						</c:spPr>
					</c:valAx>
		</c:plotArea>
    <c:legend>
        <c:legendPos val="b"/>
        <c:overlay val="0"/>
    </c:legend>
<c:dispBlanksAs val="gap"/>
<c:showDLblsOverMax val="0"/>
</c:chart>	
	<c:externalData r:id="rId1">
		<c:autoUpdate val="0"/>
	</c:externalData>
</c:chartSpace>
</pkg:xmlData>
</pkg:part>

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

@phpdave
Copy link
Author

phpdave commented Jan 4, 2017

It seems a user needs to be able to pass the graph options (data labels options, axis options, etc...) to the PhpOffice\PhpWord\Element\Chart class.

In the PhpOffice\PhpWord\Writer\Word2007\Part\Chart class's writeSeries method after it writes all the series data it needs to take the private class variable $element which is a PhpOffice\PhpWord\Element\Chart and use the data labels options to output c:dLbls values. In the writeAxis method where it checks if the option axes is set it should use the $element axis options instead of using the hard coded values below

if (isset($this->options['axes'])) {
            $xmlWriter->writeElementBlock('c:delete', 'val', 0);
            $xmlWriter->writeElementBlock('c:majorTickMark', 'val', 'none');
            $xmlWriter->writeElementBlock('c:minorTickMark', 'val', 'none');
            $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none'); // nextTo
            $xmlWriter->writeElementBlock('c:crosses', 'val', 'autoZero');
        }

It also appears having the developer send over the raw XML data for the options might be easiest, as creating a data structure for the xml can be a pain with multiple attributes and nested xml.

something like:

$chart = $section->addChart('line', $categories, array());
$chartOptions = array();
            $chartOptions['c:dLbls']='<c:dLblPos val="t"/>
                                        <c:showLegendKey val="0"/>
                                        <c:showVal val="1"/>
                                        <c:showCatName val="0"/>
                                        <c:showSerName val="0"/>
                                        <c:showPercent val="0"/>
                                        <c:showBubbleSize val="0"/>';
            $chartOptions['c:catAx']='  <c:scaling>
                                            <c:orientation val="minMax"/>
                                        </c:scaling>
                                        <c:delete val="0"/>
                                        <c:numFmt formatCode="General" sourceLinked="1"/>
                                        <c:majorTickMark val="none"/>
                                        <c:minorTickMark val="none"/>
                                        <c:tickLblPos val="nextTo"/>
                                        <c:crosses val="autoZero"/>
                                        <c:lblAlgn val="ctr"/>
                                        <c:lblOffset val="100"/>
                                        <c:noMultiLvlLbl val="0"/>';
            $chartOptions['c:valAx']='  <c:scaling>
                                            <c:orientation val="minMax"/>
                                        </c:scaling>
                                        <c:delete val="0"/>
                                        <c:majorGridlines/>
                                        <c:numFmt formatCode="General" sourceLinked="1"/>
                                        <c:majorTickMark val="none"/>
                                        <c:minorTickMark val="none"/>
                                        <c:tickLblPos val="nextTo"/>
                                        <c:spPr>
                                            <a:ln w="9525">
                                                <a:noFill/>
                                            </a:ln>
                                        </c:spPr>
                                        <c:crosses val="autoZero"/>
                                        <c:crossBetween val="between"/>';
            $chart->setOptions($chartOptions);

and in PhpOffice\PhpWord\Writer\Word2007\Part\Chart.php

Get the Axis Options outputted

private function writeAxis(XMLWriter $xmlWriter, $type)
    {
        $types = array(
            'cat' => array('c:catAx', 1, 'b', 2),
            'val' => array('c:valAx', 2, 'l', 1),
        );
        list($axisType, $axisId, $axisPos, $axisCross) = $types[$type];

        $xmlWriter->startElement($axisType);

        $xmlWriter->writeElementBlock('c:axId', 'val', $axisId);
        $xmlWriter->writeElementBlock('c:axPos', 'val', $axisPos);
        $xmlWriter->writeElementBlock('c:crossAx', 'val', $axisCross);
        $xmlWriter->writeElementBlock('c:auto', 'val', 1);
        
        //::NOTE:: NEW CODE
        //Axis options @link http:https://www.datypic.com/sc/ooxml/e-draw-chart_catAx-1.html
        $chartOptions = $this->element->getOptions();
        if($axisType=='c:catAx' && isset($chartOptions['c:catAx']))
        {
//write raw xml options and return back
            $xmlWriter->writeRaw($chartOptions['c:catAx']);
            $xmlWriter->endElement(); // $axisType
            return;
        }
        else if($axisType=='c:valAx' && isset($chartOptions['c:valAx']))
        {
//write raw xml options and return back
            $xmlWriter->writeRaw($chartOptions['c:valAx']);
            $xmlWriter->endElement(); // $axisType
            return;
        }
        else if (isset($this->options['axes'])) {
            $xmlWriter->writeElementBlock('c:delete', 'val', 0);
            $xmlWriter->writeElementBlock('c:majorTickMark', 'val', 'none');
            $xmlWriter->writeElementBlock('c:minorTickMark', 'val', 'none');
            $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none'); // nextTo
            $xmlWriter->writeElementBlock('c:crosses', 'val', 'autoZero');
        }
        if (isset($this->options['radar'])) {
            $xmlWriter->writeElement('c:majorGridlines');
        }

        $xmlWriter->startElement('c:scaling');
        $xmlWriter->writeElementBlock('c:orientation', 'val', 'minMax');
        $xmlWriter->endElement(); // c:scaling

        $this->writeShape($xmlWriter, true);

        $xmlWriter->endElement(); // $axisType
    }

Get the Data Labels options outputted

private function writeSeries(XMLWriter $xmlWriter, $scatter = false)
    {
        $series = $this->element->getSeries();

        $index = 0;
        foreach ($series as $seriesItem) {
            $categories = $seriesItem['categories'];
            $values = $seriesItem['values'];

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

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

            if (isset($this->options['scatter'])) {
                $this->writeShape($xmlWriter);
            }

            if ($scatter === true) {
                $this->writeSeriesItem($xmlWriter, 'xVal', $categories);
                $this->writeSeriesItem($xmlWriter, 'yVal', $values);
            } else {
                $this->writeSeriesItem($xmlWriter, 'cat', $categories);
                $this->writeSeriesItem($xmlWriter, 'val', $values);
            }

            $xmlWriter->endElement(); // c:ser
            $index++;
        }

        //::NOTE:: NEW CODE
        
        //Series Data Labels @link http:https://www.datypic.com/sc/ooxml/e-draw-chart_dLbls-1.html
        $chartOptions = $this->element->getOptions();
        if(isset($chartOptions['c:dLbls']))
        {
            $xmlWriter->startElement('c:dLbls');
            $xmlWriter->writeRaw($chartOptions['c:dLbls']);
            $xmlWriter->endElement(); // </c:dLbls>
        }
    }

get the legend to display

private function writeChart(XMLWriter $xmlWriter)
    {
        $xmlWriter->startElement('c:chart');

        $xmlWriter->writeElementBlock('c:autoTitleDeleted', 'val', 1);

        $this->writePlotArea($xmlWriter);
//::NOTE:: New Code
        $xmlWriter->writeRaw('<c:legend>
                                <c:legendPos val="b"/>
                                <c:overlay val="0"/>
                            </c:legend>');
        $xmlWriter->endElement(); // c:chart
    }

To give the SeriesItem a name so that in the legend each line has a name you have to add

private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values,$name)
    {
        $types = array(
            'cat' => array('c:cat', 'c:strLit'),
            'val' => array('c:val', 'c:numLit'),
            'xVal' => array('c:xVal', 'c:strLit'),
            'yVal' => array('c:yVal', 'c:numLit'),
        );
        list($itemType, $itemLit) = $types[$type];
        
            $seriesName = '
                                          <c:tx>
                                            <c:strRef>
                                              <c:strCache>
                                                <c:ptCount val="1"/>
                                                <c:pt idx="0">
                                                  <c:v>'.$name.'</c:v>
                                                </c:pt>
                                              </c:strCache>
                                            </c:strRef>
                                          </c:tx>';
        $chartOptions = $this->element->getOptions();
        if(isset($seriesName) && $type ==='cat')
        {
            $xmlWriter->writeRaw($seriesName);
        }

@scalco19
Copy link

scalco19 commented Mar 9, 2017

How can I implement these Data Label properties
http:https://www.datypic.com/sc/ooxml/e-draw-chart_dLbl-1.html

@phpdave
Copy link
Author

phpdave commented Mar 9, 2017

@scalco19 not sure, that's a bar graph and not a line graph in the issue I was working on. I'd recommend looking into reverse engineering the xml and just writing the rawxml of the entire graph from a template.

@marwankhanfar
Copy link

@phpdave did you manage to add legends and chart data

@diggamies
Copy link

diggamies commented Aug 2, 2017

@marwankhanfar If you follow his instructions stated in this thread, everything works like a charm for me. I think, if you have the time, you could build some setters for the data labels and legend if you want to, so that you don't have to work with the raw xml.

@phpdave Do you have an idea how to position multiple chart elements in a row side-by-side. As far as I have tested, I only get them like a block element beneath each other.

@phpdave
Copy link
Author

phpdave commented Aug 2, 2017

@diggamies I would make that change in word, save it as xml and view the difference it made to the xml. That seems like the quickest way to figure out how to do it.

@marwabjhanfar yes if you follow what I wrote it will work.

@diggamies
Copy link

@phpdave Yeah, been there, done that. As I have found out, there is always a new paragraph around a chart element. Wenn you put them in word side-by-side you have both of them inside one paragraph. I found a variable $withoutP in the AbstractElement but it is not working on the Chart Element, when you change it to true.

@marwankhanfar
Copy link

marwankhanfar commented Aug 2, 2017

@phpdave @diggamies can you please send me the package with the changes, I tried to implement yours with no luck at my email : [email protected]

@LDKJJ
Copy link

LDKJJ commented Mar 26, 2018

Hello @phpdave thank you for your post
i am see last change for show axis and datalabel in chart using PHPWORD with add same XML and it's working for me.
Now my need is how to set style color in chart for example (radar chart) thanx :)

@iarc13
Copy link

iarc13 commented Jul 22, 2018

@phpdave thank you so much for the Legend. It now shows up in the pie-chart. I now want to display the DATA LABELS in pie chart. Would the hard coding suggested by you work with pie-chart?

@iarc13
Copy link

iarc13 commented Jul 22, 2018

My code is not recognizing the setOptions function...any idea?
PHP Fatal error: Uncaught Error: Call to undefined method PhpOffice\PhpWord\Element\Chart::setOptions() in /var/www/html/phpword/samples/Sample_32_Chart.php:66
Stack trace:

@diggamies
Copy link

diggamies commented Nov 21, 2018

@ARC113 Sorry, for not answering in such a long time, but I think with a new version of PHPWord the setOptions function has been removed. There are some options available now in the style object of the Chart class, but these are not working really good but there is no option for a legend as i can see. The dataLabels should work with your pieCharts.

@phpdave Did you update to the current version and can tell us a workaround to get the legend back?

@phpdave
Copy link
Author

phpdave commented Nov 21, 2018

I’d recommend looking over the recent changes 65b0f06#diff-f95e31bde7c0c2535019d08b30203161

@phpdave
Copy link
Author

phpdave commented Nov 21, 2018

@jaek-s did some work to charts that may fix the issues I was running into

@phpdave
Copy link
Author

phpdave commented Nov 21, 2018

Looks like he added Data labels :-)

@diggamies
Copy link

@phpdave Yeah, I was just checking these changes and since the setOptions method is not available anymore and only dataLabels are supported, I lost the otion to add the legend. Maybe i have to fork and set up a pull request in some time in the future to add legends to charts. Since I am using mostly pieCharts the dataLabels are not a big help in my case.

@phpdave
Copy link
Author

phpdave commented Nov 21, 2018

Ah I understand your issue now. Looks like fork and PR is the best approach. At least you have the documentation above to help. Good luck @diggamies!

@phpdave phpdave closed this as completed Apr 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

6 participants