使用 Python 在演示文稿中管理图表数据标签
Introduction
数据标签显示有关图表系列和各个数据点的信息,帮助读者识别数值并理解图表。本文说明了如何格式化数值、显示百分比、读取标签文本、控制超出轴最大值的标签、调整类别轴标签间距以及设置饼图标签的位置。
在图表数据标签中设置数据精度
使用 setNumberFormatOfValues 来格式化系列数值。此示例创建一个具有默认数据的折线图,显示其数据表,并为第一系列启用数值标签。格式 #,##0.00 显示千位分隔符和两位小数,而不会更改底层数值。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, Presentation, SaveFormat
presentation = 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 磅字体下显示两位小数的百分比。总和为零的类别会被跳过,以避免除以零。如果图表数据发生变化,需要重新计算自定义标签文本。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, Portion, Presentation, SaveFormat
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(0)
chart = slide.getShapes().addChart(ChartType.StackedColumn, 20, 20, 400, 400)
chart_series = chart.getChartData().getSeries()
category_totals = [0.0] * chart.getChartData().getCategories().size()
for category_index in range(len(category_totals)):
for series_index in range(chart_series.size()):
data_point = chart_series.get_Item(series_index).getDataPoints().get_Item(category_index)
category_totals[category_index] += float(data_point.getValue().getData())
for series_index in range(chart_series.size()):
series = chart_series.get_Item(series_index)
series.getLabels().getDefaultDataLabelFormat().setShowLegendKey(False)
for point_index in range(series.getDataPoints().size()):
data_point = series.getDataPoints().get_Item(point_index)
label = data_point.getLabel()
if category_totals[point_index] == 0:
print(f"Cannot calculate a percentage for category {point_index}: the total is zero.")
continue
point_percentage = float(data_point.getValue().getData()) / category_totals[point_index] * 100
portion = Portion()
portion.setText(f"{point_percentage:.2f} %")
portion.getPortionFormat().setFontHeight(8)
label.getTextFrameForOverriding().setText("")
paragraph = label.getTextFrameForOverriding().getParagraphs().get_Item(0)
paragraph.getPortions().add(portion)
label_format = label.getDataLabelFormat()
label_format.setShowValue(True)
label_format.setShowSeriesName(False)
label_format.setShowPercentage(False)
label_format.setShowLegendKey(False)
label_format.setShowCategoryName(False)
label_format.setShowBubbleSize(False)
presentation.save("DisplayPercentageAsLabels_out.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
使用图表数据标签设置百分号
当数值以分数形式存储时,使用 setNumberFormat 来显示百分比。向 setNumberFormatLinkedToSource 传入 False,以使标签格式独立于源单元格。
此示例创建一个 100% 堆积柱形图,包含跨四个类别的红色和蓝色系列。每对数值加总为 1。标签格式 0.0% 将 0.30 显示为 30.0%,而垂直轴使用两位小数。两个系列的标签文字均为白色、10 磅。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, FillType, Presentation, SaveFormat
Color = jpype.JClass("java.awt.Color")
presentation = 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()
worksheet_index = 0
for i in range(4):
category_cell = workbook.getCell(worksheet_index, i + 1, 0, f"Category {i + 1}")
chart.getChartData().getCategories().add(category_cell)
series_names = ["Reds", "Blues"]
series_colors = [Color.RED, Color.BLUE]
values = [[0.30, 0.50, 0.80, 0.65], [0.70, 0.50, 0.20, 0.35]]
for i, series_name in enumerate(series_names):
series_cell = workbook.getCell(worksheet_index, 0, i + 1, series_name)
series = chart.getChartData().getSeries().add(series_cell, chart.getType())
for j, value in enumerate(values[i]):
value_cell = workbook.getCell(worksheet_index, j + 1, i + 1, jpype.JDouble(value))
series.getDataPoints().addDataPointForBarSeries(value_cell)
series.getFormat().getFill().setFillType(FillType.Solid)
series.getFormat().getFill().getSolidFillColor().setColor(series_colors[i])
label_format = series.getLabels().getDefaultDataLabelFormat()
label_format.setShowValue(True)
label_format.setNumberFormatLinkedToSource(False)
label_format.setNumberFormat("0.0%")
portion_format = label_format.getTextFormat().getPortionFormat()
portion_format.setFontHeight(10)
portion_format.getFillFormat().setFillType(FillType.Solid)
portion_format.getFillFormat().getSolidFillColor().setColor(Color.WHITE)
presentation.save("SetDataLabelsPercentageSign_out.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
读取数据标签的实际文本
使用 getActualLabelText 来获取数据标签设置生成的文本。这在提取报告标签、搜索演示文稿内容或验证生成的图表时非常有用。在下面的示例中,默认的 data label format 将每个类别名称、系列名称和数值组合在一起。一个点将其数值格式化为百分比,另一个则使用来自 getTextFrameForOverriding 的自定义文本。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, Presentation
presentation = 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()
first_category_cell = workbook.getCell(0, 1, 0, "Q1")
chart.getChartData().getCategories().add(first_category_cell)
second_category_cell = workbook.getCell(0, 2, 0, "Q2")
chart.getChartData().getCategories().add(second_category_cell)
north_series_cell = workbook.getCell(0, 0, 1, "North")
north = chart.getChartData().getSeries().add(north_series_cell, chart.getType())
north_first_value_cell = workbook.getCell(0, 1, 1, jpype.JDouble(0.25))
north.getDataPoints().addDataPointForBarSeries(north_first_value_cell)
north_second_value_cell = workbook.getCell(0, 2, 1, jpype.JDouble(0.75))
north.getDataPoints().addDataPointForBarSeries(north_second_value_cell)
south_series_cell = workbook.getCell(0, 0, 2, "South")
south = chart.getChartData().getSeries().add(south_series_cell, chart.getType())
south_first_value_cell = workbook.getCell(0, 1, 2, jpype.JDouble(0.40))
south.getDataPoints().addDataPointForBarSeries(south_first_value_cell)
south_second_value_cell = workbook.getCell(0, 2, 2, jpype.JDouble(0.60))
south.getDataPoints().addDataPointForBarSeries(south_second_value_cell)
for series in chart.getChartData().getSeries():
label_format = series.getLabels().getDefaultDataLabelFormat()
label_format.setShowCategoryName(True)
label_format.setShowSeriesName(True)
label_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 series in chart.getChartData().getSeries():
for point in series.getDataPoints():
label = point.getLabel()
if not label.isVisible():
continue
print(f"Value: {point.getValue().getData()}; label: {label.getActualLabelText()}")
finally:
presentation.dispose()
数据点中存储的数值仍为 0.75,即使其标签显示为 75% 并附带类别和系列名称。自定义文本会替代生成的标签文本。无论哪种情况,getActualLabelText 都会返回结果标签字符串。当您只想提取可见标签时,请单独检查 isVisible,如上所示。
控制超出轴最大值的数据标签
当您手动限制轴范围时,某些数据点可能超过其最大值。使用 setShowDataLabelsOverMaximum 来控制是否显示这些数据标签。此设置更改标签可见性,但不修改轴范围或底层数据值。
下面的示例创建一个 2D 群集柱形图,数值为 60 和 120。它向 setAutomaticMaxValue 传入 False,并在垂直轴上使用 setMaxValue 将最大值设为 100。第一张幻灯片允许标签超出最大值;该幻灯片的复制版则禁用这些标签。两张幻灯片均保存为 DataLabelsOverMaximum.pptx。
使用 setShowValue 启用数值标签。图表级别的设置本身并不会启用数值显示,也不会覆盖单个标签已禁用的数值显示。此示例为整个系列启用数值,并使用 setPosition 将标签放置在每根柱形的外侧端点。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, LegendDataLabelPosition, Presentation, SaveFormat
presentation = 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()
first_category = workbook.getCell(0, 1, 0, "Within range")
second_category = workbook.getCell(0, 2, 0, "Above maximum")
chart.getChartData().getCategories().add(first_category)
chart.getChartData().getCategories().add(second_category)
series_name = workbook.getCell(0, 0, 1, "Values")
series = chart.getChartData().getSeries().add(series_name, chart.getType())
first_value = workbook.getCell(0, 1, 1, jpype.JDouble(60))
second_value = workbook.getCell(0, 2, 1, jpype.JDouble(120))
series.getDataPoints().addDataPointForBarSeries(first_value)
series.getDataPoints().addDataPointForBarSeries(second_value)
series.getLabels().getDefaultDataLabelFormat().setShowValue(True)
series.getLabels().getDefaultDataLabelFormat().setPosition(LegendDataLabelPosition.OutsideEnd)
chart.getAxes().getVerticalAxis().setAutomaticMaxValue(False)
chart.getAxes().getVerticalAxis().setMaxValue(100)
chart.setShowDataLabelsOverMaximum(True)
second_slide = presentation.getSlides().addClone(slide)
second_chart = second_slide.getShapes().get_Item(0)
second_chart.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。此设置影响类别轴标签,而非附加在单个数据点上的标签。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, Presentation, SaveFormat
presentation = 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 调整其水平和垂直偏移。这些偏移分别相对于图表的宽度和高度。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, LegendDataLabelPosition, Presentation, SaveFormat
presentation = 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()

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

