Repository: PHPOffice/PhpSpreadsheet (php)

Issue:
Is there a way to set the font size of data labels in a pie chart directly in PHP using PhpSpreadsheet?
This is:

```
- [ ] a bug report
- [x] 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?
In PhpSpreadsheet, I would like to be able to set the font size of data labels (both category names and percentages) in a pie chart directly from the PHP code.

What is the current behavior?
Currently, there doesn’t seem to be a direct way to modify the font size of pie chart data labels (like category names and percentages) within PhpSpreadsheet. I have reviewed the documentation and tried various settings, but could not find a solution for this.

What are the steps to reproduce?
Below is a sample code to generate a pie chart with data labels. However, I cannot find a way to adjust the font size of these labels (category names and values shown on the chart) directly:

```php
<?php
<?php

require __DIR__ . '/vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Layout;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;

$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();

// Sample data for pie chart
$data = [
    ['Category', 'Value'],
    ['Category A', 40],
    ['Category B', 30],
    ['Category C', 20],
    ['Category D', 10],
];
$worksheet->fromArray($data, null, 'A1');

// Create data series for the pie chart
$categories = [new DataSeriesValues('String', 'Worksheet!$A$2:$A$5', null, 4)];
$values = [new DataSeriesValues('Number', 'Worksheet!$B$2:$B$5', null, 4)];

// Set layout for data labels
$layout = new Layout();
$layout->setShowVal(true); // Display values
$layout->setShowCatName(true); // Display category names

$series = new DataSeries(
    DataSeries::TYPE_PIECHART, // Chart type: Pie chart
    null,
    range(0, count($values) - 1),
    [],
    $categories,
    $values
);

$plotArea = new PlotArea($layout, [$series]);
$chart = new Chart('Pie Chart', null, null, $plotArea);

// Add chart to worksheet
$worksheet->addChart($chart);

// Save to file
$writer = new Xlsx($spreadsheet);
$writer->setIncludeCharts(true);
$writer->save('pie_chart_example.xlsx');

```
If this is an issue with reading a specific spreadsheet file, then it may be appropriate to provide a sample file that demonstrates the problem; but please keep it as small as possible, and sanitize any confidential information before uploading.

### What features do you think are causing the issue
 - [ ]Reader
 - [ ] Writer
 - [x]Styles
 - [ ]Data Validations
 - [ ]Formula Calculations
 - [x]Charts
 - [ ]AutoFilter
 - [ ]Form Elements
Does an issue affect all spreadsheet file formats? If not, which formats are affected?
This issue likely affects all formats that include pie charts with data labels.

Which versions of PhpSpreadsheet and PHP are affected?
I am using PhpSpreadsheet version versions : * 3.3.0 and PHP version PHP 8.2.9.


Pull request:
Add setLabelFont to Chart/Layout
Fix #4201. Although that issue can be dealt with without any change to PhpSpreadsheet, it is pretty clear that `setLabelFont` has been accidentally omitted from Chart/Layout. Add it now. Xlsx Chart Writer is changed to use font name from labelFont if latin, eastAsian, or complexScript is uninitialized. Finally, chart label font size is multiplied by 100 in Xlsx Writer, as it is in Excel, but the corresponding division by 100 has been omitted from Xlsx Chart Reader - add that now.

This is:

- [x] a bugfix
- [ ] a new feature
- [ ] refactoring
- [ ] additional unit tests

Checklist:

- [x] Changes are covered by unit tests
  - [ ] Changes are covered by existing unit tests
  - [x] New unit tests have been added
- [x] Code style is respected
- [x] Commit message explains **why** the change is made (see https://github.com/erlang/otp/wiki/Writing-good-commit-messages)
- [ ] CHANGELOG.md contains a short summary of the change and a link to the pull request if applicable
- [ ] Documentation is updated as necessary

### Why this change is needed?

Provide an explanation of why this change is needed, with links to any Issues (if appropriate).
If this is a bugfix or a new feature, and there are no existing Issues, then please also create an issue that will make it easier to track progress with this PR.


Patch:
diff --git a/src/PhpSpreadsheet/Chart/Layout.php b/src/PhpSpreadsheet/Chart/Layout.php
index 570892ec1..5dc2991a4 100644
--- a/src/PhpSpreadsheet/Chart/Layout.php
+++ b/src/PhpSpreadsheet/Chart/Layout.php
@@ -450,6 +450,13 @@ class Layout
         return $this->labelFont;
     }
 
+    public function setLabelFont(?Font $labelFont): self
+    {
+        $this->labelFont = $labelFont;
+
+        return $this;
+    }
+
     public function getLabelEffects(): ?Properties
     {
         return $this->labelEffects;
diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php
index 146944150..beca090da 100644
--- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php
+++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php
@@ -1192,6 +1192,9 @@ class Chart
         }
         $fontArray = [];
         $fontArray['size'] = self::getAttributeInteger($titleDetailPart->pPr->defRPr, 'sz');
+        if ($fontArray['size'] !== null && $fontArray['size'] >= 100) {
+            $fontArray['size'] /= 100.0;
+        }
         $fontArray['bold'] = self::getAttributeBoolean($titleDetailPart->pPr->defRPr, 'b');
         $fontArray['italic'] = self::getAttributeBoolean($titleDetailPart->pPr->defRPr, 'i');
         $fontArray['underscore'] = self::getAttributeString($titleDetailPart->pPr->defRPr, 'u');
@@ -1305,6 +1308,10 @@ class Chart
                 case 'showLeaderLines':
                     $plotArea->setShowLeaderLines($plotAttributeValue);
 
+                    break;
+                case 'labelFont':
+                    $plotArea->setLabelFont($plotAttributeValue);
+
                     break;
             }
         }
diff --git a/src/PhpSpreadsheet/Style/Font.php b/src/PhpSpreadsheet/Style/Font.php
index b96cfca60..7d70dc4f7 100644
--- a/src/PhpSpreadsheet/Style/Font.php
+++ b/src/PhpSpreadsheet/Style/Font.php
@@ -20,10 +20,12 @@ class Font extends Supervisor
 
     protected ?string $cap = null;
 
+    public const DEFAULT_FONT_NAME = 'Calibri';
+
     /**
      * Font Name.
      */
-    protected ?string $name = 'Calibri';
+    protected ?string $name = self::DEFAULT_FONT_NAME;
 
     /**
      * The following 7 are used only for chart titles, I think.
diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
index 3bbcb3a88..e0856a51b 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
@@ -1912,19 +1912,23 @@ class Chart extends WriterPart
             $this->writeEffects($objWriter, $axisText);
         }
         if ($labelFont !== null) {
-            if (!empty($labelFont->getLatin())) {
+            $defaultFont = ($labelFont->getName() !== Font::DEFAULT_FONT_NAME) ? $labelFont->getName() : '';
+            $fontName = $labelFont->getLatin() ?: $defaultFont;
+            if (!empty($fontName)) {
                 $objWriter->startElement('a:latin');
-                $objWriter->writeAttribute('typeface', $labelFont->getLatin());
+                $objWriter->writeAttribute('typeface', $fontName);
                 $objWriter->endElement();
             }
-            if (!empty($labelFont->getEastAsian())) {
+            $fontName = $labelFont->getEastAsian() ?: $defaultFont;
+            if (!empty($fontName)) {
                 $objWriter->startElement('a:eastAsian');
-                $objWriter->writeAttribute('typeface', $labelFont->getEastAsian());
+                $objWriter->writeAttribute('typeface', $fontName);
                 $objWriter->endElement();
             }
-            if (!empty($labelFont->getComplexScript())) {
+            $fontName = $labelFont->getComplexScript() ?: $defaultFont;
+            if (!empty($fontName)) {
                 $objWriter->startElement('a:complexScript');
-                $objWriter->writeAttribute('typeface', $labelFont->getComplexScript());
+                $objWriter->writeAttribute('typeface', $fontName);
                 $objWriter->endElement();
             }
         }


Test patch:
diff --git a/tests/PhpSpreadsheetTests/Chart/Issue4201Test.php b/tests/PhpSpreadsheetTests/Chart/Issue4201Test.php
new file mode 100644
index 000000000..d93146c6c
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Chart/Issue4201Test.php
@@ -0,0 +1,97 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpOffice\PhpSpreadsheetTests\Chart;
+
+use PhpOffice\PhpSpreadsheet\Chart\Chart;
+use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
+use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
+use PhpOffice\PhpSpreadsheet\Chart\Layout;
+use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
+use PhpOffice\PhpSpreadsheet\Style\Font;
+use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
+use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
+
+class Issue4201Test extends AbstractFunctional
+{
+    public function readCharts(XlsxReader $reader): void
+    {
+        $reader->setIncludeCharts(true);
+    }
+
+    public function writeCharts(XlsxWriter $writer): void
+    {
+        $writer->setIncludeCharts(true);
+    }
+
+    public function testLabelFont(): void
+    {
+        $spreadsheet = new Spreadsheet();
+        $worksheet = $spreadsheet->getActiveSheet();
+
+        // Sample data for pie chart
+        $data = [
+            ['Category', 'Value'],
+            ['Category A', 40],
+            ['Category B', 30],
+            ['Category C', 20],
+            ['Category D', 10],
+        ];
+        $worksheet->fromArray($data, null, 'A1');
+        $worksheet->getColumnDimension('A')->setAutoSize(true);
+
+        // Create data series for the pie chart
+        $categories = [new DataSeriesValues('String', 'Worksheet!$A$2:$A$5', null, 4)];
+        $values = [new DataSeriesValues('Number', 'Worksheet!$B$2:$B$5', null, 4)];
+
+        // Set layout for data labels
+        $font = new Font();
+        $font->setName('Times New Roman');
+        $font->setSize(8);
+        $layout = new Layout();
+        $layout->setShowVal(true); // Display values
+        $layout->setShowCatName(true); // Display category names
+        $layout->setLabelFont($font);
+
+        $series = new DataSeries(
+            DataSeries::TYPE_PIECHART, // Chart type: Pie chart
+            null,
+            range(0, count($values) - 1),
+            [],
+            $categories,
+            $values
+        );
+
+        $plotArea = new PlotArea($layout, [$series]);
+        $chart = new Chart('Pie Chart', null, null, $plotArea);
+        $chart->setTopLeftPosition('A7');
+        $chart->setBottomRightPosition('H20');
+        $worksheet->addChart($chart);
+
+        /** @var callable */
+        $callableReader = [$this, 'readCharts'];
+        /** @var callable */
+        $callableWriter = [$this, 'writeCharts'];
+        $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
+        $spreadsheet->disconnectWorksheets();
+
+        $sheet = $reloadedSpreadsheet->getActiveSheet();
+        $charts = $sheet->getChartCollection();
+        self::assertCount(1, $charts);
+        $chart2 = $charts[0];
+        self::assertNotNull($chart2);
+        $plotArea2 = $chart2->getPlotArea();
+        self::assertNotNull($plotArea2);
+        $layout2 = $plotArea2->getLayout();
+        self::assertNotNull($layout2);
+        $font2 = $layout2->getLabelFont();
+        self::assertNotNull($font2);
+        self::assertSame('Times New Roman', $font2->getLatin());
+        self::assertSame(8.0, $font2->getSize());
+
+        $reloadedSpreadsheet->disconnectWorksheets();
+    }
+}