Ширина столбцов и высота строк в openpyxl
Длинные названия больше не обрезаются: column_dimensions задаёт ширины столбцов, row_dimensions — высоты строк, а автоширина считается циклом по самой длинной строке.
Редакция Питоники
Таблица из прошлых уроков окрашена шрифтом и заливкой, заголовок склеен merge_cells — но «Кофе зерновой, 1 кг» всё равно показывается как «Кофе зернов...». Excel ширины столбцов подбирает мышкой, а openpyxl — присваиванием: у каждого столбца есть настройка ширины, у каждой строки — высоты. В этом уроке закрываем внешний вид таблицы полностью, включая автоматический подбор ширин — фирменный приём генераторов прайсов.
Ширина столбца: column_dimensions
Ширины живут в ws.column_dimensions — справочнике столбцов по буквам: "A", "B", "C". Присваивание полю width задаёт ширину.
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws["A1"] = "Наименование товара"
ws.column_dimensions["A"].width = 24 # единица - символ шрифта
print("Ширина A:", ws.column_dimensions["A"].width)
print("Ширина B:", ws.column_dimensions["B"].width)
Ширина A: 24.0 Ширина B: 13.0
Столбец A получил ширину 24, а B отвечает 13.0 — значение по умолчанию внутри openpyxl для столбца, которому ширину не назначали; в файл оно не пишется, и Excel рисует такой столбец своей стандартной шириной, чуть больше восьми символов. Важна сама единица измерения: ширина считается не в пикселях и не в сантиметрах, а в символах стандартного шрифта книги. Число 24 означает «вмещает примерно 24 символа шрифта по умолчанию».
| Настройка | Ключ | Единица |
|---|---|---|
| Ширина столбца | column_dimensions["A"].width | символы стандартного шрифта |
| Высота строки | row_dimensions[1].height | пункты, как размер шрифта |
| Скрытие столбца | column_dimensions["B"].hidden | True / False |
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws["A1"] = "виден"
ws["B1"] = "скрыт"
ws.column_dimensions["B"].hidden = True # столбец исчезнет из вида
print("Скрыт B:", ws.column_dimensions["B"].hidden)
print("Скрыт A:", ws.column_dimensions["A"].hidden)
Скрыт B: True Скрыт A: False
У столбца в том же справочнике есть и другие переключатели: hidden прячет служебные колонки — техпаспорта, внутренние артикулы, — не удаляя их из файла. Работает это в паре с шириной: спрятанный столбец сохраняет свою настройку и вернётся, когда hidden сбросят в False.
Высота строки: row_dimensions
Строки адресуются в ws.row_dimensions номерами — без букв. Высота меряется в пунктах, как размер шрифта: стандартная строка Excel для кегля 11 — около 15 пунктов, шапке с крупным шрифтом дают 22–30.
Зачем вообще трогать высоту, если Excel подбирает её сам? Две причины. Первая — дизайн: шапке с жирным шрифтом 12 пунктов нужен воздух, иначе текст упирается в границы, нарисованные в прошлом уроке. Вторая — контроль: высота, заданная явно, не изменится, когда файл откроют в другой версии Excel или LibreOffice, а автоподбор там может сработать иначе. Управляешь высотой — управляешь тем, как файл выглядит у всех.
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws["A1"] = "Шапка"
ws.row_dimensions[1].height = 30 # высота строки в пунктах
print("Высота 1:", ws.row_dimensions[1].height)
print("Высота 2:", ws.row_dimensions[2].height)
Высота 1: 30.0 Высота 2: None
Строке, которой высоту не назначали, соответствует None: настройка не записана, и Excel рисует строку стандартной. Та же логика, что у ширин: присвоил — значение записалось в файл, не присвоил — работает умолчание табличного редактора.
from openpyxl import Workbook
from openpyxl.styles import Alignment
wb = Workbook()
ws = wb.active
ws["A2"] = "Длинное описание, которое занимает несколько строк"
ws["A2"].alignment = Alignment(wrap_text=True, vertical="top")
ws.row_dimensions[2].height = 45 # высоту под перенос задаём сами
print("Перенос:", ws["A2"].alignment.wrap_text)
print("Высота 2:", ws.row_dimensions[2].height)
Перенос: True Высота 2: 45.0
Высота и перенос работают в паре: wrap_text из урока 6 переносит текст по словам, а height отводит под него место — без явной высоты Excel сделает это сам, но в сгенерированных файлах неплохо контролировать результат самим, чтобы строки не сжались при открытии в старых версиях.
Автоширина: считаем по самой длинной строке
Задавать каждую ширину руками — та же ручная работа, от которой мы уходим. Генераторы отчётов считают ширины сами: обходят столбцы, находят самое длинное значение и назначают ширину с запасом. Свойство ws.columns отдаёт столбцы готовыми порциями — кортежами ячеек, а у ячейки есть column_letter — буква её столбца.
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.append(["Товар", "Цена"])
ws.append(["Кофе зерновой, 1 кг", 690])
ws.append(["Чай чёрный", 120])
ws.append(["Сироп топинамбура", 340])
for column_cells in ws.columns:
longest = max(len(str(cell.value or "")) for cell in column_cells)
letter = column_cells[0].column_letter
ws.column_dimensions[letter].width = longest + 3
for letter in ("A", "B"):
print(letter, "-", ws.column_dimensions[letter].width)
A - 22.0 B - 7.0
Сердце приёма — одна строка: max(len(str(cell.value or "")) for cell in column_cells). Разбираем её по кускам: cell.value or "" подставляет пустую строку вместо None — иначе len(None) упадёт с TypeError; str(...) превращает числа в строки, чтобы их длина тоже считалась; max выбирает длиннейшее. К нему добавляем запас в три символа — и ни одно название не обрежется. Для столбца A победила строка из 19 символов «Кофе зерновой, 1 кг», плюс три — двадцать два.
Всё это опирается на два свойства листа: ws.columns отдаёт столбцы кортежами ячеек, ws.rows — строки. Размеры листа считаются простым len по спискам — пригодится и для проверок «а там вообще есть данные?».
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.append(["a", "b", "c"])
ws.append(["d", "e", "f"])
print(len(list(ws.rows)), len(list(ws.columns)))
2 3
Две строки по три ячейки: строк две, столбцов три. Числа совпадают с max_row и max_column из урока 4, но через rows и columns ты получаешь сами ячейки — со стилями, которые пригодятся, когда размеры и оформление нужно считать одновременно.
Столбцы — буквами, строки — числами
Автоподбор — не единственный способ считать ширины. Если у таблицы фиксированная структура, ширины удобно держать в словаре-конфигурации: колонка — ширина. Такой словарь живёт в начале скрипта, правится в одном месте и применяется циклом.
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.append(["Итог", "Комментарий"])
widths = {"A": 10, "B": 40}
for letter, width in widths.items():
ws.column_dimensions[letter].width = width
print(ws.column_dimensions["A"].width, ws.column_dimensions["B"].width)
10.0 40.0
Словарь можно отдать параметром командной строки или прочитать из настроек — и один и тот же скрипт начнёт генерировать прайсы под разные шаблоны. Между «считать по содержимому» и «задать руками» есть и гибрид: автоширина с потолком — min(longest + 3, 60), чтобы описание на абзац не растянуло столбец на весь экран.
Самая коварная опечатка темы: справочники похожи, а ключи у них разные. Столбец — буква в кавычках, строка — число без кавычек. Перепутаешь — никакой ошибки не будет.
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.column_dimensions["1"].width = 20 # опечатка: цифра вместо буквы A
ws.row_dimensions["2"].height = 25 # и тут: строка вместо числа
print("Столбец A настроен:", "A" in ws.column_dimensions)
print("Столбец '1' настроен:", "1" in ws.column_dimensions)
print("Строка 1 настроена:", 1 in ws.row_dimensions)
print("Строка '2' настроена:", "2" in ws.row_dimensions)
Столбец A настроен: False Столбец '1' настроен: True Строка 1 настроена: False Строка '2' настроена: True
Отсюда же — совет для функций-обёрток: если ширина приходит параметром, приводи ключ к букве на входе. В openpyxl нет отдельного исключения «нет такого столбца»: справочник column_dimensions принимает любой ключ как приказ создать настройку. Хорошая обёртка валидирует буквы столбцов заранее — например, проверкой, что ключ состоит из латинских букв и входит в диапазон от A до XFD.
Ширины и высоты живут в файле
Настройки размеров — часть xlsx, как стили и значения: сохранил — они переживают закрытие, открыл через load_workbook — они на месте. Это удобно для скриптов, которые дочитывают и дочищают готовые файлы.
Из этого следует и рабочая привычка: размеры задавай до сохранения, одним куском с данными. Скрипт, который создаёт файл, знает про него всё — и длины текстов, и число строк; откладывать настройку ширин «на потом» в другом скрипте значит снова собирать эти знания по крохам. Генератор, который отдаёт файл сразу готовым к показу, — признак зрелого кода.
from openpyxl import Workbook, load_workbook
import os
wb = Workbook()
ws = wb.active
ws["A1"] = "Отчёт"
ws.column_dimensions["A"].width = 30
ws.row_dimensions[1].height = 24
wb.save("report-l7.xlsx")
book = load_workbook("report-l7.xlsx") # ширины и высоты сохраняются в файле
sheet = book.active
print("Ширина A:", sheet.column_dimensions["A"].width)
print("Высота 1:", sheet.row_dimensions[1].height)
os.remove("report-l7.xlsx")
Ширина A: 30.0 Высота 1: 24.0
Первая программа: прайс с автошириной
from openpyxl import Workbook
import os
wb = Workbook()
ws = wb.active
ws.append(["Товар", "Цена, руб.", "Остаток"])
for row in [
["Кофе зерновой, 1 кг", 690, 14],
["Чай чёрный", 120, 40],
["Сироп топинамбура", 340, 9],
]:
ws.append(row)
ws.row_dimensions[1].height = 22 # шапке - чуть больше воздуха
# автоширина: по самой длинной ячейке каждого столбца
for column_cells in ws.columns:
longest = max(len(str(cell.value or "")) for cell in column_cells)
ws.column_dimensions[column_cells[0].column_letter].width = longest + 3
for letter in ("A", "B", "C"):
print(letter, ws.column_dimensions[letter].width)
wb.save("price-l7.xlsx")
os.remove("price-l7.xlsx")
A 22.0 B 13.0 C 10.0
Обрати внимание на столбец B: самое длинное значение — три символа «690», но победила шапка «Цена, руб.» из десяти символов, плюс запас — тринадцать. Автоподбор считает и заголовки тоже, и это правильно: шапка обрезается ничуть не лучше, чем данные. Внешний вид прайса теперь закрыт целиком: стили из пятого урока, объединение и выравнивание из шестого, размеры отсюда. Дальше по курсу — числовые форматы: рубли, проценты и разделители разрядов, о которых Excel мечтает, когда видит голые числа.
- запас два-три символа — для цифр и коротких слов;
- запас четыре — для кириллицы с заглавными и длинных названий;
- объединённые ячейки и переносы в расчёт не включай — считай только строки данных;
- проверяй результат глазами в Excel: ширина в символах — приближение, а не пиксельная точность.
Что дальше
Ты умеешь задавать размеры вручную и считать их сам: column_dimensions для столбцов, row_dimensions для строк, цикл с max(len(...)) для автоширины. Это последний урок «внешнего вида» — со следующего openpyxl начинает разговаривать с Excel на языке чисел: форматы рублей и процентов, а затем даты. Сохрани свой скрипт прайса — в десятке уроков он станет основой финального проекта с диаграммой.
И финальный штрих дисциплины: размеры, как и стили, — часть контракта генератора. Файл, который после запуска не нужно дорабатывать мышкой, — это и есть автоматизация; всё, что требует ручной доводки, рано или поздно доедет до того, кто забудет выровнять колонки.
Кнопки «Автоподбор ширины» в openpyxl нет — её заменяют три строки: найти самое длинное значение столбца и назначить width с запасом.
Сначала предскажи ответ в голове — это главный навык программиста.
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.column_dimensions["A"].width = 20
ws.row_dimensions[2].height = 15
print(ws.column_dimensions["A"].width, ws.row_dimensions[2].height)
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.append(["SKU", "Название"])
ws.append(["k1", "Молоко"])
for column_cells in ws.columns:
longest = max(len(str(c.value or "")) for c in column_cells)
ws.column_dimensions[column_cells[0].column_letter].width = longest + 2
print(int(ws.column_dimensions["A"].width), int(ws.column_dimensions["B"].width))
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws["B1"] = "x"
ws.row_dimensions[1].height = 40
print(ws.row_dimensions[1].height, ws.row_dimensions[2].height)
1. В каких единицах измеряется ширина столбца в openpyxl?
2. Как задать высоту второй строки равной 30?
3. Как в openpyxl реализовать автоподбор ширины столбца?
4. Что будет после ws.column_dimensions["1"].width = 20?
5. Сохраняются ли заданные ширины столбцов в xlsx-файле?
Собери таблицу курсов: шапка ["Валюта", "Курс"] и две строки — Доллар 93, Евро 100. Задай высоте шапки 26 пунктов, затем посчитай автоширину обоих столбцов: len самой длинной ячейки плюс 2. Выведи ширины столбцов A и B как целые числа, сохрани файл rate-ex-l7.xlsx и удали его.
Как изменить ширину столбца в Excel через openpyxl?
ws.column_dimensions["A"].width = 24 — по букве столбца. Единица измерения — символ стандартного шрифта, а не пиксель, поэтому значение подбирают с запасом в два-три символа. Автоподбор считается циклом: max(len(str(cell.value or "")) for cell in ws["A"]) плюс запас.
Как задать высоту строки в openpyxl?
ws.row_dimensions[1].height = 30 — по номеру строки, без кавычек. Высота меряется в пунктах, как размер шрифта: стандартная строка — около 15, шапкам с крупным текстом дают 22–30. Не заданной строке соответствует None — Excel рисует её стандартной.
Почему ширина столбца не соответствует заданному числу пикселей?
Потому что width в openpyxl и Excel измеряется в символах стандартного шрифта книги, а не в пикселях: одно и то же число вмещает разное количество текста разными гарнитурами. Пиксели зависят от шрифта и масштаба экрана, поэтому от них и абстрагировались. Подбирай значения по длине содержимого с запасом.
Как сделать автоподбор ширины всех столбцов сразу?
Циклом по ws.columns: для каждого столбца найди max(len(str(cell.value or "")) for cell in column_cells) и назначь width с прибавкой 2–3. Обходить удобно со второй строки, если в шапке сидит объединённый заголовок — иначе его длина раздует первый столбец.
Понравился урок? Сошлитесь на него
«Единица ширины столбца — не пиксель, а символ стандартного шрифта: одно и то же число 20 по-разному вмещает текст узким шрифтом и широким.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что читать дальше
openpyxl · Урок 5
Форматирование ячеек: шрифт, заливка и границы в openpyxl
Шапка прайса — жирный белый на синем, границы на всю таблицу: Font, PatternFill и Border, и главное правило — один стиль на весь диапазон.
openpyxl · Урок 6
Выравнивание и объединение ячеек в openpyxl: merge_cells
Заголовок на всю ширину таблицы по центру: merge_cells объединяет ячейки, Alignment выравнивает и переносит текст — и не наступаем на MergedCell.
openpyxl · Урок 8
Числовые форматы в openpyxl: рубли, проценты и разделители
Строка number_format превращает голое 1234.5 в «1 234.50 ₽»: задаём рубли, проценты и разделители тысяч — и разбираемся, почему значение ячейки при этом не меняется.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Pandas · Урок 3
Выборка данных в Pandas: loc, iloc и фильтрация строк по условию
loc и iloc, булева маска, isin и between — достаём из таблицы заказов именно те строки и столбцы, которые нужны, и не попадаемся на SettingWithCopyWarning.
как отфильтровать строки в pandas по условиюpandas выбрать строки по условию
Pandas · Урок 5
Группировка groupby в Pandas: агрегация как в Excel, только мощнее
groupby, agg и pivot_table — считаем выручку по городам и товарам, строим сводные таблицы и не теряем строки с NaN.
сводные таблицы pythongroupby несколько столбцов
openpyxl · Урок 12
Диаграммы в Excel через openpyxl: BarChart и LineChart
Собираем настоящие диаграммы Excel из кода: BarChart по продажам недели и LineChart по выручке — Reference, add_data, категории, якорь и размеры в сантиметрах.
BarChart openpyxlopenpyxl диаграмма