可调整列宽的大小

我有以下脚本,这是转换一个 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)
244097 次浏览

您可以估计(或使用单宽度字体)来实现这一点

[['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,1):  # ,1 to start at 1
worksheet.column_dimensions[get_column_letter(i)].width = column_width

虽然有点粗糙,但你的报告会更易读。

我的 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 库将引发 TypeError,如果您传递给 column_dimensions的是一个数字而不是一个列字母,那么其他所有内容都可以保持不变。

对上述已被接受的答案的一个小小的改进,我认为这个答案更加简洁(请求原谅比请求许可要好)

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

在 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)

我遇到了 merge _ cell 和 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

这是我引用@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)

以上所有的答案都产生了一个问题,那就是 col[0]。Column 返回的是数字,而 worksheet.column _ sions [ column ]只接受‘ A’、‘ B’、‘ C’等字符来代替 column。我已经修改了@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

我们可以将数字转换为它们的 ASCII 值,并将其赋给 column _ 維参数

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')

当 openpxyl 更新时,我不得不更改上面的@User3759685来回答这个问题。我出错了。Well@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

下面是 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

在从 openpyxl2.5.2 a 更新到最新的2.6.4(python 2.x 支持的最终版本)之后,我在配置列的宽度方面遇到了同样的问题。

基本上,我总是计算一个列的宽度(dims 是维护每个列宽度的 dict) :

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

之后,我修改了一个比原来的大小稍微大一点的值,但是现在你必须给出一个列的“字母”值,而不再是一个 int 值(下面的 coll 是这个值,它被翻译成了正确的字母) :

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

这将修复可见错误,并为列分配正确的宽度;) 希望这个能帮上忙。

对于 openpyxl 3.0.3,修改列的最佳方法是使用 尺寸保持器对象,它是一个字典,将每个列映射到一个 柱维度对象。 ColumnScale 可以获得参数 最佳身材Auto _ size(这是 best Fit 的别名)和 宽度。 就个人而言,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

这是一个肮脏的修复。但 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

因为在 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

我创建了一个函数,它在使用大型 Excel 文件时速度非常快,因为它使用了 Pandas.read _ 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)


当我遇到这个问题时,我只是使用 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()
 

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

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

不存储任何状态的另一种方法可以是这样的:

from itertools import chain
# Using `ws` as the Worksheet
for cell in chain.from_iterable(ws.iter_cols()):
if cell.value:
ws.column_dimensions[cell.column_letter].width = max(
ws.column_dimensions[cell.column_letter].width,
len(f"{cell.value}"),
)

下面是一个更通用、简化的解决方案,适用于刚接触该主题的用户(没有为该问题指定)。

如果您想在 openpyxl(版本3.0.9)中更改单元格的宽度或高度,只需将单元格的属性分配给 row_dimensionscolumn_dimensions即可。

import openpyxl
wb = openpyxl.Workbook()
sheet = wb["Sheet"]




sheet["A1"] = "Tall row"
sheet["B2"] = "Wide column"


# Change height of row A1
sheet.row_dimensions[1].height = 100
# Change width of column B
sheet.column_dimensions["B"].width = 50


wb.save("StackOverflow.xlsx")

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

# 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