Управление сериями данных диаграммы в презентациях на Java

Обзор

Диаграмма хранит свои построенные данные в рабочей книге данных диаграммы. Объект IChartSeries представляет один набор связанных значений, и каждый IChartDataPoint в серии ссылается на одну или несколько ячеек рабочей книги. Объекты IChartCategory предоставляют метки или группирующие значения, общие для серий. Имя серии, категории и значения точек поэтому связаны с объектами IChartDataCell, а не хранятся только как отображаемый текст.

Для типичной диаграммы категорий стандартная рабочая книга использует строку 0 для имён серий, столбец 0 для имён категорий и оставшиеся ячейки для значений серий. Индексы листа, строки и столбца, передаваемые в IChartDataWorkbook.getCell, являются нулевыми. Такой макет полезен при создании диаграммы с данными по умолчанию, но не следует предполагать, что каждая существующая диаграмма использует его. Для загруженной презентации проверьте ячейки, на которые ссылаются серии, категории и точки данных, прежде чем изменять значения в рабочей книге.

Настройки диаграммы имеют три разных уровня:

  • Настройки уровня серии, такие как IChartSeries.getFormat, задают внешний вид по умолчанию для всех точек в одной серии.
  • Настройки точек данных, такие как IChartDataPoint.getFormat, переопределяют внешний вид серии для отдельной точки.
  • Настройки группы применяются к совместимым сериям, принадлежащим одному IChartSeriesGroup. Получить группу можно через IChartSeries.getParentSeriesGroup при необходимости задать такие параметры, как перекрытие или ширина промежутка.

Когда явная заливка точки или серии не задана, стиль и тема диаграммы определяют автоматический внешний вид. При наличии как формата серии, так и формата точки, формат точки имеет приоритет для этой точки.

серия диаграммы PowerPoint

Установить перекрытие серии диаграммы

IChartSeries.getOverlap сообщает, насколько столбцы или полосы перекрываются в 2D‑диаграмме, от ‑100 до 100 процентов. Это только чтение проекции настройки в родительской группе серий. Используйте IChartSeriesGroup.setOverlap, чтобы обновить каждую совместимую серию в этой группе. Этот параметр применяется к типам диаграмм, отображающим сгруппированные столбцы или полосы; он не влияет на несвязанные группы серий в комбинированной диаграмме.

Следующий пример задаёт перекрытие для группы, содержащей первую серию:

import com.aspose.slides.*;

final int firstSlideIndex = 0;
final int firstSeriesIndex = 0;
final byte overlapPercent = 30;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(firstSlideIndex);

    // Новая диаграмма содержит примерные серии, категории и значения.
    IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200);

    IChartSeries series = chart.getChartData().getSeries().get_Item(firstSeriesIndex);
    series.getParentSeriesGroup().setOverlap(overlapPercent);

    presentation.save("series_overlap.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Результат:

Перекрытие серии

Изменить цвет заливки серии

Используйте IChartSeries.getFormat для задания заливки по умолчанию для всей серии. Если у точки уже задана явная заливка, её настройка IChartDataPoint.getFormat переопределяет заливку серии для этой точки.

Следующий пример применяет сплошную синюю заливку к первой серии:

import com.aspose.slides.*;
import java.awt.Color;

final int firstSlideIndex = 0;
final int firstSeriesIndex = 0;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(firstSlideIndex);

    IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200);

    IChartSeries series = chart.getChartData().getSeries().get_Item(firstSeriesIndex);
    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 com.aspose.slides.*;

final int firstSlideIndex = 0;
final int worksheetIndex = 0;
final int seriesNameRowIndex = 0;
final int firstSeriesColumnIndex = 1;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(firstSlideIndex);

    IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200);

    IChartDataWorkbook workbook = chart.getChartData().getChartDataWorkbook();
    IChartDataCell seriesNameCell = workbook.getCell(worksheetIndex, seriesNameRowIndex, firstSeriesColumnIndex);
    seriesNameCell.setValue("Revenue");

    presentation.save("series_name.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Вы также можете обновить ячейку, уже используемую IChartSeries.getName. Такой подход избегает предположений о конкретных строке и столбце в существующей диаграмме:

import com.aspose.slides.*;

final int firstSlideIndex = 0;
final int firstSeriesIndex = 0;
final int firstNameCellIndex = 0;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(firstSlideIndex);

    IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200);

    IChartSeries series = chart.getChartData().getSeries().get_Item(firstSeriesIndex);
    IChartDataCell seriesNameCell = series.getName().getAsCells().get_Item(firstNameCellIndex);
    seriesNameCell.setValue("Revenue");

    presentation.save("series_name.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Результат:

Имя серии

Создать серию с именем из нескольких ячеек

Составное имя серии полезно, когда название продукта и отчетный период хранятся в разных ячейках рабочей книги. Например, можно объединить Product A в B1 и 2026 в C1 в одно имя серии, оставив обе части привязанными к исходным ячейкам.

Используйте IChartDataWorkbook.getCellCollection для получения диапазона имён, затем передайте эту коллекцию в IChartSeriesCollection.add. Параметр skipHiddenCells управляет включением скрытых ячеек: true исключает их, false включает. Этот пример использует false, чтобы включить каждую ячейку в диапазоне имён.

Следующий пример создает презентацию с одной серией и двумя точками данных. Ячейки B1:C1 содержат только имя серии; A2:A3 — метки категорий, а B2:B3 — числовые значения.

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, 620, 180);

    chart.getChartData().getSeries().clear();
    chart.getChartData().getCategories().clear();
    chart.setLegend(true);

    IChartDataWorkbook workbook = chart.getChartData().getChartDataWorkbook();
    workbook.clear(0);

    // Эти две ячейки задают имя серии.
    workbook.getCell(0, 0, 1, "Product A");
    workbook.getCell(0, 0, 2, "2026");
    IChartCellCollection nameCells = workbook.getCellCollection("Sheet1!$B$1:$C$1", false);
    IChartSeries series = chart.getChartData().getSeries().add(nameCells, ChartType.ClusteredColumn);

    // Отдельные ячейки задают категории и числовые точки данных.
    IChartDataCell northCategory = workbook.getCell(0, 1, 0, "North");
    IChartDataCell southCategory = workbook.getCell(0, 2, 0, "South");
    chart.getChartData().getCategories().add(northCategory);
    chart.getChartData().getCategories().add(southCategory);
    IChartDataCell northValue = workbook.getCell(0, 1, 1, 120);
    IChartDataCell southValue = workbook.getCell(0, 2, 1, 150);
    series.getDataPoints().addDataPointForBarSeries(northValue);
    series.getDataPoints().addDataPointForBarSeries(southValue);

    presentation.save("composite_series_name.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Полученное имя серии — Product A 2026, между двумя значениями ячеек пробел. Легенда отображает его как одну запись для обоих столбцов. На изображении ниже показан результат:

Гистограмма с значениями Север и Юг и составным именем серии Product A 2026 в легенде

Получить автоматический цвет заливки серии

IChartSeries.getAutomaticSeriesColor возвращает цвет, вычисленный на основе индекса серии и стиля диаграммы. Это цвет, используемый, когда заливка серии не определена явно. Вызов метода лишь читает вычисленный цвет; он не задаёт новую заливку.

Следующий пример выводит автоматический цвет каждой серии по умолчанию:

import com.aspose.slides.*;
import java.awt.Color;

final int firstSlideIndex = 0;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(firstSlideIndex);

    IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200);

    int seriesCount = chart.getChartData().getSeries().size();
    for (int seriesIndex = 0; seriesIndex < seriesCount; seriesIndex++) {
        IChartSeries series = chart.getChartData().getSeries().get_Item(seriesIndex);
        Color automaticColor = series.getAutomaticSeriesColor();
        System.out.println("Series " + seriesIndex + ": " + automaticColor);
    }
} 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]

Точные цвета зависят от стиля и темы диаграммы.

Установить инвертированный цвет заливки для серии диаграммы

Для серий полос, столбцов и пузырей IChartSeries.setInvertIfNegative позволяет отображать отрицательные значения другим цветом заливки. Установите обычную заливку серии как сплошную, включите инверсию и задайте цвет отрицательного значения через IChartSeries.getInvertedSolidFillColor. Отрицательные числа в рабочей книге остаются неизменными; меняется только их цвет отображения.

Следующий пример заменяет данные диаграммы по умолчанию на одну серию. Строка 0 листа содержит имя серии, столбец 0 — имена категорий, столбец 1 — значения:

import com.aspose.slides.*;
import java.awt.Color;

final int firstSlideIndex = 0;
final int worksheetIndex = 0;
final int headerRowIndex = 0;
final int categoryColumnIndex = 0;
final int firstSeriesColumnIndex = 1;
final int firstDataRowIndex = 1;

String[] categoryNames = { "Category 1", "Category 2", "Category 3" };
int[] seriesValues = { -20, 50, -30 };

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(firstSlideIndex);

    IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200);
    IChartData chartData = chart.getChartData();
    IChartDataWorkbook workbook = chartData.getChartDataWorkbook();

    chartData.getSeries().clear();
    chartData.getCategories().clear();

    IChartDataCell seriesNameCell = workbook.getCell(worksheetIndex, headerRowIndex, firstSeriesColumnIndex, "Series 1");
    int chartType = chart.getType();
    IChartSeries series = chartData.getSeries().add(seriesNameCell, chartType);

    for (int categoryIndex = 0; categoryIndex < categoryNames.length; categoryIndex++) {
        int dataRowIndex = firstDataRowIndex + categoryIndex;
        String categoryName = categoryNames[categoryIndex];
        int seriesValue = seriesValues[categoryIndex];

        IChartDataCell categoryCell = workbook.getCell(worksheetIndex, dataRowIndex, categoryColumnIndex, categoryName);
        chartData.getCategories().add(categoryCell);

        IChartDataCell valueCell = workbook.getCell(worksheetIndex, dataRowIndex, firstSeriesColumnIndex, seriesValue);
        series.getDataPoints().addDataPointForBarSeries(valueCell);
    }

    Color automaticSeriesColor = series.getAutomaticSeriesColor();
    series.getFormat().getFill().setFillType(FillType.Solid);
    series.getFormat().getFill().getSolidFillColor().setColor(automaticSeriesColor);
    series.setInvertIfNegative(true);
    series.getInvertedSolidFillColor().setColor(Color.RED);

    presentation.save("inverted_solid_fill_color.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Результат:

Инвертированный сплошной цвет заливки

Инверсию для одной точки можно включить через IChartDataPoint.setInvertIfNegative. В следующем примере инверсия отключена для серии и включена только для выбранной точки. Точке также присвоено отрицательное значение, чтобы эффект был виден:

import com.aspose.slides.*;
import java.awt.Color;

final int firstSlideIndex = 0;
final int firstSeriesIndex = 0;
final int targetDataPointIndex = 2;
final int negativeValue = -30;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(firstSlideIndex);

    IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200);

    IChartSeries series = chart.getChartData().getSeries().get_Item(firstSeriesIndex);
    Color automaticSeriesColor = series.getAutomaticSeriesColor();
    series.getFormat().getFill().setFillType(FillType.Solid);
    series.getFormat().getFill().getSolidFillColor().setColor(automaticSeriesColor);
    series.getInvertedSolidFillColor().setColor(Color.RED);
    series.setInvertIfNegative(false);

    IChartDataPoint dataPoint = series.getDataPoints().get_Item(targetDataPointIndex);
    dataPoint.getValue().getAsCell().setValue(negativeValue);
    dataPoint.setInvertIfNegative(true);

    presentation.save("data_point_invert_color_if_negative.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Очистить значение конкретной точки данных

Чтобы сделать одну точку пустой, не удаляя остальные, задайте её ячейке в рабочей книге значение null. Для столбчатой диаграммы отображаемое значение доступно через IChartDataPoint.getValue. Точка остаётся в том же положении категории, но диаграмма считает её значение пустым согласно настройкам отображения пустых значений.

Следующий пример очищает только вторую точку первой серии:

import com.aspose.slides.*;

final int firstSlideIndex = 0;
final int firstSeriesIndex = 0;
final int targetDataPointIndex = 1;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(firstSlideIndex);

    IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 20, 20, 500, 200);

    IChartSeries series = chart.getChartData().getSeries().get_Item(firstSeriesIndex);
    IChartDataPoint dataPoint = series.getDataPoints().get_Item(targetDataPointIndex);
    dataPoint.getValue().getAsCell().setValue(null);

    presentation.save("clear_data_point_value.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Диаграммы разброса используют отдельные ячейки X и Y, а диаграммы‑пузыри — также ячейку размера. Очищайте только ячейку, представляющую значение, которое нужно удалить. Не вызывайте IChartDataPointCollection.clear если хотите сохранить остальные точки, потому что этот метод удаляет все точки из коллекции.

Управление отображением пустых ячеек

Скрытые ячейки, содержащие значения, — отдельный случай от пустых ячеек. Чтобы включать или исключать данные из скрытых строк и столбцов листа, см. Включить данные из скрытых строк и столбцов.

Пустая ячейка рабочей книги обозначает отсутствие данных; ячейка, содержащая 0, представляет известное числовое значение. Вызовите IChartDataCell.setValue с null, чтобы сделать ячейку пустой. Числовой ноль остаётся нулём независимо от настройки пустой ячейки.

Используйте IChart.setDisplayBlanksAs, чтобы выбрать, как диаграмма отображает пустые ячейки. Эта настройка применяется ко всей диаграмме. Она меняет способ построения пустот, не заполняя пустую ячейку нулём или интерполированным значением.

Следующий автономный пример создаёт линейную диаграмму с одной серией, очищает значение для Дня 3 и сохраняет одну и ту же диаграмму в каждом режиме. Входной файл не требуется. IChartDataWorkbook использует лист 0, столбец 0 — метки категорий, столбец 1 — значения; строка 0 — имя серии. Итоговые данные: 10, 20, empty, 30, 40.

import com.aspose.slides.*;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    IChart chart = slide.getShapes().addChart(ChartType.LineWithMarkers, 40, 40, 640, 400);
    IChartData chartData = chart.getChartData();
    IChartDataWorkbook workbook = chartData.getChartDataWorkbook();

    chartData.getSeries().clear();
    chartData.getCategories().clear();

    IChartDataCell seriesNameCell = workbook.getCell(0, 0, 1, "Measurements");
    IChartSeries series = chartData.getSeries().add(seriesNameCell, chart.getType());
    int[] values = { 10, 20, 25, 30, 40 };

    for (int i = 0; i < values.length; i++) {
        IChartDataCell categoryCell = workbook.getCell(0, i + 1, 0, "Day " + (i + 1));
        chartData.getCategories().add(categoryCell);
        IChartDataCell valueCell = workbook.getCell(0, i + 1, 1, values[i]);
        series.getDataPoints().addDataPointForLineSeries(valueCell);
    }

    // Оставить День 3 действительно пустым, сохранив его категорию и точку данных.
    workbook.getCell(0, 3, 1).setValue(null);

    int[] modes = { DisplayBlanksAsType.Gap, DisplayBlanksAsType.Zero, DisplayBlanksAsType.Span };
    String[] modeNames = { "Gap", "Zero", "Span" };
    for (int i = 0; i < modes.length; i++) {
        chart.setDisplayBlanksAs(modes[i]);
        presentation.save("empty_cells_" + modeNames[i] + ".pptx", SaveFormat.Pptx);
    }
} finally {
    presentation.dispose();
}

Каждый выходной файл сохраняет режим, выбранный перед сохранением: empty_cells_Gap.pptx, empty_cells_Zero.pptx и empty_cells_Span.pptx. Чтобы сохранить только одну версию, задайте нужный режим и сохраните презентацию один раз вместо итерации по режимам.

Сравнение ниже показывает одинаковые данные во всех трёх файлах. День 3 пуст в рабочей книге во всех случаях:

Линейные диаграммы с одинаковыми данными: Gap разрывает линию на Дне 3, Zero опускает линию до нуля, а Span соединяет День 2 с Днём 4

Видимый эффект зависит от типа диаграммы. Линейная диаграмма позволяет легко сравнивать все три режима. У столбчатых и колонных диаграмм нет линии, соединяющей пропущенную категорию, поэтому Span не может создать соединительный сегмент, показанный выше; отсутствующий столбец и столбец нулевой высоты могут выглядеть одинаково. Аналогично, у диаграммы разброса только с маркерами нет соединительной линии. Не ожидайте три различных результата для каждого типа диаграммы; проверьте вывод для используемого типа.

Установить ширину промежутка серии

Ширина промежутка — это расстояние между соседними кластерами полос или столбцов, выраженное в процентах от ширины полосы или столбца. Как и перекрытие, она относится к родительской группе серий, а не к отдельной серии. Вызовите IChartSeriesGroup.setGapWidth один раз для группы. Большое значение создаёт больше пространства между кластерами; меньшее — делает их плотнее.

Следующий пример меняет ширину промежутка и сохраняет только окончательную презентацию:

import com.aspose.slides.*;

final int firstSlideIndex = 0;
final int firstSeriesIndex = 0;
final int gapWidthPercent = 30;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(firstSlideIndex);

    IChart chart = slide.getShapes().addChart(ChartType.StackedColumn, 20, 20, 500, 200);

    IChartSeries series = chart.getChartData().getSeries().get_Item(firstSeriesIndex);
    series.getParentSeriesGroup().setGapWidth(gapWidthPercent);

    presentation.save("gap_width_30.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Результат:

Ширина промежутка

FAQ

Какие типы диаграмм поддерживают серии данных?
Все типы диаграмм, представленные перечислением ChartType, используют данные диаграммы, но их серии не имеют одинаковой структуры значений или настроек. Например, диаграммы категорий используют категории и значения, диаграммы разброса — X и Y, а диаграммы‑пузыри добавляют размер пузыря. Используйте метод создания точек данных, соответствующий типу серии. Параметры такие как перекрытие и ширина промежутка применимы только к совместимым группам полос или столбцов.

Что такое группа серий диаграммы?
IChartSeriesGroup содержит совместимые серии, которые разделяют настройки уровня группы построения. Комбинированная диаграмма может включать более одной группы, поэтому изменение группы, полученной через одну серию, не обязательно меняет все серии в диаграмме.

Создаётся ли в новой диаграмме набор данных по умолчанию?
Да. По умолчанию IShapeCollection.addChart создаёт образцы серий, категорий и значений. Вы можете отредактировать эти ячейки или очистить как коллекцию серий, так и коллекцию категорий перед добавлением полностью пользовательского набора данных. Перегрузка метода также может создавать диаграмму без данных по умолчанию.

Как объекты диаграммы связаны с ячейками рабочей книги?
Имена серий, метки категорий и значения точек данных ссылаются на ячейки в IChartDataWorkbook. Изменение связанной ячейки обновляет соответствующий элемент диаграммы. При построении пользовательских данных следите за тем, чтобы строки категорий и строки значений серий были согласованы, чтобы каждая точка отображалась под нужной категорией.

Как очистить одну точку, а не всю серию?
Установите значение соответствующей ячейки в null, чтобы точка оставалась в позиции категории, но воспринималась как пустая. Используйте IChartDataPointCollection.clear только тогда, когда хотите удалить все точки из серии. Если вы также удаляете категории, обновите все серии, чтобы их значения оставались согласованными с коллекцией категорий.

Как отображаются пустые точки?
Результат зависит от типа диаграммы и значения, настроенного через IChart.setDisplayBlanksAs. Поддерживаемые диаграммы могут отображать пустоты как разрывы, как нулевые значения или соединяя соседние точки. Выберите настройку, соответствующую смыслу отсутствующих данных в вашей презентации. См. раздел Управление отображением пустых ячеек для полного примера и визуального сравнения.

Как форматируются отрицательные значения?
Для поддерживаемых полос, столбцов и пузырей вызовите IChartSeries.setInvertIfNegative и задайте цвет, возвращаемый IChartSeries.getInvertedSolidFillColor. Поведение отдельной точки можно переопределить с помощью IChartDataPoint.setInvertIfNegative. Эти методы влияют только на оформление, а не на сохраняемые числовые значения.

Какой формат выигрывает, если заданы и серия, и точка?
Явное форматирование точки данных имеет приоритет для этой точки. Другие точки продолжают использовать явный формат серии или, если формат серии не задан, автоматический стиль и тему диаграммы. Настройки группы, такие как перекрытие и ширина промежутка, управляют компоновкой и не являются переопределениями формата на уровне точек.

Существует ли ограничение на количество серий в диаграмме?
Aspose.Slides не накладывает отдельного фиксированного ограничения на количество серий. На практике ограничения задаются размером файла презентации, доступной памятью, временем рендеринга и читаемостью диаграммы.

Что менять, если столбцы слишком близко или слишком далеко друг от друга?
Вызовите IChartSeriesGroup.setGapWidth для соответствующей родительской группы серий. Увеличьте значение, чтобы расширить пространство между кластерами, или уменьшите, чтобы собрать кластеры ближе.