113

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

18 に答える 18

105

これを達成するために見積もる(または単幅フォントを使用する)ことができます。データが次のようなネストされた配列であると仮定しましょう

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

少しハックしますが、レポートはより読みやすくなります。

于 2013-01-22T02:20:42.643 に答える
72

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他のすべては同じままです。

于 2016-03-04T07:33:00.180 に答える
49

少なくともopenpyxlバージョン2.4.0で機能するすべての列の幅を設定するさらにPython的な方法:

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)
于 2016-12-02T15:03:24.787 に答える
20

openpyxl 3.0.3では、列を変更する最良の方法は、各列をColumnDimensionオブジェクトにマップするディクショナリであるDimensionHolderオブジェクトを使用することです。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
于 2020-03-22T16:12:21.583 に答える
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
于 2017-04-24T23:26:57.497 に答える
9

上記の受け入れられた答えのわずかな改善は、私がよりパイソン的だと思います(許しを求めることは許可を求めることよりも優れています)

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
于 2016-10-17T12:50:10.887 に答える
7

数値を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')
于 2019-06-20T06:31:49.710 に答える
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)
于 2019-05-15T02:48:33.663 に答える
4

上記のすべての回答は、col [0] .columnが数値を返しているのに対し、worksheet.column_dimensions[column]は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
于 2019-05-29T04:29:34.000 に答える
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
于 2019-08-24T00:44:25.840 に答える
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値ではなく、列の「文字」値を指定する必要があります(下の列は値であり、正しい文字に変換されます)。

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

これにより、目に見えるエラーが修正され、列に適切な幅が割り当てられます;)このヘルプが役立つことを願っています。

于 2019-11-11T09:38:58.657 に答える
2

これはダーティな修正です。しかし、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
于 2020-10-22T16:39:15.713 に答える
2

上記の複数の提案をコンパイルして適用し、マージされたセルの検出を水平方向にマージされたセルのみに拡張すると、次のコードを提供できます。

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
于 2021-07-07T17:01:01.807 に答える
2

状態を保存しない別のアプローチは、次のようになります。

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}"),
        )
于 2022-02-04T12:56:47.780 に答える
1

Python3.8とOpenPyXL3.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
于 2019-11-02T02:19:05.263 に答える
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
于 2020-11-27T13:31:45.490 に答える
1

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)

于 2021-05-26T17:22:41.430 に答える
1

これが思い浮かんだとき、openpyxlでやりたいことをすべて実行し、ブックを保存して、pywin32で再度開きました。Pywin32には、多数のルール/条件を作成することなく、autofitが組み込まれています。

編集: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()

ただし、表示する必要のない長い値を持つ1つのテキスト列があったため、ルールを追加しました。列を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()
 
于 2021-06-24T15:40:34.207 に答える