Mam następujący skrypt, który konwertuje plik CSV do pliku XLSX, ale rozmiar mojej kolumny jest bardzo wąski. Za każdym razem muszę przeciągać je myszą, aby odczytać dane. Czy ktoś wie, jak ustawić szerokość kolumny w openpyxl
?
Oto kod, którego używam.
#!/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)
Odpowiedzi:
Aby to osiągnąć, możesz oszacować (lub użyć czcionki o stałej szerokości). Załóżmy, że dane są zagnieżdżoną tablicą, taką jak [['a1', 'a2'], ['b1', 'b2']]
Możemy uzyskać maksymalną liczbę znaków w każdej kolumnie. Następnie ustaw na to szerokość. Szerokość to dokładnie szerokość czcionki o stałej szerokości (jeśli nie zmienia się przynajmniej innych stylów). Nawet jeśli używasz czcionki o zmiennej szerokości, jest to przyzwoita ocena. To nie zadziała w przypadku formuł.
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
Trochę hack, ale Twoje raporty będą bardziej czytelne.
źródło
Moja odmiana odpowiedzi Bufkego. Unika rozgałęziania się z tablicą i ignoruje puste komórki / kolumny.
Teraz naprawiono dla wartości komórek niebędących ciągami.
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
Od wersji 3.0.3 openpyxl musisz użyć
dims[cell.column_letter] = max((dims.get(cell.column_letter, 0), len(str(cell.value))))
ponieważ biblioteka openpyxl zgłosi błąd TypeError, jeśli podasz
column_dimensions
liczbę zamiast litery w kolumnie, wszystko inne może pozostać takie samo.źródło
Jeszcze bardziej pythonowy sposób na ustawienie szerokości wszystkich kolumn, który działa przynajmniej w openpyxl w wersji 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
Funkcja as_text powinna być czymś, co konwertuje wartość na ciąg o odpowiedniej długości, jak w Pythonie 3:
def as_text(value): if value is None: return "" return str(value)
źródło
def as_text(value): return str(value) if value is not None else ""
len(cell.value or "")
, nie potrzeba dodatkowych funkcji__len__
, zgłosi wyjątek (int
lubNoneType
na przykład)TypeError: expected <class 'str'>
. Należy teraz podać nazwę kolumny, np.ws.column_dimensions[openpyxl.utils.get_column_letter(column_cells[0].column)].width = length
Patrz bitbucket.org/openpyxl/openpyxl/issues/1240/…Mam problem z komórkami scalonymi i autosize nie działają poprawnie, jeśli masz ten sam problem, możesz rozwiązać następnym kodem:
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
źródło
Nieznaczna poprawa powyższej akceptowanej odpowiedzi, która moim zdaniem jest bardziej pytoniczna (prośba o wybaczenie jest lepsza niż prośba o pozwolenie)
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
źródło
W openpyxl 3.0.3 najlepszym sposobem modyfikacji kolumn jest obiekt DimensionHolder , który jest słownikiem mapującym każdą kolumnę na obiekt ColumnDimension . ColumnDimension może pobierać parametry takie jak bestFit , auto_size (co jest aliasem bestFit) i width . Osobiście auto_size nie działa zgodnie z oczekiwaniami i musiałem użyć szerokości i zamazałem, że najlepsza szerokość kolumny to
len(cell_value) * 1.23
.Aby uzyskać wartość każdej komórki, konieczne jest iterowanie po każdej z nich, ale osobiście jej nie użyłem, ponieważ w moim projekcie musiałem tylko napisać arkusze, więc uzyskałem najdłuższy ciąg w każdej kolumnie bezpośrednio na moich danych.
Poniższy przykład pokazuje, jak zmodyfikować wymiary kolumny:
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
źródło
To jest moja wersja odnosząca się do fragmentu kodu @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
Sposób użycia jest następujący:
adjust_column_width_from_col(ws, 1,1, ws.max_column)
źródło
Wszystkie powyższe odpowiedzi generują problem, który polega na tym, że kolumna [0] .kolumna zwraca liczbę, podczas gdy arkusz roboczy.column_dimensions [kolumna] akceptuje tylko znaki takie jak „A”, „B”, „C” zamiast kolumny. Zmodyfikowałem kod @ Virako i teraz działa dobrze.
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
źródło
Możemy przekonwertować liczby na ich wartości ASCII i przekazać to parametrowi 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')
źródło
Musiałem zmienić powyższą odpowiedź @ User3759685 na to, gdy aktualizacja openpxyl. Otrzymałem błąd. @Phihag również zgłosił to w komentarzach
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
źródło
Po aktualizacji z openpyxl2.5.2a do najnowszej wersji 2.6.4 (ostateczna wersja obsługująca python 2.x), mam ten sam problem z konfiguracją szerokości kolumny.
Zasadniczo zawsze obliczam szerokość kolumny (dims to dykt, który zachowuje szerokość każdej kolumny):
dims[cell.column] = max((dims.get(cell.column, 0), len(str(cell.value))))
Następnie modyfikuję skalę do czegoś nieco większego niż rozmiar oryginalny, ale teraz musisz podać wartość „Letter” kolumny, a nie wartość int (kolumna poniżej jest wartością i jest tłumaczona na prawą literę):
worksheet.column_dimensions[get_column_letter(col)].width = value +1
To naprawi widoczny błąd i przypisanie odpowiedniej szerokości do twojej kolumny;) Mam nadzieję, że to pomoże.
źródło
Oto odpowiedź na Python 3.8 i OpenPyXL 3.0.0.
Próbowałem uniknąć używania tej
get_column_letter
funkcji, ale nie udało mi się.W tym rozwiązaniu używane są nowo wprowadzone wyrażenia przypisania znane jako „operator morsa”:
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
źródło
max(len(str(cell.value)) for cell in filter(None, column_cells))
wydaje mi się jaśniejsze.To jest brudna poprawka. Ale openpyxl faktycznie obsługuje
auto_fit
. Ale nie ma metody dostępu do nieruchomości.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
źródło
Ponieważ w openpyxl 2.6.1 wymaga litery kolumny, a nie numeru kolumny, podczas ustawiania szerokości.
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
źródło