web-dev-qa-db-fra.com

Existe-t-il un moyen d’ajuster automatiquement la largeur des colonnes Excel avec pandas.ExcelWriter?

On me demande de générer des rapports Excel. J'utilise actuellement énormément les pandas pour mes données, donc naturellement, j'aimerais utiliser la méthode pandas.ExcelWriter pour générer ces rapports. Cependant, les largeurs de colonne fixes sont un problème. 

Le code que j'ai jusqu'à présent est assez simple. Disons que j'ai un cadre de données appelé 'df':

writer = pd.ExcelWriter(Excel_file_path)
df.to_Excel(writer, sheet_name="Summary")

Je parcourais le code des pandas et je ne vois pas vraiment d'options permettant de définir la largeur des colonnes. Existe-t-il une astuce dans l'univers pour que les colonnes s'ajustent automatiquement aux données? Ou y a-t-il quelque chose que je puisse faire après coup dans le fichier xlsx pour ajuster la largeur des colonnes? 

(J'utilise la bibliothèque OpenPyXL et génère des fichiers .xlsx, si cela change quelque chose.)

Je vous remercie.

50
badideas

Inspiré par la réponse de user6178746 , j'ai les éléments suivants:

# 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()
18
alichaudry

Il n’ya probablement aucun moyen automatique de le faire pour le moment, mais comme vous utilisez openpyxl, la ligne suivante (adaptée d’une autre réponse donnée par l’utilisateur Bufke on comment le faire manuellement ) vous permet de spécifier valeur (en largeur de caractère):

writer.sheets['Summary'].column_dimensions['A'].width = 15
17
ojdo

Je publie cela parce que je viens de rencontrer le même problème et que la documentation officielle de Xlsxwriter et des pandas contient toujours cette fonctionnalité non prise en charge. J'ai piraté ensemble une solution qui résolvait le problème que j'avais. En gros, je parcoure chaque colonne et utilise worksheet.set_column pour définir la largeur de la colonne == la longueur maximale du contenu de cette colonne. 

Une note importante, cependant. Cette solution ne correspond pas aux en-têtes de colonne, mais simplement aux valeurs de colonne. Cela devrait être un changement facile si vous devez plutôt adapter les en-têtes. J'espère que ça aide quelqu'un :)

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()
16
user6178746

Il y a un paquet gentil que j'ai commencé à utiliser récemment appelé StyleFrame.

il récupère DataFrame et vous permet de le styler très facilement ...

par défaut, la largeur des colonnes s'ajuste automatiquement.

par exemple:

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

vous pouvez aussi changer la largeur des colonnes:

sf.set_column_width(columns=['aaaaaaaaaaa', 'bbbbbbbbb'],
                    width=35.3)


METTRE À JOUR

Dans la version 1.4, l'argument best_fit a été ajouté à StyleFrame.to_Excel. Voir le documentation .

11
AsafSH

En utilisant pandas et xlsxwriter, vous pouvez vous acquitter de votre tâche. Le code ci-dessous fonctionnera parfaitement dans Python 3.x. Pour plus de détails sur l’utilisation de XlsxWriter avec pandas, ce lien peut être utile 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()
2
Ashu007

J'ai trouvé qu'il était plus utile d'ajuster la colonne en fonction de son en-tête plutôt que de son contenu.

En utilisant df.columns.values.tolist(), je génère une liste des en-têtes de colonne et utilise la longueur de ces en-têtes pour déterminer la largeur des colonnes.

Voir le code complet ci-dessous:

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
1
jack1536

La solution la plus simple consiste à spécifier la largeur de la colonne dans la méthode set_column. 

    for worksheet in writer.sheets.values():
        worksheet.set_column(0,last_column_value, required_width_constant)
0
Ashish Jith
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
0
Ssubrat Rrudra

Combinant les autres réponses et commentaires et prenant également en charge les multi-indices:

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()
0
kgibm