openpyxl-调整列宽大小


81

我有以下脚本将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)

Answers:


84

您可以估计(或使用等宽字体)来实现此目的。假设数据是一个嵌套数组,例如[['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属性,这会遇到错误,有什么办法可以避免这种情况?谢谢!
Kevin Zhao

1
@KevinZhao有点晚了-但您的问题在这里得到解决:stackoverflow.com/questions/2189800/…–
jonyfries

53

我对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))))

因为如果您传递column_dimensions数字而不是列字母,openpyxl库将引发TypeError ,其他所有内容都可以保持不变。


2
可以改进第6行以使用列字母:dims [cell.column_letter] = max((dims.get(cell.column_letter,0),len(str(cell.value))))
Jonathan L

36

设置至少在openpyxl版本2.4.0中有效的所有列的宽度的更多pythonic方法:

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 "") ,不需要其他功能
Irina Velikopolskaya

2
@IrinaVelikopolskaya如果cell.value没有实现__len__,这将抛出异常(intNoneType例如)
thorhunter

2
@IrinaVelikopolskaya datetime是另一个发生异常的示例。as_text函数似乎最适合我。
软件先知

6
请注意,对于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有问题,并且autosize不能正常工作,如果您有同样的问题,则可以使用以下代码解决:

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

上面接受的答案略有改进,我认为是更pythonic的(寻求宽恕比寻求许可要好)

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年前的事了 您是正确的,尽管我进行了修复。刚刚在字符串上添加了强制类型转换。
阴沉的

4

以上所有答案均产生一个问题,即col [0] .column返回数字,而worksheet.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

4

对于openpyxl 3.0.3,修改列的最佳方法是使用DimensionHolder对象,该对象是将每个列映射到ColumnDimension对象的字典。ColumnDimension可以获取参数bestFitauto_size(这是bestFit的别名)和width。就个人而言,auto_size不能按预期工作,我不得不使用width并弄混了该列的最佳宽度是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

3

这是我的版本,引用@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)

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是保持每一列宽度的命令):

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

之后,我将比例尺修改为比原始大小稍大一些,但是现在您必须为列提供“字母”值,而不再是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

没用 至少不适用于Microsoft Excel。
Sirmabus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.