在 Python 中格式化演示文稿图表
概述
本文说明如何在 PowerPoint 演示文稿中使用 Aspose.Slides 对图表进行格式化。它展示了如何自定义轴、网格线、标题、图例、绘图区域和墙面填充等关键图表元素,以提升图表数据的外观和可读性。
还演示了如何为图表文本设置字体属性、对图表数据应用预设数字格式以及为图表区域启用圆角。通过这些示例,可控制演示文稿中图表的视觉样式和数据展示。
格式化图表实体
使用 图表 来格式化图表标题、轴、网格线、图例和绘图区域。此示例创建了一个带标记的折线图并使用默认数据,然后分别为其数值轴和类别轴应用不同的文字和线条样式。字体大小和线宽以磅为单位;类别标签旋转 45 度。
数值轴使用 setNumberFormat 独立于源单元格。其刻度范围为 -2 到 15,主刻度间隔为 2,次刻度间隔为 0.5。示例还将百分比格式与 setDisplayUnit 设置为千位相结合,您可根据数据的意义和量级自行调整这些设置。图例因调用 False 的 setOverlay 而位于绘图区域外。通过 getBackWall 和 getFloor 配置背墙和地板填充,但这些表面仅在 3D 图表中可见。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, DisplayUnitType, FillType, FontData, LineDashStyle, NullableBool, Presentation, PresetColor, SaveFormat, TickLabelPositionType
Color = jpype.JClass("java.awt.Color")
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(0)
chart = slide.getShapes().addChart(ChartType.LineWithMarkers, 50, 50, 500, 400)
chart.setTitle(True)
chart.getChartTitle().addTextFrameForOverriding("")
chart_title = chart.getChartTitle().getTextFrameForOverriding().getParagraphs().get_Item(0).getPortions().get_Item(0)
chart_title.setText("Sample Chart")
chart_title.getPortionFormat().getFillFormat().setFillType(FillType.Solid)
chart_title.getPortionFormat().getFillFormat().getSolidFillColor().setColor(Color.GRAY)
chart_title.getPortionFormat().setFontHeight(20)
chart_title.getPortionFormat().setFontBold(NullableBool.True_)
chart_title.getPortionFormat().setFontItalic(NullableBool.True_)
chart.getAxes().getVerticalAxis().getMajorGridLinesFormat().getLine().getFillFormat().setFillType(FillType.Solid)
chart.getAxes().getVerticalAxis().getMajorGridLinesFormat().getLine().getFillFormat().getSolidFillColor().setColor(Color.BLUE)
chart.getAxes().getVerticalAxis().getMajorGridLinesFormat().getLine().setWidth(5)
chart.getAxes().getVerticalAxis().getMajorGridLinesFormat().getLine().setDashStyle(LineDashStyle.DashDot)
chart.getAxes().getVerticalAxis().getMinorGridLinesFormat().getLine().getFillFormat().setFillType(FillType.Solid)
chart.getAxes().getVerticalAxis().getMinorGridLinesFormat().getLine().getFillFormat().getSolidFillColor().setColor(Color.RED)
chart.getAxes().getVerticalAxis().getMinorGridLinesFormat().getLine().setWidth(3)
chart.getAxes().getVerticalAxis().setNumberFormatLinkedToSource(False)
chart.getAxes().getVerticalAxis().setDisplayUnit(DisplayUnitType.Thousands)
chart.getAxes().getVerticalAxis().setNumberFormat("0.0%")
chart.getAxes().getVerticalAxis().setAutomaticMajorUnit(False)
chart.getAxes().getVerticalAxis().setAutomaticMaxValue(False)
chart.getAxes().getVerticalAxis().setAutomaticMinorUnit(False)
chart.getAxes().getVerticalAxis().setAutomaticMinValue(False)
chart.getAxes().getVerticalAxis().setMaxValue(15)
chart.getAxes().getVerticalAxis().setMinValue(-2)
chart.getAxes().getVerticalAxis().setMinorUnit(0.5)
chart.getAxes().getVerticalAxis().setMajorUnit(2.0)
value_axis_text = chart.getAxes().getVerticalAxis().getTextFormat().getPortionFormat()
value_axis_text.setFontBold(NullableBool.True_)
value_axis_text.setFontHeight(16)
value_axis_text.setFontItalic(NullableBool.True_)
value_axis_text.getFillFormat().setFillType(FillType.Solid)
value_axis_text.getFillFormat().getSolidFillColor().setPresetColor(PresetColor.DarkGreen)
value_axis_font = FontData("Times New Roman")
value_axis_text.setLatinFont(value_axis_font)
chart.getAxes().getVerticalAxis().setTitle(True)
chart.getAxes().getVerticalAxis().getTitle().addTextFrameForOverriding("")
value_axis_title = chart.getAxes().getVerticalAxis().getTitle().getTextFrameForOverriding().getParagraphs().get_Item(0).getPortions().get_Item(0)
value_axis_title.setText("Primary Axis")
value_axis_title.getPortionFormat().getFillFormat().setFillType(FillType.Solid)
value_axis_title.getPortionFormat().getFillFormat().getSolidFillColor().setColor(Color.GRAY)
value_axis_title.getPortionFormat().setFontHeight(20)
value_axis_title.getPortionFormat().setFontBold(NullableBool.True_)
value_axis_title.getPortionFormat().setFontItalic(NullableBool.True_)
chart.getAxes().getHorizontalAxis().getMajorGridLinesFormat().getLine().getFillFormat().setFillType(FillType.Solid)
category_grid_color = Color(0, 128, 0)
chart.getAxes().getHorizontalAxis().getMajorGridLinesFormat().getLine().getFillFormat().getSolidFillColor().setColor(category_grid_color)
chart.getAxes().getHorizontalAxis().getMajorGridLinesFormat().getLine().setWidth(5)
chart.getAxes().getHorizontalAxis().getMinorGridLinesFormat().getLine().getFillFormat().setFillType(FillType.Solid)
chart.getAxes().getHorizontalAxis().getMinorGridLinesFormat().getLine().getFillFormat().getSolidFillColor().setColor(Color.YELLOW)
chart.getAxes().getHorizontalAxis().getMinorGridLinesFormat().getLine().setWidth(3)
category_axis_text = chart.getAxes().getHorizontalAxis().getTextFormat().getPortionFormat()
category_axis_text.setFontBold(NullableBool.True_)
category_axis_text.setFontHeight(16)
category_axis_text.setFontItalic(NullableBool.True_)
category_axis_text.getFillFormat().setFillType(FillType.Solid)
category_axis_text.getFillFormat().getSolidFillColor().setColor(Color.BLUE)
category_axis_font = FontData("Arial")
category_axis_text.setLatinFont(category_axis_font)
chart.getAxes().getHorizontalAxis().setTitle(True)
chart.getAxes().getHorizontalAxis().getTitle().addTextFrameForOverriding("")
category_axis_title = chart.getAxes().getHorizontalAxis().getTitle().getTextFrameForOverriding().getParagraphs().get_Item(0).getPortions().get_Item(0)
category_axis_title.setText("Sample Category")
category_axis_title.getPortionFormat().getFillFormat().setFillType(FillType.Solid)
category_axis_title.getPortionFormat().getFillFormat().getSolidFillColor().setColor(Color.GRAY)
category_axis_title.getPortionFormat().setFontHeight(20)
category_axis_title.getPortionFormat().setFontBold(NullableBool.True_)
category_axis_title.getPortionFormat().setFontItalic(NullableBool.True_)
chart.getAxes().getHorizontalAxis().setTickLabelPosition(TickLabelPositionType.Low)
chart.getAxes().getHorizontalAxis().setTickLabelRotationAngle(45)
legend_text = chart.getLegend().getTextFormat().getPortionFormat()
legend_text.setFontBold(NullableBool.True_)
legend_text.setFontHeight(16)
legend_text.setFontItalic(NullableBool.True_)
legend_text.getFillFormat().setFillType(FillType.Solid)
legend_text.getFillFormat().getSolidFillColor().setPresetColor(PresetColor.DarkRed)
chart.getLegend().setOverlay(False)
chart.getBackWall().setThickness(1)
chart.getBackWall().getFormat().getFill().setFillType(FillType.Solid)
back_wall_color = Color(255, 165, 0)
chart.getBackWall().getFormat().getFill().getSolidFillColor().setColor(back_wall_color)
chart.getFloor().getFormat().getFill().setFillType(FillType.Solid)
chart.getFloor().getFormat().getFill().getSolidFillColor().setColor(Color.RED)
chart.getPlotArea().getFormat().getFill().setFillType(FillType.Solid)
chart.getPlotArea().getFormat().getFill().getSolidFillColor().setPresetColor(PresetColor.LightCyan)
presentation.save("FormattedChart_out.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
设置图表的字体属性
通过 Chart.getTextFormat 设置图表文本的默认字体大小。示例创建了一个簇状柱形图,默认字体为 20 磅,并通过 setShowValue 为第一系列启用数值标签。具有显式字体设置的文字元素可以覆盖图表默认设置。
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, 100, 100, 500, 400)
chart.getTextFormat().getPortionFormat().setFontHeight(20)
chart.getChartData().getSeries().get_Item(0).getLabels().getDefaultDataLabelFormat().setShowValue(True)
presentation.save("FontPropertiesForChart.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
设置数值格式
使用 ChartDataCell.setPresetNumberFormat 为图表工作簿单元格应用内置数字格式。此示例创建了一个簇状柱形图,使用默认的基于单元格的数据,并为每个系列的数值单元格应用格式索引 10(0.00%)。这会改变工作簿中数值的显示方式,而不改变其底层数值;例如,0.25 将显示为 25.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.ClusteredColumn, 50, 50, 500, 400)
chart_series_collection = chart.getChartData().getSeries()
for chart_series in chart_series_collection:
for data_point in chart_series.getDataPoints():
data_point.getValue().getAsCell().setPresetNumberFormat(jpype.JByte(10)) # 0.00%
presentation.save("PresetNumberFormat_out.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
以下表格列出了内置数字格式索引及其在美国英语地区的代表性 Excel 格式。具体的格式字符串及显示方式可能随应用程序和地区而异,尤其是货币和日期。一些 Excel 格式也与 OOXML 标准的默认值不同,详见 Microsoft 的数字格式实现说明。
| 索引 | 格式 |
|---|---|
| 0 | General |
| 1 | 0 |
| 2 | 0.00 |
| 3 | #,##0 |
| 4 | #,##0.00 |
| 5 | "$"#,##0_);("$"#,##0) |
| 6 | "$"#,##0_);[Red]("$"#,##0) |
| 7 | "$"#,##0.00_);("$"#,##0.00) |
| 8 | "$"#,##0.00_);[Red]("$"#,##0.00) |
| 9 | 0% |
| 10 | 0.00% |
| 11 | 0.00E+00 |
| 12 | # ?/? |
| 13 | # ??/?? |
| 14 | m/d/yyyy |
| 15 | d-mmm-yy |
| 16 | d-mmm |
| 17 | mmm-yy |
| 18 | h:mm AM/PM |
| 19 | h:mm:ss AM/PM |
| 20 | h:mm |
| 21 | h:mm:ss |
| 22 | m/d/yyyy h:mm |
| 37 | #,##0_);(#,##0) |
| 38 | #,##0_);[Red](#,##0) |
| 39 | #,##0.00_);(#,##0.00) |
| 40 | #,##0.00_);[Red](#,##0.00) |
| 41 | _(* #,##0_);_(* (#,##0);_(* "-"_);_(@_) |
| 42 | _("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_) |
| 43 | _(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_) |
| 44 | _("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_) |
| 45 | mm:ss |
| 46 | [h]:mm:ss |
| 47 | mm:ss.0 |
| 48 | ##0.0E+0 |
| 49 | @ |
设置图表区域圆角边框
调用 Chart.setRoundedCorners 并传入 True 可为图表区域的四角设置圆角。示例创建了一个簇状柱形图,并使用 getLineFormat 为其轮廓指定了实心灰色和单线样式,然后保存演示文稿。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import ChartType, FillType, LineStyle, Presentation, SaveFormat
Color = jpype.JClass("java.awt.Color")
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(0)
chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 100, 600, 400)
chart.getLineFormat().getFillFormat().setFillType(FillType.Solid)
chart.getLineFormat().getFillFormat().getSolidFillColor().setColor(Color.GRAY)
chart.getLineFormat().setStyle(LineStyle.Single)
chart.setRoundedCorners(True)
presentation.save("out.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
编辑现有的图表批注
图表可以包含自定义形状,例如用于说明报告状态的文本批注。通过 Chart.getUserShapes 访问这些形状。由 getShapes 返回的集合包含图表拥有的形状。
放置在图表之上的普通文本框属于幻灯片,即使它看起来像图表的一部分。遍历 Slide.getShapes 可以找到图表和普通幻灯片形状,但不会枚举图表内部的单个形状。图表标题和数据标签是独立的图表元素,而不是该集合中的自定义批注。
下载 chart-annotations.pptx 并将其放在应用程序的工作目录中。其第一张幻灯片包含一个带有未分组批注 “Preliminary results”、图表拥有的线条以及普通幻灯片文本框 “Slide overlay” 的图表。示例在该幻灯片上找到第一张图表,并在报告准备发布时将批注改为 “Final results”。它会检查集合是否为空,并仅编辑通过 getTextFrame 返回的非 None 文本框的 AutoShape,以及符合预期文本的形状。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import AutoShape, Chart, Presentation, SaveFormat
presentation = Presentation("chart-annotations.pptx")
try:
slide = presentation.getSlides().get_Item(0)
chart = None
for shape in slide.getShapes():
if isinstance(shape, Chart):
chart = shape
break
if chart is None or chart.getUserShapes().getShapes().size() == 0:
print("No chart or chart-owned shapes found.")
else:
updated = False
for shape in chart.getUserShapes().getShapes():
if isinstance(shape, AutoShape):
text_frame = shape.getTextFrame()
if text_frame is not None and text_frame.getText() == "Preliminary results":
text_frame.setText("Final results")
updated = True
break
if updated:
presentation.save("chart-annotations-updated.pptx", SaveFormat.Pptx)
else:
print("No matching text annotation found.")
finally:
presentation.dispose()
线条和幻灯片文本框保持不变。以下图片展示了编辑前后的结果:
| 编辑前 | 编辑后 |
|---|---|
![]() |
![]() |
Note
示例仅检查顶层的图表拥有形状。如果批注位于 GroupShape 中,需要同时检查该组的 getShapes 集合。对嵌套组递归执行相同的文本检查,对其子形状应用相同的逻辑。组本身是一个容器,不应将其视为文本框。常见问题
我可以在保持边框不透明的情况下为柱形/区域设置半透明填充吗?
可以。填充透明度和轮廓是分开配置的。这在密集可视化中有助于提升网格和数据的可读性。
当数据标签重叠时该怎么办?
可以减小字体大小,关闭非必要的标签组件(例如类别),调整标签位置,必要时仅为选定点显示标签,或切换为 “数值 + 图例” 格式。
我可以为系列应用渐变或图案填充吗?
可以。系列支持纯色、渐变和图案填充。实际使用时建议少用渐变,并避免与网格和文字形成对比度不足的组合。

