使用 PHP 在演示文稿中管理图表数据标签
简介
数据标签显示图表系列和单个数据点的信息,帮助读者识别数值并理解图表。本文介绍如何格式化数值、显示百分比、读取标签文本、在坐标轴最大值之外控制标签、调整分类坐标轴标签间距以及定位饼图标签。
设置图表数据标签的数值精度
使用 setNumberFormatOfValues 来格式化系列数值。此示例创建一个默认数据的折线图,显示其数据表,并为第一系列启用数值标签。格式 #,##0.00 显示千位分隔符和两位小数,而不会更改底层数值。
use aspose\slides\Presentation;
use aspose\slides\ChartType;
use aspose\slides\SaveFormat;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$chart = $slide->getShapes()->addChart(ChartType::Line, 50, 50, 450, 300);
$chart->setDataTable(true);
$series = $chart->getChartData()->getSeries()->get_Item(0);
$series->setNumberFormatOfValues("#,##0.00");
$series->getLabels()->getDefaultDataLabelFormat()->setShowValue(true);
$presentation->save("PrecisionOfDatalabels_out.pptx", SaveFormat::Pptx);
} finally {
$presentation->dispose();
}
将百分比显示为标签
对于堆积柱形图,计算每个数值占其分类总计的百分比,并将文本分配给由 getTextFrameForOverriding 返回的文本框。本示例使用默认图表数据,并以两位小数、8 磅字体显示百分比。总计为零的分类会被跳过,以避免除以零。如果图表数据更改,需要重新计算自定义标签文本。
use aspose\slides\Presentation;
use aspose\slides\ChartType;
use aspose\slides\Portion;
use aspose\slides\SaveFormat;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$chart = $slide->getShapes()->addChart(ChartType::StackedColumn, 20, 20, 400, 400);
$categoryCount = java_values($chart->getChartData()->getCategories()->size());
$categoryTotals = array_fill(0, $categoryCount, 0.0);
for ($k = 0; $k < $categoryCount; $k++) {
for ($i = 0; $i < java_values($chart->getChartData()->getSeries()->size()); $i++) {
$series = $chart->getChartData()->getSeries()->get_Item($i);
$pointValue = java_values($series->getDataPoints()->get_Item($k)->getValue()->getData());
$categoryTotals[$k] += $pointValue;
}
}
for ($x = 0; $x < java_values($chart->getChartData()->getSeries()->size()); $x++) {
$series = $chart->getChartData()->getSeries()->get_Item($x);
$series->getLabels()->getDefaultDataLabelFormat()->setShowLegendKey(false);
for ($j = 0; $j < java_values($series->getDataPoints()->size()); $j++) {
$label = $series->getDataPoints()->get_Item($j)->getLabel();
if ($categoryTotals[$j] == 0) {
continue;
}
$pointValue = java_values($series->getDataPoints()->get_Item($j)->getValue()->getData());
$dataPointPercent = ($pointValue / $categoryTotals[$j]) * 100;
$portion = new Portion();
$portion->setText(sprintf("%.2F %%", $dataPointPercent));
$portion->getPortionFormat()->setFontHeight(8);
$label->getTextFrameForOverriding()->setText("");
$paragraph = $label->getTextFrameForOverriding()->getParagraphs()->get_Item(0);
$paragraph->getPortions()->add($portion);
$label->getDataLabelFormat()->setShowValue(true);
$label->getDataLabelFormat()->setShowSeriesName(false);
$label->getDataLabelFormat()->setShowPercentage(false);
$label->getDataLabelFormat()->setShowLegendKey(false);
$label->getDataLabelFormat()->setShowCategoryName(false);
$label->getDataLabelFormat()->setShowBubbleSize(false);
}
}
$presentation->save("DisplayPercentageAsLabels_out.pptx", SaveFormat::Pptx);
} finally {
$presentation->dispose();
}
在图表数据标签中设置百分号
当数值以分数形式存储时,使用 setNumberFormat 显示百分比。将 false 传递给 setNumberFormatLinkedToSource 以使标签格式独立于源单元格。
此示例创建一个 100% 堆积柱形图,包含红色和蓝色系列,跨四个分类。每对数值相加为 1。标签格式 0.0% 将 0.30 显示为 30.0%,而垂直坐标轴使用两位小数。两个系列的标签文本均为白色、10 磅。
use aspose\slides\Presentation;
use aspose\slides\ChartType;
use aspose\slides\FillType;
use aspose\slides\SaveFormat;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$chart = $slide->getShapes()->addChart(ChartType::PercentsStackedColumn, 20, 20, 500, 400);
$chart->getAxes()->getVerticalAxis()->setNumberFormatLinkedToSource(false);
$chart->getAxes()->getVerticalAxis()->setNumberFormat("0.00%");
$chart->getChartData()->getSeries()->clear();
$chart->getChartData()->getCategories()->clear();
$workbook = $chart->getChartData()->getChartDataWorkbook();
$worksheetIndex = 0;
for ($i = 0; $i < 4; $i++) {
$categoryCell = $workbook->getCell($worksheetIndex, $i + 1, 0, "Category " . ($i + 1));
$chart->getChartData()->getCategories()->add($categoryCell);
}
$colors = java("java.awt.Color");
$seriesNames = [ "Reds", "Blues" ];
$seriesColors = [ $colors->RED, $colors->BLUE ];
$values = [ [ 0.30, 0.50, 0.80, 0.65 ], [ 0.70, 0.50, 0.20, 0.35 ] ];
for ($i = 0; $i < count($seriesNames); $i++) {
$seriesCell = $workbook->getCell($worksheetIndex, 0, $i + 1, $seriesNames[$i]);
$series = $chart->getChartData()->getSeries()->add($seriesCell, $chart->getType());
for ($j = 0; $j < 4; $j++) {
$valueCell = $workbook->getCell($worksheetIndex, $j + 1, $i + 1, $values[$i][$j]);
$series->getDataPoints()->addDataPointForBarSeries($valueCell);
}
$series->getFormat()->getFill()->setFillType(FillType::Solid);
$series->getFormat()->getFill()->getSolidFillColor()->setColor($seriesColors[$i]);
$labelFormat = $series->getLabels()->getDefaultDataLabelFormat();
$labelFormat->setShowValue(true);
$labelFormat->setNumberFormatLinkedToSource(false);
$labelFormat->setNumberFormat("0.0%");
$labelFormat->getTextFormat()->getPortionFormat()->setFontHeight(10);
$labelFormat->getTextFormat()->getPortionFormat()->getFillFormat()->setFillType(FillType::Solid);
$labelFormat->getTextFormat()->getPortionFormat()->getFillFormat()->getSolidFillColor()->setColor($colors->WHITE);
}
$presentation->save("SetDataLabelsPercentageSign_out.pptx", SaveFormat::Pptx);
} finally {
$presentation->dispose();
}
读取数据标签的实际文本
使用 getActualLabelText 获取数据标签设置产生的文本。当提取标签用于报告、搜索演示文稿内容或验证生成的图表时,这很有用。下例中,默认的 data label format 将每个分类名称、系列名称和数值组合在一起。一个点将其数值格式化为百分比,另一个使用来自 getTextFrameForOverriding 的自定义文本。
use aspose\slides\Presentation;
use aspose\slides\ChartType;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$chart = $slide->getShapes()->addChart(ChartType::ClusteredColumn, 20, 20, 500, 300);
$chart->getChartData()->getSeries()->clear();
$chart->getChartData()->getCategories()->clear();
$workbook = $chart->getChartData()->getChartDataWorkbook();
$firstCategoryCell = $workbook->getCell(0, 1, 0, "Q1");
$chart->getChartData()->getCategories()->add($firstCategoryCell);
$secondCategoryCell = $workbook->getCell(0, 2, 0, "Q2");
$chart->getChartData()->getCategories()->add($secondCategoryCell);
$northSeriesCell = $workbook->getCell(0, 0, 1, "North");
$north = $chart->getChartData()->getSeries()->add($northSeriesCell, $chart->getType());
$northFirstValueCell = $workbook->getCell(0, 1, 1, 0.25);
$north->getDataPoints()->addDataPointForBarSeries($northFirstValueCell);
$northSecondValueCell = $workbook->getCell(0, 2, 1, 0.75);
$north->getDataPoints()->addDataPointForBarSeries($northSecondValueCell);
$southSeriesCell = $workbook->getCell(0, 0, 2, "South");
$south = $chart->getChartData()->getSeries()->add($southSeriesCell, $chart->getType());
$southFirstValueCell = $workbook->getCell(0, 1, 2, 0.40);
$south->getDataPoints()->addDataPointForBarSeries($southFirstValueCell);
$southSecondValueCell = $workbook->getCell(0, 2, 2, 0.60);
$south->getDataPoints()->addDataPointForBarSeries($southSecondValueCell);
for ($i = 0; $i < java_values($chart->getChartData()->getSeries()->size()); $i++) {
$series = $chart->getChartData()->getSeries()->get_Item($i);
$format = $series->getLabels()->getDefaultDataLabelFormat();
$format->setShowCategoryName(true);
$format->setShowSeriesName(true);
$format->setShowValue(true);
}
$north->getLabels()->get_Item(1)->getDataLabelFormat()->setNumberFormatLinkedToSource(false);
$north->getLabels()->get_Item(1)->getDataLabelFormat()->setNumberFormat("0%");
$south->getLabels()->get_Item(0)->getTextFrameForOverriding()->setText("Reviewed");
for ($i = 0; $i < java_values($chart->getChartData()->getSeries()->size()); $i++) {
$series = $chart->getChartData()->getSeries()->get_Item($i);
for ($j = 0; $j < java_values($series->getDataPoints()->size()); $j++) {
$point = $series->getDataPoints()->get_Item($j);
$label = $point->getLabel();
if (!java_values($label->isVisible())) {
continue;
}
echo "Value: " . java_values($point->getValue()->getData()) . "; label: " . java_values($label->getActualLabelText()) . PHP_EOL;
}
}
} finally {
$presentation->dispose();
}
数据点中存储的数值仍为 0.75,即使其标签显示 75% 并附带分类和系列名称。自定义文本会替代生成的标签文本。 getActualLabelText 在两种情况下都返回结果标签字符串。需要仅提取可见标签时,请像上文所示单独检查 isVisible。
在坐标轴最大值之外控制数据标签
当手动限制坐标轴范围时,某些数据点可能超出其最大值。使用 setShowDataLabelsOverMaximum 控制是否显示这些数据点的标签。此设置仅改变标签可见性,不会更改坐标轴范围或底层数据值。
下面的示例创建一个 2D 群集柱形图,数值为 60 和 120。它向 setAutomaticMaxValue 传递 false,并使用 setMaxValue 将垂直坐标轴的最大值设为 100。第一张幻灯片允许标签超出最大值;该幻灯片的复制版禁用此功能。两张幻灯片均保存为 DataLabelsOverMaximum.pptx。
使用 setShowValue 启用数值标签。图表级设置本身不会启用数值显示,也不会覆盖单个标签被禁用的数值显示。此示例为整个系列启用数值,并使用 setPosition 将标签放置在每个柱形的外部端点。
use aspose\slides\Presentation;
use aspose\slides\ChartType;
use aspose\slides\LegendDataLabelPosition;
use aspose\slides\SaveFormat;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$chart = $slide->getShapes()->addChart(ChartType::ClusteredColumn, 50, 50, 600, 400);
$chart->setLegend(false);
$chart->getChartData()->getSeries()->clear();
$chart->getChartData()->getCategories()->clear();
$workbook = $chart->getChartData()->getChartDataWorkbook();
$firstCategory = $workbook->getCell(0, 1, 0, "Within range");
$secondCategory = $workbook->getCell(0, 2, 0, "Above maximum");
$chart->getChartData()->getCategories()->add($firstCategory);
$chart->getChartData()->getCategories()->add($secondCategory);
$seriesName = $workbook->getCell(0, 0, 1, "Values");
$series = $chart->getChartData()->getSeries()->add($seriesName, $chart->getType());
$firstValue = $workbook->getCell(0, 1, 1, 60);
$secondValue = $workbook->getCell(0, 2, 1, 120);
$series->getDataPoints()->addDataPointForBarSeries($firstValue);
$series->getDataPoints()->addDataPointForBarSeries($secondValue);
$series->getLabels()->getDefaultDataLabelFormat()->setShowValue(true);
$series->getLabels()->getDefaultDataLabelFormat()->setPosition(LegendDataLabelPosition::OutsideEnd);
$chart->getAxes()->getVerticalAxis()->setAutomaticMaxValue(false);
$chart->getAxes()->getVerticalAxis()->setMaxValue(100);
$chart->setShowDataLabelsOverMaximum(true);
$secondSlide = $presentation->getSlides()->addClone($slide);
$secondChart = $secondSlide->getShapes()->get_Item(0);
$secondChart->setShowDataLabelsOverMaximum(false);
$presentation->save("DataLabelsOverMaximum.pptx", SaveFormat::Pptx);
} finally {
$presentation->dispose();
}
以下图像显示了 Microsoft PowerPoint 渲染的保存幻灯片。设置为 true 时,标签 120 在上边界可见;设置为 false 时,标签隐藏。标签 60 保持可见,坐标轴最大值仍为 100,第二个数据点在两种情况下均为 120。
| setShowDataLabelsOverMaximum(true) | setShowDataLabelsOverMaximum(false) |
|---|---|
![]() |
![]() |
Chart Type
此示例使用带数值坐标轴的 2D 柱形图。没有数值坐标轴的图表,如饼图和环形图,没有可用于此类限制的坐标轴最大值。设置标签与坐标轴的距离
使用 setLabelOffset 控制分类坐标轴标签与坐标轴之间的距离。该值是坐标轴标签最大字体大小的百分比。此示例创建一个群集柱形图,并将水平坐标轴标签偏移设置为 500。此设置影响分类坐标轴标签,而不是附加到单个数据点的标签。
use aspose\slides\Presentation;
use aspose\slides\ChartType;
use aspose\slides\SaveFormat;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$chart = $slide->getShapes()->addChart(ChartType::ClusteredColumn, 20, 20, 500, 300);
$chart->getAxes()->getHorizontalAxis()->setLabelOffset(500);
$presentation->save("SetCategoryAxisLabelDistance_out.pptx", SaveFormat::Pptx);
} finally {
$presentation->dispose();
}
调整标签位置
在饼图上,调整数据标签位置以改善间距并为指引线留出空间。
此示例显示第一个数据点的数值,将其标签放置在切片外部,并使用 setX 和 setY 调整其水平和垂直偏移。这些偏移相对于图表的宽度和高度。
use aspose\slides\Presentation;
use aspose\slides\ChartType;
use aspose\slides\LegendDataLabelPosition;
use aspose\slides\SaveFormat;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$chart = $slide->getShapes()->addChart(ChartType::Pie, 50, 50, 200, 200);
$series = $chart->getChartData()->getSeries();
$label = $series->get_Item(0)->getLabels()->get_Item(0);
$label->getDataLabelFormat()->setShowValue(true);
$label->getDataLabelFormat()->setPosition(LegendDataLabelPosition::OutsideEnd);
$label->setX(0.71);
$label->setY(0.04);
$presentation->save("presentation.pptx", SaveFormat::Pptx);
} finally {
$presentation->dispose();
}

在柱形图上方添加多行数据标签
此示例创建一个柱形图,在绘图区上方显示两行数据标签。Series A 显示可见的柱形,而 Series B 与 Series C 提供额外的标签。通过移除填充和轮廓来隐藏它们的柱形。ChartSeriesGroup::setOverlap 方法使所有三个系列在同一分类中心对齐。
ChartPlotArea 设置为标签行保留空间。调用 Chart::validateChartLayout 计算默认位置后,使用 DataLabel::setX 和 DataLabel::setY 保持水平对齐并应用垂直偏移,以将标签排列成两行。数字仍然是链接到系列数值的数据标签;只有行标题是独立的文本形状。
use aspose\slides\Presentation;
use aspose\slides\ChartType;
use aspose\slides\FillType;
use aspose\slides\LegendDataLabelPosition;
use aspose\slides\LayoutTargetType;
use aspose\slides\ShapeType;
use aspose\slides\SaveFormat;
$colors = java("java.awt.Color");
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$chart = $slide->getShapes()->addChart(ChartType::ClusteredColumn, 40, 40, 640, 200);
$chart->setTitle(false);
$chart->setLegend(false);
$chart->getTextFormat()->getPortionFormat()->setFontHeight(12);
$chart->getChartData()->getSeries()->clear();
$chart->getChartData()->getCategories()->clear();
$workbook = $chart->getChartData()->getChartDataWorkbook();
$workbook->clear(0);
$categories = [ "North", "South", "East", "West" ];
$seriesNames = [ "Series A", "Series B", "Series C" ];
$seriesValues = [
[ 35, 42, 28, 47 ],
[ 22, 31, 19, 26 ],
[ 12, 16, 14, 18 ]
];
for ($categoryIndex = 0; $categoryIndex < count($categories); $categoryIndex++) {
$categoryCell = $workbook->getCell(0, $categoryIndex + 1, 0, $categories[$categoryIndex]);
$chart->getChartData()->getCategories()->add($categoryCell);
}
for ($seriesIndex = 0; $seriesIndex < count($seriesNames); $seriesIndex++) {
$seriesCell = $workbook->getCell(0, 0, $seriesIndex + 1, $seriesNames[$seriesIndex]);
$series = $chart->getChartData()->getSeries()->add($seriesCell, ChartType::ClusteredColumn);
for ($categoryIndex = 0; $categoryIndex < count($categories); $categoryIndex++) {
$valueCell = $workbook->getCell(0, $categoryIndex + 1, $seriesIndex + 1, $seriesValues[$seriesIndex][$categoryIndex]);
$series->getDataPoints()->addDataPointForBarSeries($valueCell);
}
if ($seriesIndex > 0) {
// 隐藏 B 和 C 的柱形,但保留它们的数据标签。
$series->getFormat()->getFill()->setFillType(FillType::NoFill);
$series->getFormat()->getLine()->getFillFormat()->setFillType(FillType::NoFill);
$labelFormat = $series->getLabels()->getDefaultDataLabelFormat();
$labelFormat->setShowValue(true);
$labelFormat->getTextFormat()->getPortionFormat()->setFontHeight(12);
$labelFill = $labelFormat->getTextFormat()->getPortionFormat()->getFillFormat();
$labelFill->setFillType(FillType::Solid);
$labelFill->getSolidFillColor()->setColor($colors->BLACK);
$labelFormat->setPosition(LegendDataLabelPosition::InsideBase);
}
}
// 使所有三个系列在相同的分类中心对齐。
$chart->getChartData()->getSeries()->get_Item(0)->getParentSeriesGroup()->setOverlap(100);
// 在此紧凑示例中使用更少的网格线。
$chart->getAxes()->getVerticalAxis()->setAutomaticMajorUnit(false);
$chart->getAxes()->getVerticalAxis()->setMajorUnit(10);
// 在绘图区上方预留空间以放置两行数据标签。
$chart->getPlotArea()->setLayoutTargetType(LayoutTargetType::Inner);
$chart->getPlotArea()->setX(0.15);
$chart->getPlotArea()->setY(0.32);
$chart->getPlotArea()->setWidth(0.80);
$chart->getPlotArea()->setHeight(0.48);
$chart->validateChartLayout();
$chartX = java_values($chart->getX());
$chartY = java_values($chart->getY());
$chartHeight = java_values($chart->getHeight());
for ($seriesIndex = 1; $seriesIndex < count($seriesNames); $seriesIndex++) {
$series = $chart->getChartData()->getSeries()->get_Item($seriesIndex);
$rowTop = $seriesIndex == 1 ? 0.15 : 0.03;
for ($categoryIndex = 0; $categoryIndex < count($categories); $categoryIndex++) {
$dataLabel = $series->getDataPoints()->get_Item($categoryIndex)->getLabel();
// 保持默认的水平位置。Y 是相对于
// 默认标签位置的偏移量,以图表高度的比例表示。
$actualY = java_values($dataLabel->getActualY());
$dataLabel->setX(0);
$dataLabel->setY($rowTop - $actualY / $chartHeight);
}
// 只有行标题是单独的文本形状。
$rowHeading = $slide->getShapes()->addAutoShape(ShapeType::Rectangle, $chartX, $chartY + $rowTop * $chartHeight, 85, 18);
$rowHeading->getFillFormat()->setFillType(FillType::NoFill);
$rowHeading->getLineFormat()->getFillFormat()->setFillType(FillType::NoFill);
$rowHeading->addTextFrame($seriesNames[$seriesIndex]);
$rowHeading->getTextFrame()->getTextFrameFormat()->setMarginTop(0);
$rowHeading->getTextFrame()->getTextFrameFormat()->setMarginBottom(0);
$headingFormat = $rowHeading->getTextFrame()->getParagraphs()->get_Item(0)->getPortions()->get_Item(0)->getPortionFormat();
$headingFormat->setFontHeight(12);
$headingFormat->getFillFormat()->setFillType(FillType::Solid);
$headingFormat->getFillFormat()->getSolidFillColor()->setColor($colors->BLACK);
}
$presentation->save("multiple-rows-of-labels.pptx", SaveFormat::Pptx);
} finally {
$presentation->dispose();
}

常见问题
如何在密集图表中防止数据标签重叠?
结合自动标签放置、指引线和减小字体大小;如有必要,隐藏某些字段(例如分类),或仅对极值或关键点显示标签。
如何仅对零、负数或空值禁用标签?
在启用标签之前过滤数据点,并根据定义的规则关闭对值为 0、负值或缺失值的显示。
在导出为 PDF/图像时,如何确保标签样式一致?
显式设置字体系列和大小,并确认渲染环境中存在该字体,以避免回退。

