Openpyxl - 调整列宽大小

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

https://dev59.com/CVoV5IYBdhLWcg3wEreD - Smart Manoj
21个回答

4

这个方法并不太优雅,但是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

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

https://xkcd.com/1171/ - scign

3
当我遇到这个问题时,我只是使用openpyxl做了我想做的一切,保存工作簿,然后用pywin32再次打开。Pywin32内置了自适应宽度,无需制定大量规则/条件。
编辑:我应该注意到,pywin32仅适用于Windows。
from win32com.client import Dispatch

excel = Dispatch('Excel.Application')
wb = excel.Workbooks.Open("excelFile.xlsx")

excel.Worksheets(1).Activate()
excel.ActiveSheet.Columns.AutoFit()

wb.Save()
wb.Close()
excel.Quit()

我添加了一条规则,因为我有一个文本列的值很长,而且我不需要展示所有的信息。所以我将任何列的字符限制在75个字符以内。

excel = Dispatch('Excel.Application')
wb = excel.Workbooks.Open("excelFile.xlsx")

excel.Worksheets(1).Activate()
excel.ActiveSheet.Columns.AutoFit()

for col in excel.ActiveSheet.Columns:
    if col.ColumnWidth > 75:
        col.ColumnWidth = 75

wb.Save()
wb.Close()
excel.Quit()
 

1
这是目前为止最好的方法(运行起来非常顺畅),但是它在Linux上不会起作用,对吧? - Angel
@Ángel 这是正确的。不幸的是,pywin32 只适用于 Windows。我本应该在那时添加一个注释,但没有想到。 - bpw1009

3

编译和应用多个建议,扩展到仅水平合并单元格的合并单元格检测后,我可以提供以下代码:

def adjust_width(ws):
    """
    Adjust width of the columns
    @param ws: worksheet
    @return: None
    """

    def is_merged_horizontally(cell):
        """
        Checks if cell is merged horizontally with an another cell
        @param cell: cell to check
        @return: True if cell is merged horizontally with an another cell, else False
        """
        cell_coor = cell.coordinate
        if cell_coor not in ws.merged_cells:
            return False
        for rng in ws.merged_cells.ranges:
            if cell_coor in rng and len(list(rng.cols)) > 1:
                return True
        return False

    for col_number, col in enumerate(ws.columns, start=1):
        col_letter = get_column_letter(col_number)

        max_length = max(
            len(str(cell.value or "")) for cell in col if not is_merged_horizontally(cell)
        )
        adjusted_width = (max_length + 2) * 0.95
        ws.column_dimensions[col_letter].width = adjusted_width

这个代码完美运行,只需要进行一个小小的简单更改。adjusted_width = (max_length + 2) * 0.8 - SomeSimpleton

3

当openpyxl更新时,我不得不更改@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

我写了一个函数,使用pandas.read_excel来处理大型Excel文件,因此速度非常快。

import pandas as pd
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter

def auto_adjust_column_width(file_path, sheet_name=0):
    column_widths = []

    df = pd.read_excel(file_path, sheet_name=sheet_name, header=None)
    for col in df.columns:
        max_length = int(df[col].astype(str).str.len().max() * 1.2)
        column_widths.append(max_length)

    wb = load_workbook(file_path)
    if isinstance(sheet_name, int):
        sheet_name = wb.sheetnames[sheet_name]

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


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 

这将修复可见错误并为您的列分配正确的宽度;) 希望这有所帮助。

1

只需在您的文件中插入以下代码行

# Imorting the necessary modules
try:
        from openpyxl.cell import get_column_letter
except ImportError:
        from openpyxl.utils import get_column_letter
        from openpyxl.utils import column_index_from_string
from openpyxl import load_workbook
import openpyxl
from openpyxl import Workbook



for column_cells in sheet.columns:
    new_column_length = max(len(str(cell.value)) for cell in column_cells)
    new_column_letter = (get_column_letter(column_cells[0].column))
    if new_column_length > 0:
        sheet.column_dimensions[new_column_letter].width = new_column_length*1.23

1
以下代码使用特定字体计算和调整宽度:
# example of usage: 
# adjust_excel_column_widths(worksheet, 'calibri', 11)

import math
from PIL import ImageFont
from openpyxl import worksheet
from openpyxl.utils.cell import get_column_letter

def adjust_excel_column_widths(worksheet: worksheet, fontname, fontsize):
    
    def points_to_pixels(points):
        return points * 4 / 3 # 1pnt = 4/3px

    font = ImageFont.truetype(fontname, points_to_pixels(fontsize)) 
    excel_unit_width = font.getlength('0')

    def getwidth(cell_value):
        return 0.0 if cell_value is None else font.getlength(str(cell_value))

    column_number = 0
    for column in worksheet.columns:
        column_number += 1
        column_letter = get_column_letter(column_number)
        column_width = math.ceil( max(getwidth(cell.value) for cell in column) / excel_unit_width )
        worksheet.column_dimensions[column_letter].width = column_width

1
自从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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接