在 Python 中格式化簡報圖表
概覽
本文說明了如何使用 Aspose.Slides 在 PowerPoint 簡報中格式化圖表。它展示了如何自訂坐標軸、格線、標題、圖例、繪圖區域以及牆面填色等關鍵圖表元素,以提升圖表資料的外觀與可讀性。
此外,還示範了如何設定圖表文字的字型屬性、將預設數字格式套用至圖表資料,以及為圖表區域啟用圓角。這些範例共同說明了如何同時控制圖表的視覺樣式與資料呈現方式。
格式化圖表實體
使用圖表來格式化圖表標題、坐標軸、格線、圖例與繪圖區域。本範例建立一個帶有標記的折線圖與預設資料,然後對其值軸與類別軸分別套用不同的文字與線條樣式。字型大小與線條寬度以點為單位;類別標籤旋轉 45 度。
值軸使用setNumberFormat獨立於來源儲存格。其比例範圍為 -2 到 15,主間隔為 2,次間隔為 0.5。範例同時結合百分比格式與setDisplayUnit設定為千位,請依據資料的意義與量級調整這些設定。圖例因呼叫setOverlay 並傳入False 而位於繪圖區域之外。背牆與底面填色透過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 集合。對於巢狀群組,請以相同方式遞迴檢查其子圖形,並對子圖形執行相同的文字檢查。群組本身僅是容器,請勿將其當作文字方塊處理。常見問題
我可以為柱狀圖/面積圖設定半透明填色,同時保持邊框不透明嗎?
可以。填色透明度與輪廓是分開設定的。此方式有助於在密集的視覺化圖表中提升格線與資料的可讀性。
當資料標籤彼此重疊時,我該怎麼處理?
可以縮小字型、停用非必要的標籤元件(例如類別)、調整標籤位置、必要時僅為選取的資料點顯示標籤,或改為「值 + 圖例」的格式。
我可以為系列套用漸層或圖案填色嗎?
可以。系列支援實心、漸層與圖案填色。實務上建議謹慎使用漸層,並避免使用會降低格線與文字對比度的組合。

