在 Python 中管理演示文稿的图表数据系列
概述
图表将其绘制的数据存储在图表数据工作簿中。ChartSeries 表示一组相关值,系列中的每个 ChartDataPoint 引用一个或多个工作簿单元格。ChartCategory 对象提供系列共享的标签或分组值。因此,系列名称、类别和数据点值连接到 ChartDataCell 对象,而不是仅以显示文本形式存储。
对于典型的分类图表,默认工作簿使用第 0 行存放系列名称,第 0 列存放类别名称,其余单元格用于系列值。传递给 ChartDataWorkbook.getCell 的工作表、行和列索引采用零基计数。此布局在创建带默认数据的图表时很有用,但不要假设每个现有图表都使用它。对于已加载的演示文稿,在更改工作簿值之前,请检查系列、类别和数据点引用的单元格。
图表设置有三种不同的作用范围:
- 系列级设置,例如 ChartSeries.getFormat,为单个系列中的所有数据点提供默认外观。
- 数据点级设置,例如 ChartDataPoint.getFormat,覆盖该点的系列外观。
- 组设置适用于属于同一 ChartSeriesGroup 的兼容系列。当需要设置如重叠或间隔宽度等选项时,可通过 ChartSeries.getParentSeriesGroup 访问该组。
当未设置显式的数据点或系列填充时,图表样式和主题决定自动外观。当系列和数据点的格式均存在时,以数据点的格式为该点的优先级。

设置图表系列的重叠
ChartSeries.getOverlap 报告 2D 图表中条形或柱形的重叠程度,范围为 -100% 到 100%。它是父系列组设置的只读投影。使用 ChartSeriesGroup.setOverlap 可更新该组中所有兼容系列。此选项适用于显示分组条形或柱形的图表类型;它不会影响组合图表中不相关的系列组。
以下示例为包含第一个系列的组设置重叠:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, Presentation, SaveFormat
first_slide_index = 0
first_series_index = 0
overlap_percent = 30
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(first_slide_index)
# 新图表包含示例系列、类别和数值。
chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200)
series = chart.getChartData().getSeries().get_Item(first_series_index)
series.getParentSeriesGroup().setOverlap(overlap_percent)
presentation.save("series_overlap.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
结果如下:

更改系列填充颜色
使用 ChartSeries.getFormat 为整个系列设置默认填充。如果某个数据点已经具有显式填充,则其 ChartDataPoint.getFormat 设置会覆盖该点的系列填充。
以下示例为第一个系列应用实心蓝色填充:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, FillType, Presentation, SaveFormat
Color = jpype.JClass("java.awt.Color")
first_slide_index = 0
first_series_index = 0
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(first_slide_index)
chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200)
series = chart.getChartData().getSeries().get_Item(first_series_index)
series.getFormat().getFill().setFillType(FillType.Solid)
series.getFormat().getFill().getSolidFillColor().setColor(Color.BLUE)
presentation.save("series_color.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
结果如下:

更改系列名称
系列名称存储在图表数据工作簿中,通常显示在图例中。在为聚类柱形图创建的默认工作簿中,单元格 B1 位于第 0 行第 1 列,包含第一个系列的名称。以下示例中的命名变量明确了该结构:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, Presentation, SaveFormat
first_slide_index = 0
worksheet_index = 0
series_name_row_index = 0
first_series_column_index = 1
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(first_slide_index)
chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200)
workbook = chart.getChartData().getChartDataWorkbook()
series_name_cell = workbook.getCell(worksheet_index, series_name_row_index, first_series_column_index)
series_name_cell.setValue("Revenue")
presentation.save("series_name.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
您也可以更新 ChartSeries.getName 已引用的单元格。此方法避免在现有图表中假设特定的行列位置:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, Presentation, SaveFormat
first_slide_index = 0
first_series_index = 0
first_name_cell_index = 0
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(first_slide_index)
chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200)
series = chart.getChartData().getSeries().get_Item(first_series_index)
series_name_cell = series.getName().getAsCells().get_Item(first_name_cell_index)
series_name_cell.setValue("Revenue")
presentation.save("series_name.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
结果如下:

获取自动系列填充颜色
ChartSeries.getAutomaticSeriesColor 返回根据系列索引和图表样式计算的颜色。当系列填充未明确定义时,将使用此颜色。调用该方法仅读取计算得到的颜色;不会分配新的填充。
以下示例打印每个默认系列的自动颜色:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, Presentation
first_slide_index = 0
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(first_slide_index)
chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200)
series_count = chart.getChartData().getSeries().size()
for series_index in range(series_count):
series = chart.getChartData().getSeries().get_Item(series_index)
automatic_color = series.getAutomaticSeriesColor()
print(f"Series {series_index}: {automatic_color}")
finally:
presentation.dispose()
默认图表样式的示例输出:
Series 0: java.awt.Color[r=79,g=129,b=189]
Series 1: java.awt.Color[r=192,g=80,b=77]
Series 2: java.awt.Color[r=155,g=187,b=89]
确切的颜色取决于图表样式和主题。
为图表系列设置负值填充颜色翻转
对于条形、柱形和气泡系列,ChartSeries.setInvertIfNegative 可以为负值显示不同的填充。将常规系列填充设为实心,启用翻转,并通过 ChartSeries.getInvertedSolidFillColor 分配负值颜色。工作簿中的负数保持不变,仅其显示颜色会变化。
以下示例用单个系列替换默认图表数据。工作表第 0 行包含系列名称,第 0 列包含类别名称,第 1 列包含数值:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, FillType, Presentation, SaveFormat
Color = jpype.JClass("java.awt.Color")
first_slide_index = 0
worksheet_index = 0
header_row_index = 0
category_column_index = 0
first_series_column_index = 1
first_data_row_index = 1
category_names = ["Category 1", "Category 2", "Category 3"]
series_values = [-20, 50, -30]
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(first_slide_index)
chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200)
chart_data = chart.getChartData()
workbook = chart_data.getChartDataWorkbook()
chart_data.getSeries().clear()
chart_data.getCategories().clear()
series_name_cell = workbook.getCell(worksheet_index, header_row_index, first_series_column_index, "Series 1")
chart_type = chart.getType()
series = chart_data.getSeries().add(series_name_cell, chart_type)
for category_index in range(len(category_names)):
data_row_index = first_data_row_index + category_index
category_name = category_names[category_index]
series_value = series_values[category_index]
category_cell = workbook.getCell(worksheet_index, data_row_index, category_column_index, category_name)
chart_data.getCategories().add(category_cell)
value_cell = workbook.getCell(worksheet_index, data_row_index, first_series_column_index, series_value)
series.getDataPoints().addDataPointForBarSeries(value_cell)
automatic_series_color = series.getAutomaticSeriesColor()
series.getFormat().getFill().setFillType(FillType.Solid)
series.getFormat().getFill().getSolidFillColor().setColor(automatic_series_color)
series.setInvertIfNegative(True)
series.getInvertedSolidFillColor().setColor(Color.RED)
presentation.save("inverted_solid_fill_color.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
结果如下:

您可以通过 ChartDataPoint.setInvertIfNegative 为单个数据点启用翻转。在以下示例中,系列的翻转被禁用,仅对选中的数据点启用翻转。该点还被赋予负值,以便效果可见:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, FillType, Presentation, SaveFormat
Color = jpype.JClass("java.awt.Color")
first_slide_index = 0
first_series_index = 0
target_data_point_index = 2
negative_value = -30
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(first_slide_index)
chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200)
series = chart.getChartData().getSeries().get_Item(first_series_index)
automatic_series_color = series.getAutomaticSeriesColor()
series.getFormat().getFill().setFillType(FillType.Solid)
series.getFormat().getFill().getSolidFillColor().setColor(automatic_series_color)
series.getInvertedSolidFillColor().setColor(Color.RED)
series.setInvertIfNegative(False)
data_point = series.getDataPoints().get_Item(target_data_point_index)
data_point.getValue().getAsCell().setValue(negative_value)
data_point.setInvertIfNegative(True)
presentation.save("data_point_invert_color_if_negative.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
清除特定数据点的值
要使单个数据点为空而不删除其他点,请将其对应的工作簿单元格设为 None。对于柱形图,可通过 ChartDataPoint.getValue 获取绘制值。数据点仍保留在相同的类别位置,但图表会根据其空值设置将该值视为空白。
以下示例仅清除第一系列的第二个数据点:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, Presentation, SaveFormat
first_slide_index = 0
first_series_index = 0
target_data_point_index = 1
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(first_slide_index)
chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200)
series = chart.getChartData().getSeries().get_Item(first_series_index)
data_point = series.getDataPoints().get_Item(target_data_point_index)
data_point.getValue().getAsCell().setValue(None)
presentation.save("clear_data_point_value.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
散点图使用独立的 X 和 Y 单元格,气泡图还使用大小单元格。仅清除表示您想要移除的数值的单元格。若希望保留其他点,请勿调用 ChartDataPointCollection.clear,因为该方法会删除该系列中的所有数据点。
控制空单元格的显示
包含值的隐藏单元格与空单元格是不同的情况。要包含或排除隐藏工作表行列中的数据,请参阅包含隐藏行和列的数据。
空工作簿单元格表示缺失数据;包含 0 的单元格表示已知的数值。使用 ChartDataCell.setValue 并传入 None 可将单元格设为空。无论空单元格设置如何,数值零始终保持为零。
使用 Chart.setDisplayBlanksAs 选择图表如何显示空单元格。此设置适用于整个图表。它改变空白的绘制方式,而不将空工作簿单元格填充为零或插值。
以下独立示例创建一个带有单个系列的折线图,清除第 3 天的数值,并以每种模式保存相同的图表。无需输入文件。ChartDataWorkbook 使用工作表 0,列 0 作为类别标签,列 1 作为数值;第 0 行保存系列名称。最终数据为 10, 20, empty, 30, 40。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, DisplayBlanksAsType, Presentation, SaveFormat
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(0)
chart = slide.getShapes().addChart(ChartType.LineWithMarkers, 40, 40, 640, 400)
chart_data = chart.getChartData()
workbook = chart_data.getChartDataWorkbook()
chart_data.getSeries().clear()
chart_data.getCategories().clear()
series_name_cell = workbook.getCell(0, 0, 1, "Measurements")
series = chart_data.getSeries().add(series_name_cell, chart.getType())
values = [10, 20, 25, 30, 40]
for i, value in enumerate(values):
category_cell = workbook.getCell(0, i + 1, 0, f"Day {i + 1}")
chart_data.getCategories().add(category_cell)
value_cell = workbook.getCell(0, i + 1, 1, jpype.JInt(value))
series.getDataPoints().addDataPointForLineSeries(value_cell)
# 将第 3 天真正留空,同时保留其类别和数据点。
workbook.getCell(0, 3, 1).setValue(None)
modes = [DisplayBlanksAsType.Gap, DisplayBlanksAsType.Zero, DisplayBlanksAsType.Span]
mode_names = ["Gap", "Zero", "Span"]
for mode, mode_name in zip(modes, mode_names):
chart.setDisplayBlanksAs(mode)
presentation.save(f"empty_cells_{mode_name}.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
每个输出文件在保存前存储所分配的模式:empty_cells_Gap.pptx、empty_cells_Zero.pptx 和 empty_cells_Span.pptx。若只需保存一个版本,请在保存演示文稿前分配所需模式,而不是遍历所有模式。
下表比较展示了三个文件中相同的数据。在所有情况下,第 3 天在工作簿中均为空:

可见效果取决于图表类型。折线图可以轻松比较所有三种模式。柱形和条形图没有跨缺失类别的连线,因此 Span 无法产生上述连接段;缺失的柱形和高度为零的柱形也可能看起来相同。类似地,仅带标记的散点图没有连接线。不要期望每种图表类型都有三种截然不同的结果;请检查所使用图表类型的输出。
设置系列间隔宽度
间隔宽度是相邻条形或柱形簇之间的间距,以条形或柱形宽度的百分比表示。与重叠类似,它属于父系列组,而非单个系列。对该组调用一次 ChartSeriesGroup.setGapWidth 即可。值越大,簇之间的空间越大;值越小,簇则更紧密。
以下示例更改间隔宽度并仅保存最终演示文稿:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, Presentation, SaveFormat
first_slide_index = 0
first_series_index = 0
gap_width_percent = 30
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(first_slide_index)
chart = slide.getShapes().addChart(ChartType.StackedColumn, 20, 20, 500, 200)
series = chart.getChartData().getSeries().get_Item(first_series_index)
series.getParentSeriesGroup().setGapWidth(gap_width_percent)
presentation.save("gap_width_30.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
结果如下:

常见问题
哪些图表类型支持数据系列?
ChartType 枚举表示的所有图表类型都使用图表数据,但它们的系列并不具备相同的数值结构或设置。例如,分类图使用类别和数值,散点图使用 X 和 Y 数值,气泡图则额外使用气泡大小。请使用与系列类型相匹配的数据点创建方法。重叠和间隔宽度等选项仅适用于兼容的条形或柱形组。
什么是图表系列组?
ChartSeriesGroup 包含共享组级绘图设置的兼容系列。组合图表可以包含多个组,因此通过某个系列获取的组的更改不一定会影响图表中的所有系列。
新创建的图表是否包含默认数据?
是的。默认情况下,ShapeCollection.addChart 会创建示例系列、类别和数值。您可以编辑这些单元格,或在添加完全自定义的数据集之前清除系列和类别集合。某些重载也可以创建没有默认数据的图表。
图表对象如何与工作簿单元格关联?
系列名称、类别标签和数据点数值引用 ChartDataWorkbook 中的单元格。更改被引用的单元格会更新相应的图表元素。构建自定义数据时,请保持类别行和系列值行对齐,以便每个点在预期的类别下绘制。
如何只清除一个数据点而不是整个系列?
将相关的数值单元格设为 None,即可在保留该点类别位置的同时将其设为空点。仅在需要删除该系列所有数据点时才使用 ChartDataPointCollection.clear。如果同时删除了类别,请更新每个系列,使其数值仍与类别集合保持对齐。
空数据点如何显示?
结果取决于图表类型以及通过 Chart.setDisplayBlanksAs 配置的值。支持的图表可以将空白显示为间隙、零值或通过连接相邻点来显示。请选择与演示文稿中缺失数据含义相符的设置。参见“控制空单元格的显示”获取完整示例和可视化比较。
负值如何格式化?
对于支持的条形、柱形和气泡系列,调用 ChartSeries.setInvertIfNegative 并通过 ChartSeries.getInvertedSolidFillColor 设置返回的颜色。您也可以使用 ChartDataPoint.setInvertIfNegative 为单个数据点覆盖此行为。这些方法影响格式,而非存储的数值。
当系列和数据点都进行了格式化时,哪种格式优先?
显式的数据点格式在该点上优先。其他点继续使用显式的系列格式,或在未定义系列格式时使用自动的图表样式和主题。组设置(如重叠和间隔宽度)控制布局,并非点级别的格式覆盖。
图表可以包含的系列数量是否有限制?
Aspose.Slides 并未设定单独的系列数量上限。实际上,演示文件的限制、可用内存、渲染时间以及图表的可读性决定了实际可用的上限。
当柱形之间过于靠近或过于分散时该如何调整?
对相应的父系列组调用 ChartSeriesGroup.setGapWidth。增大该值可扩大簇之间的间距,减小则使簇更靠近。