Сообщить об ошибке.

Создание диаграмм средствами модуля openpyxl в Python

Диаграммы - отличный способ быстро визуализировать и понять огромное количество данных. Существует множество различных типов диаграмм: столбчатая диаграмма, линейная диаграмма, круговая диаграмма, и так далее. Модуль openpyxl поддерживает многие из них.

Здесь будут разбираться приемы создания наиболее часто используемых диаграмм - это столбчатая и линейная диаграммы. Так как теория лежащая в основе создания диаграмм одинакова, создание остальных типов диаграмм не составит труда.

Примечание: В зависимости от того, что используется для просмотра документа XLSX - Microsoft Excel или альтернатива с открытым исходным кодом (LibreOffice Calc или OpenOffice Calc), диаграмма может выглядеть немного иначе. В частности, LibreOffice Calc неправильно отображает подписи осей, заголовок диаграммы вообще не выводится. Кстати китайский WPS Office Calc отображает все корректно.

Содержание:


Основы построения диаграмм.

Диаграммы состоят, по крайней мере, из одного или нескольких рядов данных. Сами ряды данных состоят из ссылок на диапазоны ячеек.

from openpyxl import Workbook
from openpyxl.chart import BarChart, Reference

wb = Workbook()
ws = wb.active

# данные для диаграммы
data = [
    ["Product", "Online", "Store"],
    [1, 30, 45],
    [2, 40, 30],
    [3, 40, 25],
    [4, 50, 30],
    [5, 30, 25],
    [6, 25, 35],
    [7, 20, 40],
]
for row in data:
    ws.append(row)

# выбираем диапазоны значений для диаграммы
values = Reference(worksheet=ws,
                 min_row=1,
                 max_row=8,
                 min_col=2,
                 max_col=3)
# создаем объект столбчатой диаграммы
chart = BarChart()
# добавляем в диаграмму выбранный диапазон значений
chart.add_data(values, titles_from_data=True)
# привязываем диаграмму к ячейке `E15`
ws.add_chart(chart, "A11")
# определяем размеры диаграммы в сантиметрах
chart.width = 20
chart.height = 5
# сохраняем и смотрим что получилось
wb.save("sample-chart.xlsx")

По умолчанию верхний левый угол диаграммы привязан к ячейке 'A11' и имеет размер 15 x 7,5 см. Размеры диаграммы можно изменить, задав нижеуказанные свойства:

  • chart.width - ширина диаграммы, по умолчанию 15 сантиметров.
  • chart.heigh - высота диаграммы, по умолчанию 7,5 сантиметров.

Внимание. Фактический размер будет зависеть от операционной системы и устройства.

Создание столбчатых гистограмм.

На столбчатых гистограммах, значения отображаются либо в виде горизонтальных полос, либо в виде вертикальных столбцов.

Следующие настройки влияют на вид столбчатых гистограмм:

  • Для переключения между вертикальной и горизонтальной гистограммами, необходимо просто изменить ее тип .type = "col" (вертикальные столбцы) или .type = "bar" (горизонтальные полосы).
  • При использовании диаграмм с накоплением, для свойства .overlap необходимо установить значение 100.
  • Если диаграмма имеет вид горизонтальных полос, то оси x и y меняются местами.
  • Свойство объекта диаграммы .grouping может принимать одно из значений: 'percentStacked', 'stacked', 'standard' (по умолчанию).

Смотрим пример четырех гистограмм, который иллюстрирует различные возможности и настройки (с подробным описанием кода):

from copy import deepcopy
from openpyxl import Workbook
from openpyxl.chart import BarChart, Reference

wb = Workbook()
ws = wb.active

# данные для построения диаграмм
rows = [
    ('Number', 'Batch 1', 'Batch 2'),
    (2, 10, 30),
    (3, 40, 60),
    (4, 50, 70),
    (5, 20, 10),
    (6, 10, 40),
    (7, 50, 30),
]
for row in rows:
    ws.append(row)

# ДИАГРАММА №1
# создаем объект диаграммы
chart1 = BarChart()
# установим тип - `вертикальные столбцы`
chart1.type = "col"
# установим стиль диаграммы (цветовая схема)
chart1.style = 10
# заголовок диаграммы
chart1.title = "Столбчатая диаграмма"
# подпись оси `y`
chart1.y_axis.title = 'Длина выборки'
# показывать данные на оси (для LibreOffice Calc)
chart1.y_axis.delete = False
# подпись оси `x`
chart1.x_axis.title = 'Номер теста'
chart1.x_axis.delete = False
# выберем 2 столбца с данными для оси `y`
data = Reference(ws, min_col=2, max_col=3, min_row=1, max_row=7)
# теперь выберем категорию для оси `x`
categor = Reference(ws, min_col=1, min_row=2, max_row=7)
# добавляем данные в объект диаграммы
chart1.add_data(data, titles_from_data=True)
# установим метки на объект диаграммы
chart1.set_categories(categor)
# добавим диаграмму на лист, в ячейку "A10"
ws.add_chart(chart1, "A10")

# ДИАГРАММА №2
# что бы показать типы столбчатых диаграмм, скопируем 
# первую диаграмму и будем менять настройки
chart2 = deepcopy(chart1)
# изменяем стиль
chart2.style = 11
# установим тип - `горизонтальные полосы`
chart2.type = "bar"
chart2.title = "Горизонтальные полосы"
ws.add_chart(chart2, "A25")

# ДИАГРАММА №3
chart3 = deepcopy(chart1)
chart3.type = "col"
chart3.style = 12
# зададим группировку
chart3.grouping = "stacked"
# для диаграммы с группировкой, 
# необходимо установить перекрытие
chart3.overlap = 100
chart3.title = 'Сложенная диаграмма'
ws.add_chart(chart3, "A40")

# ДИАГРАММА №4
chart4 = deepcopy(chart1)
chart4.type = "bar"
chart4.style = 13
chart4.grouping = "percentStacked"
chart4.overlap = 100
# отключим линии сетки
chart4.y_axis.majorGridlines = None
# уберем легенду
chart4.legend = None
chart4.title = 'Диаграмма с процентным накоплением'
ws.add_chart(chart4, "A55")

# сохраняем и смотрим что получилось
wb.save("bar.xlsx")

3D столбчатые гистограммы.

При помощи модуля openpyxl также можно создавать трехмерные гистограммы. Смотрим пример простой трехмерной гистограммы:

from openpyxl import Workbook
from openpyxl.chart import Reference, BarChart3D

wb = Workbook()
ws = wb.active

rows = [
    (None, 2013, 2014),
    ("Apples", 5, 4),
    ("Oranges", 6, 2),
    ("Pears", 8, 3)
]

for row in rows:
    ws.append(row)

data = Reference(ws, min_col=2, min_row=1, max_col=3, max_row=4)
titles = Reference(ws, min_col=1, min_row=2, max_row=4)
chart = BarChart3D()
chart.title = "3D Bar Chart"
chart.add_data(data=data, titles_from_data=True)
chart.set_categories(titles)

ws.add_chart(chart, "E5")
wb.save("bar3d.xlsx")

Создание линейных диаграмм.

Линейные диаграммы позволяют отображать данные относительно фиксированной оси. Они похожи на точечные диаграммы, главное отличие состоит в том, что в линейных диаграммах каждый ряд данных отображается на основе одних и тех же значений. В качестве вспомогательных осей можно использовать различные типы осей.

Как и столбчатые гистограммы, линейные диаграммы бывают трех видов: 'standard' (стандартные), 'stacked' (с накоплением) и 'percentStacked' (с процентным накоплением).

Смотрим пример линейных диаграмм, который иллюстрирует различные возможности и настройки (с подробным описанием кода):

from openpyxl import Workbook
from openpyxl.chart import LineChart, Reference
from openpyxl.chart.axis import DateAxis
from datetime import date
from copy import deepcopy

wb = Workbook()
ws = wb.active

# данные для построения диаграммы
rows = [
    ['Date', 'Batch 1', 'Batch 2', 'Batch 3'],
    [date(2015,9, 1), 40, 30, 25],
    [date(2015,9, 2), 40, 25, 30],
    [date(2015,9, 3), 50, 30, 45],
    [date(2015,9, 4), 30, 25, 40],
    [date(2015,9, 5), 25, 35, 30],
    [date(2015,9, 6), 20, 40, 35],
]
for row in rows:
    ws.append(row)

# ДИАГРАММА №1
# создаем объект диаграммы
chart1 = LineChart()
# заголовок диаграммы
chart1.title = "Линейная диаграмма"
# установим цветовую схему диаграммы
chart1.style = 13
# подпись оси `y`
chart1.y_axis.title = 'Размер'
# показывать данные на оси (для LibreOffice Calc)
chart1.y_axis.delete = False
# подпись оси `x`
chart1.x_axis.title = 'Номер теста'
chart1.x_axis.delete = False
# выберем 4 столбца с данными для оси `y` 
# в итоге получим 4 графика
data = Reference(ws, min_col=2, max_col=4, min_row=1, max_row=7)
# добавляем данные в объект диаграммы
chart1.add_data(data, titles_from_data=True)
# ТЕПЕРЬ ЗАДАДИМ СТИЛЬ ЛИНИЙ 
# ЛИНИЯ С ДАННЫМИ ИЗ 1 СТОЛБЦА ДАННЫХ
line1 = chart1.series[0]
# символ маркера для текущего значения
line1.marker.symbol = "x"
# цвет заливки маркера
line1.marker.graphicalProperties.solidFill = "FF0000"
line1.marker.graphicalProperties.line.solidFill = "FF0000"
# не заливаем линию между маркерами (прозрачная)
line1.graphicalProperties.line.noFill = True
# ЛИНИЯ С ДАННЫМИ ИЗ 2 СТОЛБЦА ДАННЫХ
line2 = chart1.series[1]
# цвет заливки линии графика
line2.graphicalProperties.line.solidFill = "00AAAA"
# делаем линию пунктирной
line2.graphicalProperties.line.dashStyle = "sysDot"
# ширина указывается в EMU
line2.graphicalProperties.line.width = 100050
# ЛИНИЯ С ДАННЫМИ ИЗ 3 СТОЛБЦА ДАННЫХ
line3 = chart1.series[2]
# символ маркера для текущего значения
line3.marker.symbol = "triangle"
# покрасим маркер в другой цвет
line1.marker.graphicalProperties.solidFill = "FF0000"
line3.marker.graphicalProperties.line.solidFill = "0000FF"
# делаем линию гладкой
line3.smooth = True
# добавим диаграмму на лист, в ячейку "A10"
ws.add_chart(chart1, "A10")

# ДИАГРАММА №2
# скопируем первую диаграмму
stacked = deepcopy(chart1)
# диаграмма с накоплением
stacked.grouping = "stacked"
stacked.title = "Графики с накоплением"
ws.add_chart(stacked, "A27")

# ДИАГРАММА №3
percent_stacked = deepcopy(chart1)
# диаграмма с процентным накоплением
percent_stacked.grouping = "percentStacked"
percent_stacked.title = "Графики с процентным накоплением"
ws.add_chart(percent_stacked, "A44")

# ДИАГРАММА №4 с датами по оси `x`, все линии
# графиков будут иметь стиль по умолчанию
# создаем объект диаграммы
chart2 = LineChart()
chart2.title = "Графики с осью дат"
# установим другую цветовую схему
chart2.style = 12
# подпись оси `y`
chart2.y_axis.title = "Размер"
chart2.y_axis.delete = False
# поперечная ось
chart2.y_axis.crossAx = 500
# подпись оси `x`
chart2.x_axis.title = "Дата"
chart2.x_axis.delete = False
chart2.x_axis = DateAxis(crossAx=100)
# формат отображения дат на оси `x`
chart2.x_axis.number_format = 'd-mmm'
# задаем временную единицу даты
chart2.x_axis.majorTimeUnit = "days"
# добавляем выборку данных из первой диаграммы
chart2.add_data(data, titles_from_data=True)
# делаем выборку данных для оси `x`
dates = Reference(ws, min_col=1, min_row=2, max_row=7)
chart2.set_categories(dates)
ws.add_chart(chart2, "A61")

# сохраняем и смотрим что получилось
wb.save("line.xlsx")

Примечание:

  • Атрибут линии dashStyle может принимать одно из значений: ‘dot’, ‘lgDashDot’, ‘lgDashDotDot’, ‘sysDash’, ‘lgDash’, ‘sysDot’, ‘solid’ (по умолчанию), ‘dashDot’, ‘sysDashDotDot’, ‘dash’, ‘sysDashDot’
  • Атрибут маркера marker.symbol может принимать одно из значений: ‘dot’, ‘plus’, ‘triangle’, ‘x’, ‘star’, ‘diamond’, ‘square’, ‘circle’, ‘dash’, ‘auto’ (по умолчанию).

3D линейные диаграммы.

В трехмерных линейных диаграммах проекция третьей оси совпадает с названием столбцов выбранных данных, в общем с легендой.

from datetime import date
from openpyxl import Workbook
from openpyxl.chart import LineChart3D, Reference
from openpyxl.chart.axis import DateAxis

wb = Workbook()
ws = wb.active

rows = [
    ['Date', 'Batch 1', 'Batch 2', 'Batch 3'],
    [date(2015,9, 1), 40, 30, 25],
    [date(2015,9, 2), 40, 25, 30],
    [date(2015,9, 3), 50, 30, 45],
    [date(2015,9, 4), 30, 25, 40],
    [date(2015,9, 5), 25, 35, 30],
    [date(2015,9, 6), 20, 40, 35],
]
for row in rows:
    ws.append(row)

# создаем объект диаграммы
chart = LineChart3D()
# устанавливаем атрибуты
chart.title = "3D Линейный график"
# легенда не нужна, т.к. 3-я ось совпадает
# с названиями столбцов выборки
chart.legend = None
chart.style = 15
chart.y_axis.title = 'Размер'
chart.x_axis.title = 'Номер теста'
# делаем выборку и добавляем ее в объект диаграммы
data = Reference(ws, min_col=2, min_row=1, max_col=4, max_row=7)
chart.add_data(data, titles_from_data=True)
# добавляем диаграмму на лист в ячейку "A10"
ws.add_chart(chart, "A10")

# сохраняем и смотрим что получилось
wb.save("line3D.xlsx")

Таблицы диаграмм XLSX-документа.

Диаграммы можно добавлять в специальные рабочие листы, называемые таблицами диаграмм, которые содержат только диаграммы.

Все данные для диаграммы должны быть на другом листе электронной таблицы.

from openpyxl import Workbook
from openpyxl.chart import PieChart, Reference, Series

wb = Workbook()
ws = wb.active
# создаем таблицу диаграммы
chartsheet = wb.create_chartsheet("Круговая диаграмма")

rows = [
    ["Bob", 3],
    ["Harry", 2],
    ["James", 4],
]
for row in rows:
    ws.append(row)

# создаем rheujde. lbfuhfvve
chart = PieChart()
# выбираем данные
labels = Reference(ws, min_col=1, min_row=1, max_row=3)
data = Reference(ws, min_col=2, min_row=1, max_row=3)
# добавляем данные 
chart.add_data(data, titles_from_data=False)
chart.set_categories(labels)
chart.title = "Круговая диаграмма"
# размеры диаграммы
chart.width = 15
chart.height = 15
# добавляем на лист диаграмм
chartsheet.add_chart(chart)

wb.save("create_chartsheet.xlsx")

Отображение определенных регионов на диаграмме.

Минимальные и максимальные значения осей можно установить вручную для отображения определенных регионов на диаграмме.

from openpyxl import Workbook
from openpyxl.chart import ScatterChart, Reference, Series

wb = Workbook()
ws = wb.active

#  данные диаграммы
ws.append(['X', '1/X'])
for x in range(-10, 11):
    if x:
        ws.append([x, 1.0 / x])

# ДИАГРАММА 1
chart1 = ScatterChart()
chart1.title = "Полные Оси"
chart1.x_axis.title = 'x'
chart1.x_axis.delete = False
chart1.y_axis.title = '1/x'
chart1.y_axis.delete = False
chart1.legend = None

# ДИАГРАММА 2
chart2 = ScatterChart()
chart2.title = "Clipped Axes"
chart2.x_axis.title = 'x'
chart2.x_axis.delete = False
chart2.y_axis.title = '1/x'
chart2.y_axis.delete = False
chart2.legend = None
# устанавливаем минимумы
chart2.x_axis.scaling.min = 0
chart2.y_axis.scaling.min = 0
# устанавливаем максимумы
chart2.x_axis.scaling.max = 11
chart2.y_axis.scaling.max = 1.5
# делаем выборку 
x = Reference(ws, min_col=1, min_row=2, max_row=22)
y = Reference(ws, min_col=2, min_row=2, max_row=22)
# собираем серию
series = Series(y, xvalues=x)
# добавляем в объекты диаграмм
chart1.append(series)
chart2.append(series)
# добавляем диаграммы на лист Excel
ws.add_chart(chart1, "d1")
ws.add_chart(chart2, "d17")

wb.save("minmax.xlsx")

Примечание. В некоторых случаях, таких как в примере, установка пределов оси фактически эквивалентна отображению поддиапазона данных. Для больших наборов данных визуализация точечных диаграмм (и, возможно, других) будет намного быстрее при использовании подмножеств данных, а не ограничений по осям как в Excel, так и в OpenOffice Calc/LibreOffice Calc.