openpyxl - налаштування розміру ширини стовпця


86

У мене є наступний сценарій, який перетворює файл CSV у файл XLSX, але розмір мого стовпця дуже вузький. Кожного разу мені доводиться перетягувати їх мишкою, щоб прочитати дані. Хтось знає, як встановити ширину стовпця openpyxl?

Ось код, який я використовую.

#!/usr/bin/python2.6
import csv
from openpyxl import Workbook
from openpyxl.cell import get_column_letter

f = open('users_info_cvs.txt', "rU")

csv.register_dialect('colons', delimiter=':')

reader = csv.reader(f, dialect='colons')

wb = Workbook()
dest_filename = r"account_info.xlsx"

ws = wb.worksheets[0]
ws.title = "Users Account Information"

for row_index, row in enumerate(reader):
    for column_index, cell in enumerate(row):
        column_letter = get_column_letter((column_index + 1))
        ws.cell('%s%s'%(column_letter, (row_index + 1))).value = cell

wb.save(filename = dest_filename)

Відповіді:


86

Ви можете оцінити (або використовувати шрифт моноширини), щоб досягти цього. Припустимо, дані є вкладеним масивом, як [['a1', 'a2'], ['b1', 'b2']]

Ми можемо отримати максимум символів у кожному стовпці. Потім встановіть для цього ширину. Ширина - це точно ширина монопросторового шрифту (якщо не змінювати принаймні інші стилі). Навіть якщо ви використовуєте шрифт із змінною шириною, це гідна оцінка. Це не буде працювати з формулами.

from openpyxl.utils import get_column_letter

column_widths = []
for row in data:
    for i, cell in enumerate(row):
        if len(column_widths) > i:
            if len(cell) > column_widths[i]:
                column_widths[i] = len(cell)
        else:
            column_widths += [len(cell)]

for i, column_width in enumerate(column_widths):
    worksheet.column_dimensions[get_column_letter(i+1)].width = column_width

Трохи зламати, але ваші звіти будуть більш читабельними.


Може у вас є уявлення про те , що буде питання тут: stackoverflow.com/questions/32642026 / ...
Pyderman

1
коли у мене є int як значення комірки, це призведе до помилки, оскільки int не має властивості len, чи є спосіб уникнути цього? Дякую!
Кевін Чжао,

1
@KevinZhao Трохи пізно - але ваше запитання адресовано тут: stackoverflow.com/questions/2189800 / ...
jonyfries

56

Моя варіація відповіді Буфке. Уникає трохи розгалуження масиву та ігнорує порожні комірки / стовпці.

Тепер виправлено для нерядкових значень комірок.

ws = your current worksheet
dims = {}
for row in ws.rows:
    for cell in row:
        if cell.value:
            dims[cell.column] = max((dims.get(cell.column, 0), len(str(cell.value))))    
for col, value in dims.items():
    ws.column_dimensions[col].width = value

Станом на openpyxl версії 3.0.3 вам потрібно використовувати

 dims[cell.column_letter] = max((dims.get(cell.column_letter, 0), len(str(cell.value))))

оскільки бібліотека openpyxl викличе помилку TypeError, якщо ви передасте column_dimensionsчисло замість літери стовпця, все інше може залишитися незмінним.


2
рядок 6 можна вдосконалити, використовуючи букву стовпця: dims [cell.column_letter] = max ((dims.get (cell.column_letter, 0), len (str (cell.value))))
Джонатан Л

38

Ще більш пітонічний спосіб встановити ширину всіх стовпців, який працює принаймні у версії 2.4.0 openpyxl:

for column_cells in worksheet.columns:
    length = max(len(as_text(cell.value)) for cell in column_cells)
    worksheet.column_dimensions[column_cells[0].column].width = length

Функція as_text повинна перетворювати значення у рядок належної довжини, як для Python 3:

def as_text(value):
    if value is None:
        return ""
    return str(value)

6
def as_text(value): return str(value) if value is not None else ""
thorhunter

4
@thorhunter len(cell.value or "") , не потрібно зайвих функцій
Ірина Великопольська,

2
@IrinaVelikopolskaya, якщо cell.value не реалізовано __len__, це призведе до винятку ( intабо, NoneTypeнаприклад)
thorhunter

2
@IrinaVelikopolskaya datetime - ще один приклад того, де можна отримати виняток. Здається, функція as_text найкраще працює для мене.
Software Prophets

10
Зверніть увагу, що в openpyxl 2.6 цей код не працює TypeError: expected <class 'str'>. Потрібно вказати назву стовпця зараз, тобто. ws.column_dimensions[openpyxl.utils.get_column_letter(column_cells[0].column)].width = lengthДив. Bitbucket.org/openpyxl/openpyxl/issues/1240/…
phihag

10

У мене проблема з merged_cells і автоматичний розмір не працює належним чином, якщо у вас така сама проблема, ви можете вирішити за допомогою наступного коду:

for col in worksheet.columns:
    max_length = 0
    column = col[0].column # Get the column name
    for cell in col:
        if cell.coordinate in worksheet.merged_cells: # not check merge_cells
            continue
        try: # Necessary to avoid error on empty cells
            if len(str(cell.value)) > max_length:
                max_length = len(cell.value)
        except:
            pass
    adjusted_width = (max_length + 2) * 1.2
    worksheet.column_dimensions[column].width = adjusted_width

7

Незначне покращення вищезгаданої прийнятої відповіді, яка, на мою думку, є більш пітонічною (просити прощення краще, ніж просити дозволу)

column_widths = []
for row in workSheet.iter_rows():
    for i, cell in enumerate(row):
        try:
            column_widths[i] = max(column_widths[i], len(str(cell.value)))
        except IndexError:
            column_widths.append(len(str(cell.value)))

for i, column_width in enumerate(column_widths):
    workSheet.column_dimensions[get_column_letter(i + 1)].width = column_width

Потрібно врахувати, якщо cell.value не є рядком. Наприклад, якщо cell.value має тип поплавця, буде потрібно кастинг типу
wontleave

2
вау, це було 4 роки тому. Ви маєте рацію, хоча я редагував, щоб виправити. Щойно додав акторський склад до струни.
shayst

5

У openpyxl 3.0.3 найкращий спосіб змінити стовпці - це об’єкт DimensionHolder , який є словником, що відображає кожен стовпець до об’єкта ColumnDimension . ColumnDimension може отримувати параметри bestFit , auto_size (що є псевдонімом bestFit) та width . Особисто auto_size працює не так, як очікувалося, і мені довелося використовувати ширину та задумавшись, що найкраща ширина для стовпця len(cell_value) * 1.23.

Щоб отримати значення кожної комірки, потрібно перебирати кожну з них, але я особисто не використовував її, оскільки в моєму проекті мені просто потрібно було писати робочі аркуші, тому я отримав найдовший рядок у кожному стовпці безпосередньо на моїх даних.

У прикладі нижче просто показано, як змінити розміри стовпців:

import openpyxl
from openpyxl.worksheet.dimensions import ColumnDimension, DimensionHolder
from openpyxl.utils import get_column_letter

wb = openpyxl.load_workbook("Example.xslx")
ws = wb["Sheet1"]

dim_holder = DimensionHolder(worksheet=ws)

for col in range(ws.min_column, ws.max_column + 1):
    dim_holder[get_column_letter(col)] = ColumnDimension(ws, min=col, max=col, width=20)

ws.column_dimensions = dim_holder

4

Це моя версія із посиланням на фрагмент коду @Virako

def adjust_column_width_from_col(ws, min_row, min_col, max_col):

        column_widths = []

        for i, col in \
                enumerate(
                    ws.iter_cols(min_col=min_col, max_col=max_col, min_row=min_row)
                ):

            for cell in col:
                value = cell.value
                if value is not None:

                    if isinstance(value, str) is False:
                        value = str(value)

                    try:
                        column_widths[i] = max(column_widths[i], len(value))
                    except IndexError:
                        column_widths.append(len(value))

        for i, width in enumerate(column_widths):

            col_name = get_column_letter(min_col + i)
            value = column_widths[i] + 2
            ws.column_dimensions[col_name].width = value

І як використовувати наступне,

adjust_column_width_from_col(ws, 1,1, ws.max_column)

4

Усі наведені вище відповіді породжують проблему, яка полягає в тому, що col [0] .column повертає номер, тоді як worksheet.column_dimensions [колонка] приймає замість стовпця лише такі символи, як 'A', 'B', 'C' Я змінив код @ Virako, і зараз він працює нормально.

import re
import openpyxl
..
for col in _ws.columns:
    max_lenght = 0
    print(col[0])
    col_name = re.findall('\w\d', str(col[0]))
    col_name = col_name[0]
    col_name = re.findall('\w', str(col_name))[0]
    print(col_name)
    for cell in col:
        try:
            if len(str(cell.value)) > max_lenght:
                max_lenght = len(cell.value)
        except:
            pass
    adjusted_width = (max_lenght+2)
    _ws.column_dimensions[col_name].width = adjusted_width

3

Ми можемо перетворити числа в їх значення ASCII і передати це параметру column_dimension

import openpyxl as xl

work_book = xl.load_workbook('file_location')
sheet = work_book['Sheet1']
column_number = 2
column = str(chr(64 + column_number))
sheet.column_dimensions[column].width = 20
work_book.save('file_location')

3

Мені довелося змінити @ User3759685 вище відповіді на це, коли openpxyl оновився. Я отримував повідомлення про помилку. Ну @phihag також повідомив про це в коментарях

for column_cells in ws.columns:
    new_column_length = max(len(as_text(cell.value)) for cell in column_cells)
    new_column_letter = (openpyxl.utils.get_column_letter(column_cells[0].column))
    if new_column_length > 0:
        ws.column_dimensions[new_column_letter].width = new_column_length + 1

2

Після оновлення з openpyxl2.5.2a до останнього 2.6.4 (остаточна версія для підтримки python 2.x), я отримав таку ж проблему при налаштуванні ширини стовпця.

В основному я завжди обчислюю ширину стовпця (dims - це дикт, що підтримує ширину кожного стовпця):

dims[cell.column] = max((dims.get(cell.column, 0), len(str(cell.value))))

Згодом я модифікую шкалу до чогось, що трохи перевищує початковий розмір, але тепер ви повинні вказати значення "Letter" стовпця, а не більше значення int (col внизу - це значення і переведено на потрібну літеру):

worksheet.column_dimensions[get_column_letter(col)].width = value +1 

Це виправить видиму помилку та присвоїть потрібну ширину стовпцю;) Сподіваюся, що це допоможе.


2

Ось відповідь на Python 3.8 та OpenPyXL 3.0.0.

Я намагався уникати використання get_column_letterфункції, але не вдалося.

Це рішення використовує нещодавно введені вирази присвоєння, також відомі як «моржовий оператор»:

import openpyxl
from openpyxl.utils import get_column_letter

workbook = openpyxl.load_workbook("myxlfile.xlsx")

worksheet = workbook["Sheet1"]

MIN_WIDTH = 10
for i, column_cells in enumerate(worksheet.columns, start=1):
    width = (
        length
        if (length := max(len(str(cell_value) if (cell_value := cell.value) is not None else "")
                          for cell in column_cells)) >= MIN_WIDTH
        else MIN_WIDTH
    )
    worksheet.column_dimensions[get_column_letter(i)].width = width

1
max(len(str(cell.value)) for cell in filter(None, column_cells))мені здається зрозумілішим.
Нуно Андре,

0

Це брудне виправлення. Але openpyxl насправді підтримує auto_fit. Але немає способу отримати доступ до власності.

import openpyxl
from openpyxl.utils import get_column_letter

wb = openpyxl.load_workbook("Example.xslx")
ws = wb["Sheet1"]
for i in range(1, ws.max_column+1):
    ws.column_dimensions[get_column_letter(i)].bestFit = True
    ws.column_dimensions[get_column_letter(i)].auto_size = True

0

Оскільки в openpyxl 2.6.1 для встановлення ширини потрібна буква стовпця, а не номер стовпця.

 for column in sheet.columns:
    length = max(len(str(cell.value)) for cell in column)
    length = length if length <= 16 else 16
    sheet.column_dimensions[column[0].column_letter].width = length
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.