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

약간의 해킹이지만 보고서는 더 읽기 쉽습니다.


여기에 문제가 무엇인지
알 수 있습니까?

1
int를 셀 값으로 사용하면 int에 len 속성이 없기 때문에 오류가 발생합니다. 이것을 피할 수있는 방법이 있습니까? 감사!
Kevin Zhao

1
- @KevinZhao A는 조금 늦게하지만 문제는 여기에 언급되어 stackoverflow.com/questions/2189800/...
jonyfries

56

Bufke의 대답에 대한 나의 변형. 배열로 약간의 분기를 피하고 빈 셀 / 열을 무시합니다.

이제 문자열이 아닌 셀 값에 대해 수정되었습니다.

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 라이브러리는 column_dimensions열 문자 대신 숫자 를 전달하면 TypeError가 발생 하므로 다른 모든 항목은 동일하게 유지 될 수 있습니다.


2
6 행은 열 문자를 사용하도록 개선 될 수 있습니다. dims [cell.column_letter] = max ((dims.get (cell.column_letter, 0), len (str (cell.value))))
Jonathan L

38

적어도 openpyxl 버전 2.4.0에서 작동하는 모든 열의 너비를 설정하는 더 비단뱀적인 방법 :

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 "") , 추가 기능에 대한 필요가 없습니다
이리나 Velikopolskaya

2
@IrinaVelikopolskaya cell.value가 구현되지 않으면 __len__예외가 발생합니다 ( int또는 NoneType예)
thorhunter 2017 년

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.See 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에서 열을 수정하는 가장 좋은 방법 은 각 열을 ColumnDimension 개체에 매핑하는 사전 인 DimensionHolder 개체를 사용하는 것입니다 . 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이 숫자를 반환하는 반면 workstation.column_dimensions [column]은 열 대신 '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

openpxyl이 업데이트되었을 때 이에 대한 답변 위의 @ User3759685를 변경해야했습니다. 오류가 발생했습니다. @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는 각 열 너비를 유지하는 dict입니다).

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

나중에 원래 크기보다 조금 더 큰 값으로 배율을 수정하고 있지만 이제는 더 이상 int 값이 아닌 "Letter"값을 제공해야합니다 (아래의 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))나에게 더 명확 해 보인다.
Nuno André

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.