使用 Java 管理簡報中的圖表資料標籤
簡介
資料標籤會顯示圖表系列與個別資料點的資訊,協助讀者辨識數值並了解圖表。本文說明如何格式化數值、以百分比顯示、讀取標籤文字、控制超出軸最大值的標籤、調整類別軸標籤間距,以及設定圓形圖標籤的位置。
設定圖表資料標籤的數據精度
使用setNumberFormatOfValues來格式化系列值。此範例建立一個使用預設資料的折線圖,顯示其資料表,並為第一個系列啟用值標籤。格式 #,##0.00 會在千位加上分隔符號並保留兩位小數,而不會更改底層的實際值。
import com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IChart chart = slide.getShapes().addChart(ChartType.Line, 50, 50, 450, 300);
chart.setDataTable(true);
IChartSeries 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 com.aspose.slides.*;
import java.util.Locale;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IChart chart = slide.getShapes().addChart(ChartType.StackedColumn, 20, 20, 400, 400);
double[] categoryTotals = new double[chart.getChartData().getCategories().size()];
for (int k = 0; k < chart.getChartData().getCategories().size(); k++) {
for (int i = 0; i < chart.getChartData().getSeries().size(); i++) {
IChartSeries series = chart.getChartData().getSeries().get_Item(i);
Number pointValue = (Number) series.getDataPoints().get_Item(k).getValue().getData();
categoryTotals[k] += pointValue.doubleValue();
}
}
for (int x = 0; x < chart.getChartData().getSeries().size(); x++) {
IChartSeries series = chart.getChartData().getSeries().get_Item(x);
series.getLabels().getDefaultDataLabelFormat().setShowLegendKey(false);
for (int j = 0; j < series.getDataPoints().size(); j++) {
IDataLabel label = series.getDataPoints().get_Item(j).getLabel();
if (categoryTotals[j] == 0) {
continue;
}
Number pointValue = (Number) series.getDataPoints().get_Item(j).getValue().getData();
double dataPointPercent = (pointValue.doubleValue() / categoryTotals[j]) * 100;
IPortion portion = new Portion();
portion.setText(String.format(Locale.US, "%.2f %%", dataPointPercent));
portion.getPortionFormat().setFontHeight(8f);
label.getTextFrameForOverriding().setText("");
IParagraph paragraph = label.getTextFrameForOverriding().getParagraphs().get_Item(0);
paragraph.getPortions().add(portion);
label.getDataLabelFormat().setShowValue(true);
label.getDataLabelFormat().setShowSeriesName(false);
label.getDataLabelFormat().setShowPercentage(false);
label.getDataLabelFormat().setShowLegendKey(false);
label.getDataLabelFormat().setShowCategoryName(false);
label.getDataLabelFormat().setShowBubbleSize(false);
}
}
presentation.save("DisplayPercentageAsLabels_out.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
使用圖表資料標籤設定百分比符號
當值以分數形式儲存時,使用setNumberFormat來顯示百分比。將 false 傳遞給setNumberFormatLinkedToSource,即可使標籤格式獨立於來源儲存格。
此範例建立一個 100% 堆疊直條圖,四個類別分別包含紅色與藍色系列。每對值的總和為 1。標籤格式 0.0% 會將 0.30 顯示為 30.0%,而垂直軸使用兩位小數。兩個系列皆使用白色、10 點的標籤文字。
import com.aspose.slides.*;
import java.awt.Color;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IChart 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();
IChartDataWorkbook workbook = chart.getChartData().getChartDataWorkbook();
int worksheetIndex = 0;
for (int i = 0; i < 4; i++) {
IChartDataCell categoryCell = workbook.getCell(worksheetIndex, i + 1, 0, "Category " + (i + 1));
chart.getChartData().getCategories().add(categoryCell);
}
String[] seriesNames = { "Reds", "Blues" };
Color[] seriesColors = { Color.RED, Color.BLUE };
double[][] values = { { 0.30, 0.50, 0.80, 0.65 }, { 0.70, 0.50, 0.20, 0.35 } };
for (int i = 0; i < seriesNames.length; i++) {
IChartDataCell seriesCell = workbook.getCell(worksheetIndex, 0, i + 1, seriesNames[i]);
IChartSeries series = chart.getChartData().getSeries().add(seriesCell, chart.getType());
for (int j = 0; j < 4; j++) {
IChartDataCell valueCell = workbook.getCell(worksheetIndex, j + 1, i + 1, values[i][j]);
series.getDataPoints().addDataPointForBarSeries(valueCell);
}
series.getFormat().getFill().setFillType(FillType.Solid);
series.getFormat().getFill().getSolidFillColor().setColor(seriesColors[i]);
IDataLabelFormat labelFormat = series.getLabels().getDefaultDataLabelFormat();
labelFormat.setShowValue(true);
labelFormat.setNumberFormatLinkedToSource(false);
labelFormat.setNumberFormat("0.0%");
labelFormat.getTextFormat().getPortionFormat().setFontHeight(10);
labelFormat.getTextFormat().getPortionFormat().getFillFormat().setFillType(FillType.Solid);
labelFormat.getTextFormat().getPortionFormat().getFillFormat().getSolidFillColor().setColor(Color.WHITE);
}
presentation.save("SetDataLabelsPercentageSign_out.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
讀取資料標籤的實際文字
使用getActualLabelText 取得由資料標籤設定產生的文字。這在擷取報表標籤、搜尋簡報內容或驗證產生的圖表時非常有用。以下範例中,預設的資料標籤格式會結合每個類別名稱、系列名稱與值。一個資料點將其值格式化為百分比,另一個則使用 getTextFrameForOverriding 取得的自訂文字。
import com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 300);
chart.getChartData().getSeries().clear();
chart.getChartData().getCategories().clear();
IChartDataWorkbook workbook = chart.getChartData().getChartDataWorkbook();
IChartDataCell firstCategoryCell = workbook.getCell(0, 1, 0, "Q1");
chart.getChartData().getCategories().add(firstCategoryCell);
IChartDataCell secondCategoryCell = workbook.getCell(0, 2, 0, "Q2");
chart.getChartData().getCategories().add(secondCategoryCell);
IChartDataCell northSeriesCell = workbook.getCell(0, 0, 1, "North");
IChartSeries north = chart.getChartData().getSeries().add(northSeriesCell, chart.getType());
IChartDataCell northFirstValueCell = workbook.getCell(0, 1, 1, 0.25);
north.getDataPoints().addDataPointForBarSeries(northFirstValueCell);
IChartDataCell northSecondValueCell = workbook.getCell(0, 2, 1, 0.75);
north.getDataPoints().addDataPointForBarSeries(northSecondValueCell);
IChartDataCell southSeriesCell = workbook.getCell(0, 0, 2, "South");
IChartSeries south = chart.getChartData().getSeries().add(southSeriesCell, chart.getType());
IChartDataCell southFirstValueCell = workbook.getCell(0, 1, 2, 0.40);
south.getDataPoints().addDataPointForBarSeries(southFirstValueCell);
IChartDataCell southSecondValueCell = workbook.getCell(0, 2, 2, 0.60);
south.getDataPoints().addDataPointForBarSeries(southSecondValueCell);
for (IChartSeries series : chart.getChartData().getSeries()) {
IDataLabelFormat format = series.getLabels().getDefaultDataLabelFormat();
format.setShowCategoryName(true);
format.setShowSeriesName(true);
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 (IChartSeries series : chart.getChartData().getSeries()) {
for (IChartDataPoint point : series.getDataPoints()) {
IDataLabel label = point.getLabel();
if (!label.isVisible()) {
continue;
}
System.out.println("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 com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 50, 50, 600, 400);
chart.setLegend(false);
chart.getChartData().getSeries().clear();
chart.getChartData().getCategories().clear();
IChartDataWorkbook workbook = chart.getChartData().getChartDataWorkbook();
IChartDataCell firstCategory = workbook.getCell(0, 1, 0, "Within range");
IChartDataCell secondCategory = workbook.getCell(0, 2, 0, "Above maximum");
chart.getChartData().getCategories().add(firstCategory);
chart.getChartData().getCategories().add(secondCategory);
IChartDataCell seriesName = workbook.getCell(0, 0, 1, "Values");
IChartSeries series = chart.getChartData().getSeries().add(seriesName, chart.getType());
IChartDataCell firstValue = workbook.getCell(0, 1, 1, 60);
IChartDataCell secondValue = workbook.getCell(0, 2, 1, 120);
series.getDataPoints().addDataPointForBarSeries(firstValue);
series.getDataPoints().addDataPointForBarSeries(secondValue);
series.getLabels().getDefaultDataLabelFormat().setShowValue(true);
series.getLabels().getDefaultDataLabelFormat().setPosition(LegendDataLabelPosition.OutsideEnd);
chart.getAxes().getVerticalAxis().setAutomaticMaxValue(false);
chart.getAxes().getVerticalAxis().setMaxValue(100);
chart.setShowDataLabelsOverMaximum(true);
ISlide secondSlide = presentation.getSlides().addClone(slide);
IChart secondChart = (IChart) secondSlide.getShapes().get_Item(0);
secondChart.setShowDataLabelsOverMaximum(false);
presentation.save("DataLabelsOverMaximum.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
以下影像顯示由 Microsoft PowerPoint 渲染的已儲存投影片。使用 true 時,標籤 120 會出現在上邊界;使用 false 時則隱藏。標籤 60 仍保持可見,軸最大值仍為 100,第二個資料點在兩種情況下皆為 120。
| setShowDataLabelsOverMaximum(true) | setShowDataLabelsOverMaximum(false) |
|---|---|
![]() |
![]() |
圖表類型
此範例使用帶有數值軸的 2D 直條圖。沒有數值軸的圖表(例如圓形圖與環形圖)沒有可供此方式限制的軸最大值。設定標籤與軸的距離
使用setLabelOffset 來控制類別軸標籤與軸之間的距離。此值是軸標籤最大字型大小的百分比。此範例建立一個叢集直條圖,並將水平軸標籤偏移設定為 500。此設定會影響類別軸標籤,而非附加於個別資料點的標籤。
import com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IChart 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 com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IChart chart = slide.getShapes().addChart(ChartType.Pie, 50, 50, 200, 200);
IChartSeriesCollection series = chart.getChartData().getSeries();
IDataLabel label = series.get_Item(0).getLabels().get_Item(0);
label.getDataLabelFormat().setShowValue(true);
label.getDataLabelFormat().setPosition(LegendDataLabelPosition.OutsideEnd);
label.setX(0.71f);
label.setY(0.04f);
presentation.save("presentation.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}

格式化指向線
當圓形圖標籤位於切片外側時,指向線可協助讀者將每個數值對應至正確的切片。使用對比色且稍微加粗的線條可以讓這些連接更易辨識,而透明度與虛線樣式則可使線條在視覺上不會過於突兀。
使用getLeaderLinesFormat 在系列的資料標籤集合層級格式化指向線。series.getLabels().getLeaderLinesFormat().getLine() 的設定會套用至整個集合,而非單一標籤。
此範例建立一個使用預設資料的圓形圖,將值顯示在切片外側,並啟用setShowLeaderLines。它使用setX 與setY 偏移,使兩個標籤遠離切片,偏移值以圖表寬度與高度的比例表示。此範例不需要輸入簡報。
線條的getFillFormat 設定為不透明度為 191(最高 255)的實心藍色,約為 25% 透明度。setWidth 設為 2 點,setDashStyle 則將線條設為虛線。
import com.aspose.slides.*;
import java.awt.Color;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IChart chart = slide.getShapes().addChart(ChartType.Pie, 80, 50, 560, 400);
chart.setLegend(false);
IChartSeries series = chart.getChartData().getSeries().get_Item(0);
IDataLabelFormat labelFormat = series.getLabels().getDefaultDataLabelFormat();
labelFormat.setShowValue(true);
labelFormat.setPosition(LegendDataLabelPosition.OutsideEnd);
labelFormat.setShowLeaderLines(true);
// 將兩個標籤從各自的切片移得更遠。
series.getLabels().get_Item(0).setX(0.10f);
series.getLabels().get_Item(0).setY(-0.05f);
series.getLabels().get_Item(1).setX(-0.10f);
series.getLabels().get_Item(1).setY(0.05f);
ILineFormat line = series.getLabels().getLeaderLinesFormat().getLine();
line.getFillFormat().setFillType(FillType.Solid);
line.getFillFormat().getSolidFillColor().setColor(new Color(30, 90, 160, 191));
line.setWidth(2);
line.setDashStyle(LineDashStyle.Dash);
presentation.save("FormattedLeaderLines.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
啟用指向線並不保證每個標籤都會出現線條。可見性取決於標籤的放置方式與圖表的版面配置行為。在此範例中,兩個被移動的標籤都有可見的指向線;靠近切片的標籤則不需要指向線。
以下影像顯示以 Aspose.Slides 渲染的已儲存 FormattedLeaderLines.pptx:

在直條圖上方加入多行資料標籤
此範例建立一個直條圖,於繪圖區之上放置兩行資料標籤。Series A 顯示可見的柱狀,Series B 與 Series C 提供額外的標籤。透過移除填色與輪廓,將它們的柱狀隱藏。ChartSeriesGroup.setOverlap 方法使三個系列的類別中心對齊。
ChartPlotArea 設定保留標籤行的空間。於Chart.validateChartLayout 計算預設位置後,使用[DataLabel.setX]與DataLabel.setY 保持水平對齊並套用垂直偏移,以將標籤排列成兩行。這些數字仍為與系列值連結的資料標籤;僅標題列是獨立的文字形狀。
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 40, 40, 640, 200);
chart.setTitle(false);
chart.setLegend(false);
chart.getTextFormat().getPortionFormat().setFontHeight(12);
chart.getChartData().getSeries().clear();
chart.getChartData().getCategories().clear();
IChartDataWorkbook workbook = chart.getChartData().getChartDataWorkbook();
workbook.clear(0);
String[] categories = {"North", "South", "East", "West"};
String[] seriesNames = {"Series A", "Series B", "Series C"};
double[][] seriesValues = {
{35, 42, 28, 47},
{22, 31, 19, 26},
{12, 16, 14, 18}
};
for (int categoryIndex = 0; categoryIndex < categories.length; categoryIndex++) {
chart.getChartData().getCategories().add(
workbook.getCell(0, categoryIndex + 1, 0, categories[categoryIndex]));
}
for (int seriesIndex = 0; seriesIndex < seriesNames.length; seriesIndex++) {
IChartSeries series = chart.getChartData().getSeries().add(
workbook.getCell(0, 0, seriesIndex + 1, seriesNames[seriesIndex]),
ChartType.ClusteredColumn);
for (int categoryIndex = 0; categoryIndex < categories.length; categoryIndex++) {
series.getDataPoints().addDataPointForBarSeries(workbook.getCell(
0, categoryIndex + 1, seriesIndex + 1,
seriesValues[seriesIndex][categoryIndex]));
}
if (seriesIndex > 0) {
// 隱藏 B 與 C 系列的柱狀,但保留其資料標籤。
series.getFormat().getFill().setFillType(FillType.NoFill);
series.getFormat().getLine().getFillFormat().setFillType(FillType.NoFill);
series.getLabels().getDefaultDataLabelFormat().setShowValue(true);
series.getLabels().getDefaultDataLabelFormat()
.getTextFormat().getPortionFormat().setFontHeight(12);
IFillFormat labelFill = series.getLabels().getDefaultDataLabelFormat()
.getTextFormat().getPortionFormat().getFillFormat();
labelFill.setFillType(FillType.Solid);
labelFill.getSolidFillColor().setColor(java.awt.Color.BLACK);
series.getLabels().getDefaultDataLabelFormat().setPosition(
LegendDataLabelPosition.InsideBase);
}
}
// 將三個系列對齊至相同的類別中心。
chart.getChartData().getSeries().get_Item(0)
.getParentSeriesGroup().setOverlap((byte) 100);
// 此緊湊範例使用較少的格線。
chart.getAxes().getVerticalAxis().setAutomaticMajorUnit(false);
chart.getAxes().getVerticalAxis().setMajorUnit(10);
// 在圖表繪圖區上方保留空間以放置兩行資料標籤。
chart.getPlotArea().setLayoutTargetType(LayoutTargetType.Inner);
chart.getPlotArea().setX(0.15f);
chart.getPlotArea().setY(0.32f);
chart.getPlotArea().setWidth(0.80f);
chart.getPlotArea().setHeight(0.48f);
chart.validateChartLayout();
for (int seriesIndex = 1; seriesIndex < seriesNames.length; seriesIndex++) {
IChartSeries series = chart.getChartData().getSeries().get_Item(seriesIndex);
float rowTop = seriesIndex == 1 ? 0.15f : 0.03f;
for (int categoryIndex = 0; categoryIndex < categories.length; categoryIndex++) {
IDataLabel dataLabel = series.getDataPoints().get_Item(categoryIndex).getLabel();
// 保留預設的水平位置。Y 為相對於
// 預設標籤位置的偏移,以圖表高度的比例表示。
dataLabel.setX(0);
dataLabel.setY(rowTop - dataLabel.getActualY() / chart.getHeight());
}
// 僅列標題為獨立的文字圖形。
IAutoShape rowHeading = slide.getShapes().addAutoShape(
ShapeType.Rectangle, chart.getX(),
chart.getY() + rowTop * chart.getHeight(), 85, 18);
rowHeading.getFillFormat().setFillType(FillType.NoFill);
rowHeading.getLineFormat().getFillFormat().setFillType(FillType.NoFill);
rowHeading.addTextFrame(seriesNames[seriesIndex]);
rowHeading.getTextFrame().getTextFrameFormat().setMarginTop(0);
rowHeading.getTextFrame().getTextFrameFormat().setMarginBottom(0);
IPortionFormat headingFormat = rowHeading.getTextFrame().getParagraphs()
.get_Item(0).getPortions().get_Item(0).getPortionFormat();
headingFormat.setFontHeight(12);
headingFormat.getFillFormat().setFillType(FillType.Solid);
headingFormat.getFillFormat().getSolidFillColor().setColor(java.awt.Color.BLACK);
}
presentation.save("multiple-rows-of-labels.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}

常見問題
如何防止資料標籤在密集圖表中重疊?
結合自動標籤放置、指向線與縮小字型大小;必要時隱藏某些欄位(例如類別),或僅對極端值或關鍵點顯示標籤。
如何只對零值、負值或空值停用標籤?
在啟用標籤前先篩選資料點,並依據定義的規則關閉 0、負值或缺失值的顯示。
如何確保匯出為 PDF/影像時標籤樣式一致?
明確設定字型族與大小,並確認渲染環境中已安裝該字型,以避免回退。

