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

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


:あなたはここでの問題を何の考えている可能性がありますstackoverflow.com/questions/32642026/...
Pyderman

1
セル値としてintを使用している場合、intにはlenプロパティがないため、エラーが発生します。これを回避する方法はありますか?ありがとう!
Kevin Zhao

1
@KevinZhao A少し遅れて-しかし、あなたの質問はここで扱われている:stackoverflow.com/questions/2189800/...
jonyfries

56

ブフケの答えの私のバリエーション。配列との分岐を少し回避し、空のセル/列を無視します。

文字列以外のセル値で修正されました。

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

38

少なくとも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)

6
def as_text(value): return str(value) if value is not None else ""
thorhunter 2017

4
@thorhunter len(cell.value or "") 、追加機能は不要
Irina Velikopolskaya 2017年

2
@IrinaVelikopolskaya cell.valueが実装されていない場合__len__、これは例外をスローします(intまたはNoneTypeたとえば)
thorhunter 2017年

2
@IrinaVelikopolskaya datetimeは、例外が発生するもう1つの例です。as_text関数は私にとって最適に機能するようです。
ソフトウェアの予言者2018年

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がfloat型の場合、型キャストが必要になります
wontleave

2
すごい4年前のことです。私が修正するために編集しましたが、あなたは正しいです。文字列にキャストを追加しました。
最も恥ずかしがり屋の

5

openpyxl 3.0.3では、列を変更する最良の方法は、各列をColumnDimensionオブジェクトにマップするディクショナリであるDimensionHolderオブジェクトを使用することです。ColumnDimensionは、bestFitauto_sizebestFitのエイリアス)、および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

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が数値を返しているのに対し、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

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値ではなく、列の「文字」値を指定する必要があります(下の列は値であり、正しい文字に変換されます)。

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

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


2

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

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

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.