Меня просят создать несколько отчетов в формате Excel. В настоящее время я довольно активно использую pandas для своих данных, поэтому, естественно, я хотел бы использовать метод pandas.ExcelWriter для создания этих отчетов. Однако фиксированная ширина столбца является проблемой.
Код, который у меня есть до сих пор, достаточно прост. Скажем, у меня есть фрейм данных под названием 'df':
writer = pd.ExcelWriter(excel_file_path, engine='openpyxl')
df.to_excel(writer, sheet_name="Summary")
Я просматривал код pandas и на самом деле не вижу никаких вариантов для установки ширины столбцов. Есть ли уловка во вселенной, чтобы столбцы автоматически подстраивались под данные? Или есть что-то, что я могу сделать постфактум с файлом xlsx, чтобы настроить ширину столбцов?
(Я использую библиотеку OpenPyXL и создаю файлы .xlsx - если это имеет значение.)
Спасибо.
to_excel
,col_style=dict
который , возможно, содержит элементы стиля заголовка col (а не значение по умолчанию,header_style
которое, похоже, сейчас жестко закодированоОтветы:
Вдохновленный ответом user6178746 , у меня есть следующее:
# Given a dict of dataframes, for example: # dfs = {'gadgets': df_gadgets, 'widgets': df_widgets} writer = pd.ExcelWriter(filename, engine='xlsxwriter') for sheetname, df in dfs.items(): # loop through `dict` of dataframes df.to_excel(writer, sheet_name=sheetname) # send df to writer worksheet = writer.sheets[sheetname] # pull worksheet object for idx, col in enumerate(df): # loop through all columns series = df[col] max_len = max(( series.astype(str).map(len).max(), # len of largest item len(str(series.name)) # len of column name/header )) + 1 # adding a little extra space worksheet.set_column(idx, idx, max_len) # set column width writer.save()
источник
worksheet.set_column(idx+nlevels, idx+nlevels, max_len)
. В противном случае длина рассчитывается для первого столбца кадра, а затем применяется к первому столбцу в Excel, который, вероятно, является индексом.enumerate(df)
должно быть,enumerate(df.columns)
поскольку вы повторяете каждый столбец вdf
.dict
фактически выполняет итерацию по ключам вdict
(вам не нужно указывать вручнуюdict.keys()
), итерация по apd.DataFrame
выполняет итерацию по столбцам. Вам не нужно вручную перебиратьdf.columns
.Я публикую это, потому что я только что столкнулся с той же проблемой и обнаружил, что в официальной документации для Xlsxwriter и pandas эта функция все еще указана как неподдерживаемая. Я разработал решение, которое решило мою проблему. Я просто перебираю каждый столбец и использую workheet.set_column, чтобы установить ширину столбца == максимальную длину содержимого этого столбца.
Однако одно важное замечание. Это решение не подходит для заголовков столбцов, а только для значений столбцов. Это должно быть легко изменить, если вам нужно вместо этого подогнать заголовки. Надеюсь, это кому-то поможет :)
import pandas as pd import sqlalchemy as sa import urllib read_server = 'serverName' read_database = 'databaseName' read_params = urllib.quote_plus("DRIVER={SQL Server};SERVER="+read_server+";DATABASE="+read_database+";TRUSTED_CONNECTION=Yes") read_engine = sa.create_engine("mssql+pyodbc:///?odbc_connect=%s" % read_params) #Output some SQL Server data into a dataframe my_sql_query = """ SELECT * FROM dbo.my_table """ my_dataframe = pd.read_sql_query(my_sql_query,con=read_engine) #Set destination directory to save excel. xlsFilepath = r'H:\my_project' + "\\" + 'my_file_name.xlsx' writer = pd.ExcelWriter(xlsFilepath, engine='xlsxwriter') #Write excel to file using pandas to_excel my_dataframe.to_excel(writer, startrow = 1, sheet_name='Sheet1', index=False) #Indicate workbook and worksheet for formatting workbook = writer.book worksheet = writer.sheets['Sheet1'] #Iterate through each column and set the width == the max length in that column. A padding length of 2 is also added. for i, col in enumerate(my_dataframe.columns): # find length of column i column_len = my_dataframe[col].astype(str).str.len().max() # Setting the length if the column header is larger # than the max column value length column_len = max(column_len, len(col)) + 2 # set the column length worksheet.set_column(i, i, column_len) writer.save()
источник
()
функция внутри max: `max (column_len (), len (col)) +Вероятно, сейчас нет автоматического способа сделать это, но, поскольку вы используете openpyxl, следующая строка (адаптированная из другого ответа пользователя Bufke о том, как это сделать вручную ) позволяет вам указать разумное значение (в ширине символов):
writer.sheets['Summary'].column_dimensions['A'].width = 15
источник
column_dimensions
атрибутов. Если вы хотите продолжать использовать openpyxl, просто укажите это при создании писателя usingpd.ExcelWriter(excel_filename, engine='openpyxl')
Xlsxwriter
в качестве движка, чтобы узнать, как указать ширину столбца с сегодняшним движком по умолчанию.Есть хороший пакет, который я начал использовать недавно, под названием StyleFrame.
он получает DataFrame и позволяет очень легко его стилизовать ...
по умолчанию ширина столбцов регулируется автоматически.
например:
from StyleFrame import StyleFrame import pandas as pd df = pd.DataFrame({'aaaaaaaaaaa': [1, 2, 3], 'bbbbbbbbb': [1, 1, 1], 'ccccccccccc': [2, 3, 4]}) excel_writer = StyleFrame.ExcelWriter('example.xlsx') sf = StyleFrame(df) sf.to_excel(excel_writer=excel_writer, row_to_add_filters=0, columns_and_rows_to_freeze='B2') excel_writer.save()
вы также можете изменить ширину столбцов:
sf.set_column_width(columns=['aaaaaaaaaaa', 'bbbbbbbbb'], width=35.3)
ОБНОВЛЕНИЕ 1
В версии 1.4
best_fit
добавлен аргументStyleFrame.to_excel
. См. Документацию .ОБНОВЛЕНИЕ 2
Вот пример кода, который работает для StyleFrame 3.xx
from styleframe import StyleFrame import pandas as pd columns = ['aaaaaaaaaaa', 'bbbbbbbbb', 'ccccccccccc', ] df = pd.DataFrame(data={ 'aaaaaaaaaaa': [1, 2, 3, ], 'bbbbbbbbb': [1, 1, 1, ], 'ccccccccccc': [2, 3, 4, ], }, columns=columns, ) excel_writer = StyleFrame.ExcelWriter('example.xlsx') sf = StyleFrame(df) sf.to_excel( excel_writer=excel_writer, best_fit=columns, columns_and_rows_to_freeze='B2', row_to_add_filters=0, ) excel_writer.save()
источник
best_fit
параметре. Кроме того, когда я попробовал это, я получил очень плохие результаты .index
параметр, но без кубиков.sf.apply_headers_style(Styler(bold=False))
мне потребовалось много времени, чтобы понять это. И в заявлении импортаfrom StyleFrame import StyleFrame, Styler
. вот все варианты, кроме жирного: styleframe.readthedocs.io/en/2.0.5/…from styleframe import StyleFrame
, чтобы соответствовать соглашениям обИспользуя pandas и xlsxwriter, вы можете выполнить свою задачу, приведенный ниже код будет отлично работать в Python 3.x. Для получения дополнительной информации о работе с XlsxWriter с пандами может быть полезна эта ссылка https://xlsxwriter.readthedocs.io/working_with_pandas.html
import pandas as pd writer = pd.ExcelWriter(excel_file_path, engine='xlsxwriter') df.to_excel(writer, sheet_name="Summary") workbook = writer.book worksheet = writer.sheets["Summary"] #set the column width as per your requirement worksheet.set_column('A:A', 25) writer.save()
источник
Динамически регулировать длину всех столбцов
writer = pd.ExcelWriter('/path/to/output/file.xlsx') df.to_excel(writer, sheet_name='sheetName', index=False, na_rep='NaN') for column in df: column_length = max(df[column].astype(str).map(len).max(), len(column)) col_idx = df.columns.get_loc(column) writer.sheets['sheetName'].set_column(col_idx, col_idx, column_length)
Вручную настройте столбец с помощью имени столбца
col_idx = df.columns.get_loc('columnName') writer.sheets['sheetName'].set_column(col_idx, col_idx, 15)
Вручную настроить столбец с помощью индекса столбца
writer.sheets['sheetName'].set_column(col_idx, col_idx, 15)
Если что-либо из вышеперечисленного не работает с
AttributeError: 'Worksheet' object has no attribute 'set_column'
обязательно установите
xlsxwriter
:источник
Я обнаружил, что более полезно настраивать столбец на основе заголовка столбца, а не содержимого столбца.
С помощью
df.columns.values.tolist()
я создаю список заголовков столбцов и использую длину этих заголовков для определения ширины столбцов.Смотрите полный код ниже:
import pandas as pd import xlsxwriter writer = pd.ExcelWriter(filename, engine='xlsxwriter') df.to_excel(writer, index=False, sheet_name=sheetname) workbook = writer.book # Access the workbook worksheet= writer.sheets[sheetname] # Access the Worksheet header_list = df.columns.values.tolist() # Generate list of headers for i in range(0, len(header_list)): worksheet.set_column(i, i, len(header_list[i])) # Set column widths based on len(header) writer.save() # Save the excel file
источник
На работе я всегда пишу фреймы данных в файлы Excel. Поэтому вместо того, чтобы писать один и тот же код снова и снова, я создал модуль. Теперь я просто импортирую его и использую для записи и форматирования файлов Excel. Однако есть один недостаток: если фрейм данных очень большой, требуется много времени. Итак, вот код:
def result_to_excel(output_name, dataframes_list, sheet_names_list, output_dir): out_path = os.path.join(output_dir, output_name) writerReport = pd.ExcelWriter(out_path, engine='xlsxwriter', datetime_format='yyyymmdd', date_format='yyyymmdd') workbook = writerReport.book # loop through the list of dataframes to save every dataframe into a new sheet in the excel file for i, dataframe in enumerate(dataframes_list): sheet_name = sheet_names_list[i] # choose the sheet name from sheet_names_list dataframe.to_excel(writerReport, sheet_name=sheet_name, index=False, startrow=0) # Add a header format. format = workbook.add_format({ 'bold': True, 'border': 1, 'fg_color': '#0000FF', 'font_color': 'white'}) # Write the column headers with the defined format. worksheet = writerReport.sheets[sheet_name] for col_num, col_name in enumerate(dataframe.columns.values): worksheet.write(0, col_num, col_name, format) worksheet.autofilter(0, 0, 0, len(dataframe.columns) - 1) worksheet.freeze_panes(1, 0) # loop through the columns in the dataframe to get the width of the column for j, col in enumerate(dataframe.columns): max_width = max([len(str(s)) for s in dataframe[col].values] + [len(col) + 2]) # define a max width to not get to wide column if max_width > 50: max_width = 50 worksheet.set_column(j, j, max_width) writerReport.save() return output_dir + output_name
источник
Объединение других ответов и комментариев, а также поддержка мультииндексов:
def autosize_excel_columns(worksheet, df): autosize_excel_columns_df(worksheet, df.index.to_frame()) autosize_excel_columns_df(worksheet, df, offset=df.index.nlevels) def autosize_excel_columns_df(worksheet, df, offset=0): for idx, col in enumerate(df): series = df[col] max_len = max(( series.astype(str).map(len).max(), len(str(series.name)) )) + 1 worksheet.set_column(idx+offset, idx+offset, max_len) sheetname=... df.to_excel(writer, sheet_name=sheetname, freeze_panes=(df.columns.nlevels, df.index.nlevels)) worksheet = writer.sheets[sheetname] autosize_excel_columns(worksheet, df) writer.save()
источник
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
источник
Самое простое решение - указать ширину столбца в методе set_column.
for worksheet in writer.sheets.values(): worksheet.set_column(0,last_column_value, required_width_constant)
источник
def auto_width_columns(df, sheetname): workbook = writer.book worksheet= writer.sheets[sheetname] for i, col in enumerate(df.columns): column_len = max(df[col].astype(str).str.len().max(), len(col) + 2) worksheet.set_column(i, i, column_len)
источник
Да, есть кое-что, что вы можете сделать постфактум с файлом xlsx, чтобы настроить ширину столбцов. Используйте xlwings для автоматического подбора столбцов. Это довольно простое решение, см. Шесть последних строк кода примера. Преимущество этой процедуры в том, что вам не нужно беспокоиться о размере шрифта, типе шрифта или чем-либо еще. Требование: установка Excel.
import pandas as pd import xlwings as xw report_file = "test.xlsx" df1 = pd.DataFrame([ ('this is a long term1', 1, 1, 3), ('this is a long term2', 1, 2, 5), ('this is a long term3', 1, 1, 6), ('this is a long term2', 1, 1, 9), ], columns=['term', 'aaaa', 'bbbbbbb', "cccccccccccccccccccccccccccccccccccccccccccccc"]) writer = pd.ExcelWriter(report_file, engine="xlsxwriter") df1.to_excel(writer, sheet_name="Sheet1", index=False) workbook = writer.book worksheet1 = writer.sheets["Sheet1"] num_format = workbook.add_format({"num_format": '#,##0.00'}) worksheet1.set_column("B:D", cell_format=num_format) writer.save() # Autofit all columns with xlwings. app = xw.App(visible=False) wb = xw.Book(report_file) for ws in wb.sheets: ws.autofit(axis="columns") wb.save(report_file) app.quit()
источник