Tengo el siguiente script que convierte un archivo CSV en un archivo XLSX, pero el tamaño de mi columna es muy estrecho. Cada vez que tengo que arrastrarlos con el mouse para leer los datos. ¿Alguien sabe cómo establecer el ancho de la columna openpyxl
?
Aquí está el código que estoy usando.
#!/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)
Respuestas:
Puede estimar (o usar una fuente de ancho mono) para lograr esto. Supongamos que los datos son una matriz anidada como [['a1', 'a2'], ['b1', 'b2']]
Podemos obtener el máximo de caracteres en cada columna. Luego establezca el ancho a eso. El ancho es exactamente el ancho de una fuente monoespaciada (si no cambia otros estilos al menos). Incluso si usa una fuente de ancho variable, es una estimación decente. Esto no funcionará con fórmulas.
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
Un poco complicado, pero sus informes serán más legibles.
fuente
Mi variación de la respuesta de Bufke. Evita un poco de ramificación con la matriz e ignora las celdas / columnas vacías.
Ahora arreglado para valores de celda que no son cadenas.
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
A partir de la versión 3.0.3 de openpyxl, debe usar
dims[cell.column_letter] = max((dims.get(cell.column_letter, 0), len(str(cell.value))))
como la biblioteca openpyxl generará un TypeError si pasa
column_dimensions
un número en lugar de una letra de columna, todo lo demás puede permanecer igual.fuente
Una forma aún más pitónica de establecer el ancho de todas las columnas que funciona al menos en la versión 2.4.0 de openpyxl:
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
La función as_text debería ser algo que convierta el valor en una cadena de longitud adecuada, como para Python 3:
def as_text(value): if value is None: return "" return str(value)
fuente
def as_text(value): return str(value) if value is not None else ""
len(cell.value or "")
, no se necesitan funciones adicionales__len__
, esto arrojará una excepción (int
oNoneType
por ejemplo)TypeError: expected <class 'str'>
. Uno tiene que especificar un nombre de columna ahora, es decirws.column_dimensions[openpyxl.utils.get_column_letter(column_cells[0].column)].width = length
.Ver bitbucket.org/openpyxl/openpyxl/issues/1240/...Tengo un problema con merged_cells y el tamaño automático no funciona correctamente, si tienes el mismo problema, puedes resolverlo con el siguiente código:
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
fuente
Una ligera mejora de la respuesta aceptada anterior, que creo que es más pitónica (pedir perdón es mejor que pedir permiso)
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
fuente
Todas las respuestas anteriores están generando un problema que es que la columna [0] .columna devuelve un número mientras que la hoja de cálculo.columna_dimensiones [columna] acepta solo caracteres como 'A', 'B', 'C' en lugar de columna. He modificado el código de @ Virako y ahora funciona bien.
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
fuente
Con openpyxl 3.0.3, la mejor manera de modificar las columnas es con el objeto DimensionHolder , que es un diccionario que asigna cada columna a un objeto ColumnDimension . ColumnDimension puede obtener parámetros como bestFit , auto_size (que es un alias de bestFit) y ancho . Personalmente, auto_size no funciona como se esperaba y tuve que usar el ancho y me di cuenta de que el mejor ancho para la columna es
len(cell_value) * 1.23
.Para obtener el valor de cada celda es necesario iterar sobre cada una, pero yo personalmente no lo usé porque en mi proyecto solo tenía que escribir hojas de trabajo, así que obtuve la cadena más larga en cada columna directamente en mis datos.
El siguiente ejemplo solo muestra cómo modificar las dimensiones de la columna:
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
fuente
Esta es mi versión que hace referencia al fragmento de código de @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
Y cómo usarlo es el siguiente,
adjust_column_width_from_col(ws, 1,1, ws.max_column)
fuente
Podemos convertir números a sus valores ASCII y darle al parámetro 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')
fuente
Tuve que cambiar @ User3759685 la respuesta anterior a esto cuando se actualizó openpxyl. Recibí un error. Bueno, @phihag también informó esto en los comentarios.
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
fuente
Después de la actualización de openpyxl2.5.2a a la última 2.6.4 (versión final para el soporte de python 2.x), tuve el mismo problema al configurar el ancho de una columna.
Básicamente, siempre calculo el ancho de una columna (dims es un dictado que mantiene el ancho de cada columna):
dims[cell.column] = max((dims.get(cell.column, 0), len(str(cell.value))))
Luego estoy modificando la escala a algo un poco más grande que el tamaño original, pero ahora tienes que dar el valor de "Letra" de una columna y ya no un valor int (la columna de abajo es el valor y se traduce a la letra correcta):
worksheet.column_dimensions[get_column_letter(col)].width = value +1
Esto solucionará el error visible y asignará el ancho correcto a su columna;) Espero que esto ayude.
fuente
Aquí hay una respuesta para Python 3.8 y OpenPyXL 3.0.0.
Intenté evitar el uso de la
get_column_letter
función pero fallé.Esta solución utiliza las expresiones de asignación recientemente introducidas, también conocidas como "operador de 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
fuente
max(len(str(cell.value)) for cell in filter(None, column_cells))
me parece más claro.Esta es una solución sucia. Pero openpyxl realmente admite
auto_fit
. Pero no hay ningún método para acceder a la propiedad.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
fuente