使用 C++ 在演示文稿中管理图表数据标签
简介
数据标签显示有关图表系列和各个数据点的信息,帮助读者识别数值并理解图表。本文解释了如何格式化数值、显示百分比、读取标签文本、控制轴最大值之外的标签、调整类目轴标签间距,以及定位饼图标签。
在图表数据标签中设置数据精度
使用set_NumberFormatOfValues来格式化系列值。此示例创建一个带默认数据的折线图,显示其数据表,并为第一系列启用数值标签。格式 #,##0.00 显示千位分隔符和两位小数,而不更改底层数值。
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IChartData.h>
#include <DOM/Chart/IChartSeriesCollection.h>
#include <DOM/Chart/IChartSeries.h>
#include <DOM/Chart/IDataLabelCollection.h>
#include <DOM/Chart/IDataLabelFormat.h>
#include <Export/SaveFormat.h>
#include <system/smart_ptr.h>
#include <system/string.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
using namespace System;
auto presentation = MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::Line, 50, 50, 450, 300);
chart->set_HasDataTable(true);
auto series = chart->get_ChartData()->get_Series()->idx_get(0);
series->set_NumberFormatOfValues(u"#,##0.00");
series->get_Labels()->get_DefaultDataLabelFormat()->set_ShowValue(true);
presentation->Save(u"PrecisionOfDatalabels_out.pptx", SaveFormat::Pptx);
要格式化图表嵌入工作簿中的数字单元格,请参阅设置工作簿单元格的自定义数字格式。该示例还展示了数值标签遵循其源单元格格式,同时保留存储的数值。
将百分比显示为标签
对于堆叠柱形图,计算每个值相对于其类目总计的百分比,并将文本分配给由get_TextFrameForOverriding返回的文本框。此示例使用默认图表数据,并以 8 磅字体显示两位小数的百分比。总计为零的类目将被跳过,以避免除以零。如果图表数据更改,需要重新计算自定义标签文本。
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IChartData.h>
#include <DOM/Chart/IChartCategoryCollection.h>
#include <DOM/Chart/IChartSeriesCollection.h>
#include <DOM/Chart/IChartSeries.h>
#include <DOM/Chart/IChartDataPointCollection.h>
#include <DOM/Chart/IChartDataPoint.h>
#include <DOM/Chart/IDoubleChartValue.h>
#include <DOM/Chart/IDataLabel.h>
#include <DOM/Chart/IDataLabelCollection.h>
#include <DOM/Chart/IDataLabelFormat.h>
#include <DOM/Portion.h>
#include <DOM/IPortionFormat.h>
#include <DOM/ITextFrame.h>
#include <DOM/IParagraph.h>
#include <DOM/IParagraphCollection.h>
#include <DOM/IPortionCollection.h>
#include <system/convert.h>
#include <vector>
#include <Export/SaveFormat.h>
#include <system/smart_ptr.h>
#include <system/string.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
using namespace System;
auto presentation = MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::StackedColumn, 20, 20, 400, 400);
auto categoryTotals = std::vector<double>(chart->get_ChartData()->get_Categories()->get_Count(), 0.0);
for (auto k = 0; k < chart->get_ChartData()->get_Categories()->get_Count(); k++)
{
for (auto i = 0; i < chart->get_ChartData()->get_Series()->get_Count(); i++)
{
auto series = chart->get_ChartData()->get_Series()->idx_get(i);
auto pointValue = Convert::ToDouble(series->get_DataPoint(k)->get_Value()->get_Data());
categoryTotals[k] += pointValue;
}
}
for (auto x = 0; x < chart->get_ChartData()->get_Series()->get_Count(); x++)
{
auto series = chart->get_ChartData()->get_Series()->idx_get(x);
series->get_Labels()->get_DefaultDataLabelFormat()->set_ShowLegendKey(false);
for (auto j = 0; j < series->get_DataPoints()->get_Count(); j++)
{
auto label = series->get_DataPoint(j)->get_Label();
if (categoryTotals[j] == 0)
{
continue;
}
auto pointValue = Convert::ToDouble(series->get_DataPoint(j)->get_Value()->get_Data());
auto dataPointPercent = (pointValue / categoryTotals[j]) * 100;
auto portion = MakeObject<Portion>();
portion->set_Text(String::Format(u"{0:F2} %", dataPointPercent));
portion->get_PortionFormat()->set_FontHeight(8.0f);
label->get_TextFrameForOverriding()->set_Text(u"");
auto paragraph = label->get_TextFrameForOverriding()->get_Paragraphs()->idx_get(0);
paragraph->get_Portions()->Add(portion);
label->get_DataLabelFormat()->set_ShowValue(true);
label->get_DataLabelFormat()->set_ShowSeriesName(false);
label->get_DataLabelFormat()->set_ShowPercentage(false);
label->get_DataLabelFormat()->set_ShowLegendKey(false);
label->get_DataLabelFormat()->set_ShowCategoryName(false);
label->get_DataLabelFormat()->set_ShowBubbleSize(false);
}
}
presentation->Save(u"DisplayPercentageAsLabels_out.pptx", SaveFormat::Pptx);
使用图表数据标签设置百分号
当数值存储为分数时,使用set_NumberFormat显示百分比。将false传递给set_IsNumberFormatLinkedToSource以使标签格式独立于源单元格。
此示例创建一个 100% 堆叠柱形图,四个类目中包含红色和蓝色系列。每对数值相加为 1。标签格式0.0%将 0.30 显示为 30.0%,而垂直轴使用两位小数。两个系列均使用白色、10 磅的标签文本。
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IAxesManager.h>
#include <DOM/Chart/IAxis.h>
#include <DOM/Chart/IChartData.h>
#include <DOM/Chart/IChartCategoryCollection.h>
#include <DOM/Chart/IChartDataWorkbook.h>
#include <DOM/Chart/IChartDataCell.h>
#include <DOM/Chart/IChartSeriesCollection.h>
#include <DOM/Chart/IChartSeries.h>
#include <DOM/Chart/IChartDataPointCollection.h>
#include <DOM/Chart/IFormat.h>
#include <DOM/Chart/IDataLabelCollection.h>
#include <DOM/Chart/IDataLabelFormat.h>
#include <DOM/Chart/IChartTextFormat.h>
#include <DOM/Chart/IChartPortionFormat.h>
#include <DOM/FillType.h>
#include <DOM/IFillFormat.h>
#include <DOM/IColorFormat.h>
#include <drawing/color.h>
#include <system/object_ext.h>
#include <Export/SaveFormat.h>
#include <system/smart_ptr.h>
#include <system/string.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
using namespace System;
using namespace System::Drawing;
auto presentation = MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::PercentsStackedColumn, 20, 20, 500, 400);
chart->get_Axes()->get_VerticalAxis()->set_IsNumberFormatLinkedToSource(false);
chart->get_Axes()->get_VerticalAxis()->set_NumberFormat(u"0.00%");
chart->get_ChartData()->get_Series()->Clear();
chart->get_ChartData()->get_Categories()->Clear();
auto workbook = chart->get_ChartData()->get_ChartDataWorkbook();
auto worksheetIndex = 0;
for (auto i = 0; i < 4; i++)
{
auto categoryCell = workbook->GetCell(worksheetIndex, i + 1, 0, ObjectExt::Box(String::Format(u"Category {0}", i + 1)));
chart->get_ChartData()->get_Categories()->Add(categoryCell);
}
String seriesNames[] = { u"Reds", u"Blues" };
Color seriesColors[] = { Color::get_Red(), Color::get_Blue() };
double values[2][4] = { { 0.30, 0.50, 0.80, 0.65 }, { 0.70, 0.50, 0.20, 0.35 } };
for (auto i = 0; i < 2; i++)
{
auto seriesCell = workbook->GetCell(worksheetIndex, 0, i + 1, ObjectExt::Box(seriesNames[i]));
auto series = chart->get_ChartData()->get_Series()->Add(seriesCell, chart->get_Type());
for (auto j = 0; j < 4; j++)
{
auto valueCell = workbook->GetCell(worksheetIndex, j + 1, i + 1, ObjectExt::Box(values[i][j]));
series->get_DataPoints()->AddDataPointForBarSeries(valueCell);
}
series->get_Format()->get_Fill()->set_FillType(FillType::Solid);
series->get_Format()->get_Fill()->get_SolidFillColor()->set_Color(seriesColors[i]);
auto labelFormat = series->get_Labels()->get_DefaultDataLabelFormat();
labelFormat->set_ShowValue(true);
labelFormat->set_IsNumberFormatLinkedToSource(false);
labelFormat->set_NumberFormat(u"0.0%");
labelFormat->get_TextFormat()->get_PortionFormat()->set_FontHeight(10);
labelFormat->get_TextFormat()->get_PortionFormat()->get_FillFormat()->set_FillType(FillType::Solid);
labelFormat->get_TextFormat()->get_PortionFormat()->get_FillFormat()->get_SolidFillColor()->set_Color(Color::get_White());
}
presentation->Save(u"SetDataLabelsPercentageSign_out.pptx", SaveFormat::Pptx);
读取数据标签的实际文本
使用GetActualLabelText检索由数据标签设置生成的文本。当提取标签用于报告、搜索演示文稿内容或验证生成的图表时,这非常有用。在下面的示例中,默认的data label format将每个类目名称、系列名称和数值组合起来。一个点将其数值格式化为百分比,另一个使用来自get_TextFrameForOverriding的自定义文本。
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IChartData.h>
#include <DOM/Chart/IChartCategoryCollection.h>
#include <DOM/Chart/IChartDataWorkbook.h>
#include <DOM/Chart/IChartDataCell.h>
#include <DOM/Chart/IChartSeriesCollection.h>
#include <DOM/Chart/IChartSeries.h>
#include <DOM/Chart/IChartDataPointCollection.h>
#include <DOM/Chart/IChartDataPoint.h>
#include <DOM/Chart/IDoubleChartValue.h>
#include <DOM/Chart/IDataLabel.h>
#include <DOM/Chart/IDataLabelCollection.h>
#include <DOM/Chart/IDataLabelFormat.h>
#include <DOM/ITextFrame.h>
#include <system/console.h>
#include <system/object_ext.h>
#include <system/smart_ptr.h>
#include <system/string.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace System;
auto presentation = MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::ClusteredColumn, 20, 20, 500, 300);
chart->get_ChartData()->get_Series()->Clear();
chart->get_ChartData()->get_Categories()->Clear();
auto workbook = chart->get_ChartData()->get_ChartDataWorkbook();
auto firstCategoryCell = workbook->GetCell(0, 1, 0, ObjectExt::Box<String>(u"Q1"));
chart->get_ChartData()->get_Categories()->Add(firstCategoryCell);
auto secondCategoryCell = workbook->GetCell(0, 2, 0, ObjectExt::Box<String>(u"Q2"));
chart->get_ChartData()->get_Categories()->Add(secondCategoryCell);
auto northSeriesCell = workbook->GetCell(0, 0, 1, ObjectExt::Box<String>(u"North"));
auto north = chart->get_ChartData()->get_Series()->Add(northSeriesCell, chart->get_Type());
auto northFirstValueCell = workbook->GetCell(0, 1, 1, ObjectExt::Box(0.25));
north->get_DataPoints()->AddDataPointForBarSeries(northFirstValueCell);
auto northSecondValueCell = workbook->GetCell(0, 2, 1, ObjectExt::Box(0.75));
north->get_DataPoints()->AddDataPointForBarSeries(northSecondValueCell);
auto southSeriesCell = workbook->GetCell(0, 0, 2, ObjectExt::Box<String>(u"South"));
auto south = chart->get_ChartData()->get_Series()->Add(southSeriesCell, chart->get_Type());
auto southFirstValueCell = workbook->GetCell(0, 1, 2, ObjectExt::Box(0.40));
south->get_DataPoints()->AddDataPointForBarSeries(southFirstValueCell);
auto southSecondValueCell = workbook->GetCell(0, 2, 2, ObjectExt::Box(0.60));
south->get_DataPoints()->AddDataPointForBarSeries(southSecondValueCell);
for (auto i = 0; i < chart->get_ChartData()->get_Series()->get_Count(); i++)
{
auto series = chart->get_ChartData()->get_Series()->idx_get(i);
auto format = series->get_Labels()->get_DefaultDataLabelFormat();
format->set_ShowCategoryName(true);
format->set_ShowSeriesName(true);
format->set_ShowValue(true);
}
north->get_Label(1)->get_DataLabelFormat()->set_IsNumberFormatLinkedToSource(false);
north->get_Label(1)->get_DataLabelFormat()->set_NumberFormat(u"0%");
south->get_Label(0)->get_TextFrameForOverriding()->set_Text(u"Reviewed");
for (auto i = 0; i < chart->get_ChartData()->get_Series()->get_Count(); i++)
{
auto series = chart->get_ChartData()->get_Series()->idx_get(i);
for (auto j = 0; j < series->get_DataPoints()->get_Count(); j++)
{
auto point = series->get_DataPoint(j);
auto label = point->get_Label();
if (!label->get_IsVisible())
{
continue;
}
Console::WriteLine(String::Format(u"Value: {0}; label: {1}", point->get_Value()->get_Data(), label->GetActualLabelText()));
}
}
存储在数据点中的数值仍为0.75,即使其标签显示为75%并包含类目和系列名称。自定义文本会替代生成的标签文本。GetActualLabelText在两种情况下均返回结果标签字符串。请像上面示例那样单独检查get_IsVisible,当您只想提取可见标签时使用。
控制轴最大值之外的数据标签
当手动限制轴范围时,某些数据点可能超过其最大值。使用set_ShowDataLabelsOverMaximum来控制是否显示这些数据标签。此设置仅改变标签可见性,不会更改轴范围或底层数据值。
下面的示例创建一个二维簇状柱形图,数值为 60 和 120。它在垂直轴上将set_IsAutomaticMaxValue设为false,并将set_MaxValue设为 100。第一张幻灯片允许在最大值之外显示标签;其副本则禁用此功能。两张幻灯片均保存为DataLabelsOverMaximum.pptx。
使用set_ShowValue启用数值标签。图表级设置本身并不启用数值显示,也不会覆盖单个标签已禁用的数值显示。此示例为整个系列启用数值,并使用set_Position将标签放置在每个柱形的外部端点。
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/ISlideCollection.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IAxesManager.h>
#include <DOM/Chart/IAxis.h>
#include <DOM/Chart/IChartData.h>
#include <DOM/Chart/IChartCategoryCollection.h>
#include <DOM/Chart/IChartDataWorkbook.h>
#include <DOM/Chart/IChartDataCell.h>
#include <DOM/Chart/IChartSeriesCollection.h>
#include <DOM/Chart/IChartSeries.h>
#include <DOM/Chart/IChartDataPointCollection.h>
#include <DOM/Chart/IDataLabelCollection.h>
#include <DOM/Chart/IDataLabelFormat.h>
#include <DOM/Chart/LegendDataLabelPosition.h>
#include <Export/SaveFormat.h>
#include <system/object_ext.h>
#include <system/smart_ptr.h>
#include <system/string.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
using namespace System;
auto presentation = MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::ClusteredColumn, 50, 50, 600, 400);
chart->set_HasLegend(false);
chart->get_ChartData()->get_Series()->Clear();
chart->get_ChartData()->get_Categories()->Clear();
auto workbook = chart->get_ChartData()->get_ChartDataWorkbook();
auto firstCategory = workbook->GetCell(0, 1, 0, ObjectExt::Box<String>(u"Within range"));
auto secondCategory = workbook->GetCell(0, 2, 0, ObjectExt::Box<String>(u"Above maximum"));
chart->get_ChartData()->get_Categories()->Add(firstCategory);
chart->get_ChartData()->get_Categories()->Add(secondCategory);
auto seriesName = workbook->GetCell(0, 0, 1, ObjectExt::Box<String>(u"Values"));
auto series = chart->get_ChartData()->get_Series()->Add(seriesName, chart->get_Type());
auto firstValue = workbook->GetCell(0, 1, 1, ObjectExt::Box(60));
auto secondValue = workbook->GetCell(0, 2, 1, ObjectExt::Box(120));
series->get_DataPoints()->AddDataPointForBarSeries(firstValue);
series->get_DataPoints()->AddDataPointForBarSeries(secondValue);
series->get_Labels()->get_DefaultDataLabelFormat()->set_ShowValue(true);
series->get_Labels()->get_DefaultDataLabelFormat()->set_Position(LegendDataLabelPosition::OutsideEnd);
chart->get_Axes()->get_VerticalAxis()->set_IsAutomaticMaxValue(false);
chart->get_Axes()->get_VerticalAxis()->set_MaxValue(100);
chart->set_ShowDataLabelsOverMaximum(true);
auto secondSlide = presentation->get_Slides()->AddClone(slide);
auto secondChart = ExplicitCast<IChart>(secondSlide->get_Shape(0));
secondChart->set_ShowDataLabelsOverMaximum(false);
presentation->Save(u"DataLabelsOverMaximum.pptx", SaveFormat::Pptx);
下图显示了 Microsoft PowerPoint 渲染的已保存幻灯片。true 时,标签120在上边界可见;false 时则隐藏。标签60始终可见,轴最大值保持为100,第二个数据点在两种情况下仍为120。
| ShowDataLabelsOverMaximum = true | ShowDataLabelsOverMaximum = false |
|---|---|
![]() |
![]() |
Chart Type
此示例使用带数值轴的二维柱形图。没有数值轴的图表(如饼图和环形图)没有可用于此类限制的轴最大值。设置标签距轴的距离
使用set_LabelOffset控制类目轴标签与轴之间的距离。该值是轴标签最大字体大小的百分比。此示例创建一个簇状柱形图,并将水平轴标签偏移设置为 500。此设置影响类目轴标签,而非附加于单个数据点的标签。
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IAxesManager.h>
#include <DOM/Chart/IAxis.h>
#include <Export/SaveFormat.h>
#include <system/smart_ptr.h>
#include <system/string.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
using namespace System;
auto presentation = MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::ClusteredColumn, 20, 20, 500, 300);
chart->get_Axes()->get_HorizontalAxis()->set_LabelOffset(500);
presentation->Save(u"SetCategoryAxisLabelDistance_out.pptx", SaveFormat::Pptx);
调整标签位置
在饼图上,调整数据标签位置以改善间距并为引线留出空间。
此示例显示第一个数据点的数值,将其标签放置在切片外部,并使用set_X和set_Y调整其偏移。这些偏移分别相对于图表的宽度和高度。
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IChartData.h>
#include <DOM/Chart/IChartSeriesCollection.h>
#include <DOM/Chart/IChartSeries.h>
#include <DOM/Chart/IDataLabel.h>
#include <DOM/Chart/IDataLabelFormat.h>
#include <DOM/Chart/LegendDataLabelPosition.h>
#include <Export/SaveFormat.h>
#include <system/smart_ptr.h>
#include <system/string.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
using namespace System;
auto presentation = MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::Pie, 50, 50, 200, 200);
auto series = chart->get_ChartData()->get_Series();
auto label = series->idx_get(0)->get_Label(0);
label->get_DataLabelFormat()->set_ShowValue(true);
label->get_DataLabelFormat()->set_Position(LegendDataLabelPosition::OutsideEnd);
label->set_X(0.71f);
label->set_Y(0.04f);
presentation->Save(u"presentation.pptx", SaveFormat::Pptx);

格式化引线
当饼图标签位于切片外部时,引线帮助读者将每个数值与相应切片对应。使用对比色和稍粗的线条可以使这些连接更易辨认,而透明度和虚线样式则保持线条不显眼。
使用get_LeaderLinesFormat在系列数据标签集合层面格式化引线。series->get_Labels()->get_LeaderLinesFormat()->get_Line() 中的设置应用于整个集合,而非单个标签。
此示例创建一个带默认数据的饼图,在切片外部显示数值,并通过set_ShowLeaderLines启用引线。它使用set_X和set_Y将两个标签进一步移离切片,偏移以图表宽度和高度的比例表示。无需输入演示文稿。
通过get_FillFormat返回的填充格式设置为蓝色实线,α值为 191(255 中的约 25% 透明度)。set_Width将粗细设为 2 磅,set_DashStyle将线条设为虚线。
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IChartData.h>
#include <DOM/Chart/IChartSeriesCollection.h>
#include <DOM/Chart/IChartSeries.h>
#include <DOM/Chart/IDataLabel.h>
#include <DOM/Chart/IDataLabelCollection.h>
#include <DOM/Chart/IDataLabelFormat.h>
#include <DOM/Chart/IChartLinesFormat.h>
#include <DOM/Chart/LegendDataLabelPosition.h>
#include <DOM/ILineFormat.h>
#include <DOM/ILineFillFormat.h>
#include <DOM/IColorFormat.h>
#include <DOM/FillType.h>
#include <DOM/LineDashStyle.h>
#include <Export/SaveFormat.h>
#include <drawing/color.h>
#include <system/smart_ptr.h>
#include <system/string.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
using namespace System;
using namespace System::Drawing;
auto presentation = MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::Pie, 80, 50, 560, 400);
chart->set_HasLegend(false);
auto series = chart->get_ChartData()->get_Series()->idx_get(0);
auto labelFormat = series->get_Labels()->get_DefaultDataLabelFormat();
labelFormat->set_ShowValue(true);
labelFormat->set_Position(LegendDataLabelPosition::OutsideEnd);
labelFormat->set_ShowLeaderLines(true);
// 将两个标签从切片上移得更远。
series->get_Label(0)->set_X(0.10f);
series->get_Label(0)->set_Y(-0.05f);
series->get_Label(1)->set_X(-0.10f);
series->get_Label(1)->set_Y(0.05f);
auto line = series->get_Labels()->get_LeaderLinesFormat()->get_Line();
line->get_FillFormat()->set_FillType(FillType::Solid);
line->get_FillFormat()->get_SolidFillColor()->set_Color(Color::FromArgb(191, 30, 90, 160));
line->set_Width(2);
line->set_DashStyle(LineDashStyle::Dash);
presentation->Save(u"FormattedLeaderLines.pptx", SaveFormat::Pptx);
启用引线并不保证每个标签都会出现引线。可见性取决于标签位置和图表布局行为。在本示例中,被移动的两个标签拥有可见的引线;靠近切片的标签则不需要引线。
下图显示了使用 Aspose.Slides 渲染的已保存 FormattedLeaderLines.pptx:

在柱形图上方添加多行数据标签
此示例创建一个柱形图,在绘图区域上方显示两行数据标签。系列 A 显示可见柱形,系列 B 和系列 C 提供额外标签。通过移除填充和轮廓将它们的柱形隐藏。set_Overlap方法使所有三个系列在同一类目中心对齐。
get_PlotArea 设置为标签行预留空间。经过ValidateChartLayout计算默认位置后,使用set_X和set_Y保持水平对齐并施加垂直偏移,以将标签排列成两行。数字仍然是链接到系列数值的数据标签;只有行标题是独立的文本形状。
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IChartData.h>
#include <DOM/Chart/IChartCategoryCollection.h>
#include <DOM/Chart/IChartDataWorkbook.h>
#include <DOM/Chart/IChartDataCell.h>
#include <DOM/Chart/IChartSeriesCollection.h>
#include <DOM/Chart/IChartSeries.h>
#include <DOM/Chart/IChartDataPointCollection.h>
#include <DOM/Chart/IChartDataPoint.h>
#include <DOM/Chart/IChartSeriesGroup.h>
#include <DOM/Chart/IFormat.h>
#include <DOM/Chart/IDataLabelCollection.h>
#include <DOM/Chart/IDataLabelFormat.h>
#include <DOM/Chart/IDataLabel.h>
#include <DOM/Chart/IChartTextFormat.h>
#include <DOM/Chart/IChartPortionFormat.h>
#include <DOM/Chart/LegendDataLabelPosition.h>
#include <DOM/Chart/IAxesManager.h>
#include <DOM/Chart/IAxis.h>
#include <DOM/Chart/IChartPlotArea.h>
#include <DOM/Chart/LayoutTargetType.h>
#include <DOM/FillType.h>
#include <DOM/IFillFormat.h>
#include <DOM/ILineFormat.h>
#include <DOM/IColorFormat.h>
#include <DOM/ShapeType.h>
#include <DOM/IAutoShape.h>
#include <DOM/ITextFrame.h>
#include <DOM/ITextFrameFormat.h>
#include <DOM/IParagraphCollection.h>
#include <DOM/IParagraph.h>
#include <DOM/IPortionCollection.h>
#include <DOM/IPortion.h>
#include <DOM/IPortionFormat.h>
#include <Export/SaveFormat.h>
#include <drawing/color.h>
#include <system/object_ext.h>
#include <system/smart_ptr.h>
#include <system/string.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
using namespace System;
using namespace System::Drawing;
auto presentation = MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::ClusteredColumn, 40, 40, 640, 200);
chart->set_HasTitle(false);
chart->set_HasLegend(false);
chart->get_TextFormat()->get_PortionFormat()->set_FontHeight(12);
chart->get_ChartData()->get_Series()->Clear();
chart->get_ChartData()->get_Categories()->Clear();
auto workbook = chart->get_ChartData()->get_ChartDataWorkbook();
workbook->Clear(0);
String categories[] = { u"North", u"South", u"East", u"West" };
String seriesNames[] = { u"Series A", u"Series B", u"Series C" };
double seriesValues[3][4] = {
{ 35, 42, 28, 47 },
{ 22, 31, 19, 26 },
{ 12, 16, 14, 18 }
};
for (auto categoryIndex = 0; categoryIndex < 4; categoryIndex++)
{
auto categoryCell = workbook->GetCell(0, categoryIndex + 1, 0, ObjectExt::Box(categories[categoryIndex]));
chart->get_ChartData()->get_Categories()->Add(categoryCell);
}
for (auto seriesIndex = 0; seriesIndex < 3; seriesIndex++)
{
auto seriesCell = workbook->GetCell(0, 0, seriesIndex + 1, ObjectExt::Box(seriesNames[seriesIndex]));
auto series = chart->get_ChartData()->get_Series()->Add(seriesCell, ChartType::ClusteredColumn);
for (auto categoryIndex = 0; categoryIndex < 4; categoryIndex++)
{
auto valueCell = workbook->GetCell(0, categoryIndex + 1, seriesIndex + 1, ObjectExt::Box(seriesValues[seriesIndex][categoryIndex]));
series->get_DataPoints()->AddDataPointForBarSeries(valueCell);
}
if (seriesIndex > 0)
{
// 隐藏 B 和 C 的柱形,但保留它们的数据标签。
series->get_Format()->get_Fill()->set_FillType(FillType::NoFill);
series->get_Format()->get_Line()->get_FillFormat()->set_FillType(FillType::NoFill);
auto labelFormat = series->get_Labels()->get_DefaultDataLabelFormat();
labelFormat->set_ShowValue(true);
labelFormat->get_TextFormat()->get_PortionFormat()->set_FontHeight(12);
auto labelFill = labelFormat->get_TextFormat()->get_PortionFormat()->get_FillFormat();
labelFill->set_FillType(FillType::Solid);
labelFill->get_SolidFillColor()->set_Color(Color::get_Black());
labelFormat->set_Position(LegendDataLabelPosition::InsideBase);
}
}
// 将所有三个系列对齐到相同的类目中心。
chart->get_ChartData()->get_Series()->idx_get(0)->get_ParentSeriesGroup()->set_Overlap(100);
// 在此紧凑示例中使用更少的网格线。
chart->get_Axes()->get_VerticalAxis()->set_IsAutomaticMajorUnit(false);
chart->get_Axes()->get_VerticalAxis()->set_MajorUnit(10);
// 在绘图区上方预留空间用于两行数据标签。
chart->get_PlotArea()->set_LayoutTargetType(LayoutTargetType::Inner);
chart->get_PlotArea()->set_X(0.15f);
chart->get_PlotArea()->set_Y(0.32f);
chart->get_PlotArea()->set_Width(0.80f);
chart->get_PlotArea()->set_Height(0.48f);
chart->ValidateChartLayout();
for (auto seriesIndex = 1; seriesIndex < 3; seriesIndex++)
{
auto series = chart->get_ChartData()->get_Series()->idx_get(seriesIndex);
auto rowTop = seriesIndex == 1 ? 0.15f : 0.03f;
for (auto categoryIndex = 0; categoryIndex < 4; categoryIndex++)
{
auto dataLabel = series->get_DataPoint(categoryIndex)->get_Label();
// 保持默认的水平位置。Y 是相对于
// 默认标签位置的偏移,以图表高度的比例表示。
dataLabel->set_X(0);
dataLabel->set_Y(rowTop - dataLabel->get_ActualY() / chart->get_Height());
}
// 只有行标题是单独的文本形状。
auto rowHeading = slide->get_Shapes()->AddAutoShape(ShapeType::Rectangle, chart->get_X(), chart->get_Y() + rowTop * chart->get_Height(), 85, 18);
rowHeading->get_FillFormat()->set_FillType(FillType::NoFill);
rowHeading->get_LineFormat()->get_FillFormat()->set_FillType(FillType::NoFill);
rowHeading->AddTextFrame(seriesNames[seriesIndex]);
rowHeading->get_TextFrame()->get_TextFrameFormat()->set_MarginTop(0);
rowHeading->get_TextFrame()->get_TextFrameFormat()->set_MarginBottom(0);
auto headingFormat = rowHeading->get_TextFrame()->get_Paragraphs()->idx_get(0)->get_Portions()->idx_get(0)->get_PortionFormat();
headingFormat->set_FontHeight(12);
headingFormat->get_FillFormat()->set_FillType(FillType::Solid);
headingFormat->get_FillFormat()->get_SolidFillColor()->set_Color(Color::get_Black());
}
presentation->Save(u"multiple-rows-of-labels.pptx", SaveFormat::Pptx);

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

