إدارة تسميات بيانات المخططات في العروض التقديمية على Android
المقدمة
تُظهر تسميات البيانات معلومات حول سلاسل المخطط والنقاط الفردية، مما يساعد القراء على تحديد القيم وفهم المخطط. يشرح هذا المقال كيفية تنسيق القيم، وعرض النسب المئوية، وقراءة نص التسمية، والتحكم في التسميات بما يتجاوز الحد الأقصى للمحور، وضبط تباعد تسميات محور الفئات، وتحديد موضع تسميات المخطط الدائري.
إحصاء تسميات البيانات الظاهرة
استخدم getCountOfVisibleDataLabels للتحقق من عدد تسميات البيانات التي تم تفعيل عرضها قبل نشر العرض التقديمي. على عكس getCount، الذي يُعيد العدد الإجمالي للتسميات في المجموعة، يأخذ هذا الأسلوب في الاعتبار القيم الافتراضية للسلسلة وإعدادات كل تسمية على حدة.
ينشئ هذا المثال مخطط أعمدة يحتوي على سلسلة واحدة وثلاث نقاط بيانات. يصل إلى مجموعة تسميات السلسلة عبر getLabels ويطبع عدد التسميات الظاهرة مع تغير الإعدادات: 0, 3, 2, 3. يظل العدد الإجمالي 3.
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, 500, 300);
chart.getChartData().getSeries().clear();
chart.getChartData().getCategories().clear();
IChartDataWorkbook workbook = chart.getChartData().getChartDataWorkbook();
IChartDataCell seriesCell = workbook.getCell(0, 0, 1, "Values");
IChartSeries series = chart.getChartData().getSeries().add(seriesCell, chart.getType());
for (int i = 0; i < 3; i++) {
IChartDataCell categoryCell = workbook.getCell(0, i + 1, 0, "Category " + (i + 1));
chart.getChartData().getCategories().add(categoryCell);
IChartDataCell valueCell = workbook.getCell(0, i + 1, 1, (i + 1) * 10);
series.getDataPoints().addDataPointForBarSeries(valueCell);
}
IDataLabelCollection labels = series.getLabels();
System.out.println("Total: " + labels.getCount() + "; visible: " + labels.getCountOfVisibleDataLabels()); // الإجمالي: 3; المرئية: 0
labels.getDefaultDataLabelFormat().setShowValue(true);
System.out.println("Visible: " + labels.getCountOfVisibleDataLabels()); // المرئية: 3
labels.get_Item(1).getDataLabelFormat().setShowValue(false);
System.out.println("Visible: " + labels.getCountOfVisibleDataLabels()); // المرئية: 2
labels.get_Item(1).getDataLabelFormat().setShowLegendKey(true);
System.out.println("Visible: " + labels.getCountOfVisibleDataLabels()); // المرئية: 3
} finally {
presentation.dispose();
}
توفر الطريقة getDefaultDataLabelFormat الإعدادات الافتراضية. تمرير true إلى setShowValue يعرض القيم لجميع الثلاث تسميات. تمرير false عبر getDataLabelFormat لتسيمة واحدة يتجاوز هذا الإعداد لتلك التسمية المحددة. تمرير true إلى setShowLegendKey يجعل تلك التسمية تُعد ظاهرة مرة أخرى، حتى وإن ظل قيمتها مخفية.
يعكس العدد الظاهر إعدادات الظهور ولا يقيس ما إذا كانت التسميات تتداخَل أو تُقَطَع أو قابلة للقراءة في المخطط المرسوم.
تعيين دقة القيم في تسميات بيانات المخططات
استخدم 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();
}
لتنسيق الخلايا الرقمية في دفتر عمل مدمج بالمخطط، راجع Set Custom Number Formats for Workbook Cells. يُظهر ذلك المثال أيضًا تسميات القيم وفق تنسيقات الخلايا المصدرية مع الحفاظ على القيم الرقمية المخزنة.
عرض النسب المئوية كتسميات
في مخطط أعمدة مكدس، احسب كل قيمة كنسبة مئوية من إجمالي الفئة وخصص النص لإطار النص الذي تُعيده 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 android.graphics.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" };
int[] 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 لاسترجاع النص الناتج عن إعدادات تسمية البيانات. هذا مفيد عند استخراج التسميات للتقارير أو البحث في محتوى العروض أو التحقق من صحة المخططات المولدة. في المثال أدناه، يجمع تنسيق تسمية البيانات الافتراضي data label format كل من اسم الفئة، اسم السلسلة، والقيمة. تُظهر إحدى النقاط قيمتها كنسبة مئوية، وتستخدم أخرى نصًا مخصصًا من 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 للتحكم فيما إذا كانت تسميات هذه النقاط تُعرض. يغيّر هذا الإعداد ظهور التسميات؛ لا يغيّر نطاق المحور ولا القيم الأساسية.
ينشئ المثال أدناه مخطط أعمدة مُجمّع ثنائي الأبعاد بقيم 60 و120. يمرّر false إلى setAutomaticMaxValue ويضبط الحد الأقصى إلى 100 عبر setMaxValue على المحور الرأسي. الشريحة الأولى تسمح بتسميات تتجاوز الحد الأقصى؛ نسخة من تلك الشريحة تُعطّلها. تُحفظ كلتا الشركتين في 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) |
|---|---|
![]() |
![]() |
Chart Type
هذا المثال يستخدم مخطط أعمدة ثنائي الأبعاد مع محور قيم. المخططات التي لا تحتوي على محور قيم، مثل المخططات الدائرية ومخططات الكعكة، لا تملك حدًا أقصى للمحور يمكن تقييده بهذه الطريقة.تحديد مسافة التسمية عن المحور
استخدم 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 السماكة إلى نقطتين، وتُعيّن setDashStyle الخط كنمط متقطع.
import com.aspose.slides.*;
import android.graphics.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(Color.argb(191, 30, 90, 160));
line.setWidth(2);
line.setDashStyle(LineDashStyle.Dash);
presentation.save("FormattedLeaderLines.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
تفعيل خطوط الربط لا يضمن ظهور خط لكل تسمية. تعتمد الرؤية على موضع التسمية وسلوك تخطيط المخطط. في هذا المثال، للتسميتين المنقولتين خطوط ربط مرئية؛ بينما التسميات القريبة من الشرائح لا تحتاج إلى ذلك.
تُظهر الصورة التالية ملف FormattedLeaderLines.pptx المُحفظ والمُعرض عبر Aspose.Slides:

إضافة عدة صفوف من تسميات البيانات فوق مخطط عمودي
ينشئ هذا المثال مخطط أعمدة مع صفين من تسميات البيانات فوق مساحة الرسم. تُظهر السلسلة A الأعمدة الظاهرة، بينما تُقدم السلسلتان B وC التسميات الإضافية. تُخفى أعمدتها بإزالة التعبئة والحد. يوزِّن الأسلوب ChartSeriesGroup.setOverlap جميع السلاسل الثلاثة على مراكز الفئات نفسها.
تُخصِّص إعدادات ChartPlotArea مساحة لصفوف التسميات. بعد أن تحسب Chart.validateChartLayout المواقع الافتراضية، يحافظ DataLabel.setX وDataLabel.setY على المحاذاة الأفقية ويطبّقان إزاحات رأسية لترتيب التسميات في صفين. تظل الأعداد تسميات بيانات مرتبطة بقيم السلسلة؛ فقط عناوين الصفوف هي أشكال نصية منفصلة.
import com.aspose.slides.*;
import android.graphics.Color;
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++) {
IChartDataCell categoryCell = workbook.getCell(0, categoryIndex + 1, 0, categories[categoryIndex]);
chart.getChartData().getCategories().add(categoryCell);
}
for (int seriesIndex = 0; seriesIndex < seriesNames.length; seriesIndex++) {
IChartDataCell seriesCell = workbook.getCell(0, 0, seriesIndex + 1, seriesNames[seriesIndex]);
IChartSeries series = chart.getChartData().getSeries().add(seriesCell, ChartType.ClusteredColumn);
for (int categoryIndex = 0; categoryIndex < categories.length; categoryIndex++) {
IChartDataCell valueCell = workbook.getCell(0, categoryIndex + 1, seriesIndex + 1, seriesValues[seriesIndex][categoryIndex]);
series.getDataPoints().addDataPointForBarSeries(valueCell);
}
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(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(Color.BLACK);
}
presentation.save("multiple-rows-of-labels.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}

الأسئلة الشائعة
كيف يمكنني منع تداخل تسميات البيانات في المخططات الكثيفة؟
اجمع بين وضع تلقائي للتسميات، خطوط الربط، وتقليل حجم الخط؛ وإذا لزم الأمر، أخفِ بعض الحقول (مثل الفئة) أو أظهر التسميات فقط للقيم المتطرفة أو النقاط الرئيسية.
كيف يمكنني تعطيل التسميات للقيم الصفرية أو السلبية أو الفارغة فقط؟
قُم بترشيح نقاط البيانات قبل تمكين التسميات وأوقف العرض للقيم التي تساوي 0 أو قيم سلبية أو قيم مفقودة وفق قاعدة محددة.
كيف يمكنني ضمان اتساق نمط التسمية عند التصدير إلى PDF أو صور؟
حدد صراحةً نوع الخط وحجمه وتأكد من توفر الخط في بيئة العرض لتجنب الاعتماد على خط بديل.

