2011-08-03 51 views
23

Estoy intentando crear un libro de Excel en el que pueda establecer automáticamente o ajustar automáticamente el ancho de las columnas antes de guardar el libro.Python xlwt: acceder al contenido de celda existente, ajustar automáticamente el ancho de la columna

He estado leyendo el tutorial de Python-Excel con la esperanza de encontrar a algunas funciones del xlwt que emulan los XLRD (como sheet_names(), cellname(row, col), cell_type, cell_value, y así sucesivamente ...) Por ejemplo, supongamos que tengo la siguientes:

from xlwt import Workbook  
wb = Workbook() 
sh1 = wb.add_sheet('sheet1' , cell_overwrite_ok = True)  
sh2 = wb.get_sheet(0) 

wb.get_sheet(0) es similar a la función ofrecida en rb.sheet_by_index(0) XLRD, excepto que el primero que permite modificar el contenido (siempre que el usuario ha establecido cell_overwrite_ok = True)

Suponiendo xlwt HACE fuera A pesar de las funciones que estoy buscando, estaba planeando revisar cada hoja de trabajo otra vez, pero esta vez haciendo un seguimiento del contenido que ocupa más espacio para una columna en particular, y establezco el ancho de la columna en función de eso. Por supuesto, también puedo hacer un seguimiento del ancho máximo de una columna específica mientras escribo en la hoja, pero creo que sería más limpio establecer los anchos una vez que todos los datos ya se hayan escrito.

¿Alguien sabe si puedo hacer esto? Si no, ¿qué recomienda hacer para ajustar el ancho de las columnas?

Respuesta

43

Acabo de implementar una clase contenedora que rastrea el ancho de los elementos a medida que los ingresa. Parece que funciona bastante bien.

import arial10 

class FitSheetWrapper(object): 
    """Try to fit columns to max size of any entry. 
    To use, wrap this around a worksheet returned from the 
    workbook's add_sheet method, like follows: 

     sheet = FitSheetWrapper(book.add_sheet(sheet_name)) 

    The worksheet interface remains the same: this is a drop-in wrapper 
    for auto-sizing columns. 
    """ 
    def __init__(self, sheet): 
     self.sheet = sheet 
     self.widths = dict() 

    def write(self, r, c, label='', *args, **kwargs): 
     self.sheet.write(r, c, label, *args, **kwargs) 
     width = arial10.fitwidth(label) 
     if width > self.widths.get(c, 0): 
      self.widths[c] = width 
      self.sheet.col(c).width = width 

    def __getattr__(self, attr): 
     return getattr(self.sheet, attr) 

Toda la magia está en John Yeung's arial10 module. Esto tiene buenos anchos para Arial 10, que es la fuente predeterminada de Excel. Si desea escribir hojas de cálculo con otras fuentes, deberá cambiar la función de ajuste de ancho, idealmente teniendo en cuenta el argumento style pasado al FitSheetWrapper.write.

+5

muy buena solución. Tuve que ajustar 'width = arial10.fitwidth (label)' con 'int (..)' ya que xlwt-0.7.5 plantea un ValueError en caso contrario. Si obtiene un ancho de celda ligeramente menor al requerido, intente con 'math.ceil (int (..))'. – dset0x

+7

El enlace al módulo arial10 se rompió para mí. Pero lo encontré en github: https://github.com/GeekPeduli/Sahana-Eden/blob/master/modules/arial10.py – Humphrey

+0

desafortunadamente esto no funcionará para las etiquetas más largas, como la anchura total puede ser superior a 65535 (que es excel máximo) – Jerzyk

4

No hay una instalación automática para esto en xlwt. Debe seguir el patrón general que describe, hacer un seguimiento del ancho máximo mientras escribe y establecer el ancho de la columna al final, en algún momento después de haber visto todos los datos, pero antes de haber guardado el libro de trabajo.

Tenga en cuenta que este es el enfoque más limpio y eficiente disponible cuando se trata de archivos de Excel. Si su noción de "después de que los datos ya se han escrito" significa después de que ya haya confirmado los valores de la celda ("escritura") pero antes de guardar realmente el libro, entonces el método descrito anteriormente está haciendo exactamente esto. Si lo que quiere decir es después de haber guardado el libro de trabajo, desea volver a leerlo para obtener los anchos máximos y luego guardarlo nuevamente con anchos de columna nuevos, esto será mucho más lento e implicará el uso de ambos xlwt y xlrd (y posiblemente xlutils también). También tenga en cuenta que cuando utiliza el Microsoft Excel original, no existe la noción de "actualizar" un archivo. Puede parecer así desde el punto de vista de un usuario, pero lo que sucede detrás de escena es que cada vez que se guarda, Excel sortea el archivo existente y escribe uno nuevo desde cero.

4

Si no está interesado en utilizar otra clase (FitSheetWrapper), esto se puede implementar utilizando el método de columna WorkSheet.

work = xlwt.WorkBook() 
sheet = work.add_sheet('Sheet1') 
for row_index in range(0,max_row): 
    for column_index in range(0,max_col) : 
     cwidth = sheet.col(column_index).width 
     if (len(column_data)*367) > cwidth: 
      sheet.col(column_index).width = (len(column_data)*367) #(Modify column width to match biggest data in that column) 

     sheet.write(row_index,column_index,column_data,style) 

El valor por defecto del ancho es de 2962 unidades y lo señala como 8.11 unidades. Por lo tanto, estoy multiplicando 367 por la longitud de los datos.

Esta es una adaptación de Kevins FitSheetWrapper.

1

FitSheetWrapper debe tener un poco de modificar con xlwt3 en 3.3.4

línea 19:

cambio:

width = arial10.fitwidth(label) 

a:

width = int(arial10.fitwidth(label)) 

razón: \ Python \ 3.3.3 \ Lib \ site-packages \ xlwt3 \ biffrecords.py

1624 def __init__(self, first_col, last_col, width, xf_index, options): 
1625  self._rec_data = pack('<6H', first_col, last_col, width, xf_index, options, 0) 

El ancho debe ser entero.

1

Esto puede ser un poco tarde, pero creado un método que hace esto para toda la hoja a la vez. Es rápido y hace el trabajo. El amortiguador extra param. solo es necesario si cree que el cálculo de 256 no será preciso (si tiene campos de texto más largos).

from xlrd import * 
from xlwt import * 

def autoAdjustColumns(workbook, path, writerSheet, writerSheet_index, extraCushion): 
    readerSheet = open_workbook(path).sheet_by_index(writerSheet_index) 
    for row in range(readerSheet.nrows): 
      for column in range(readerSheet.ncols): 
        thisCell = readerSheet.cell(row, column) 
        neededWidth = int((1 + len(str(thisCell.value))) * 256) 
        if writerSheet.col(column).width < neededWidth: 
          writerSheet.col(column).width = neededWidth + extraCushion 
    workbook.save(path) 
0

utilizo este método:

wb = Workbook() 
ws = wb.add_sheet('Sheet1') 
columnwidth = {} 
row = 0 
for rowdata in data: 
    column = 0 
    for colomndata in rowdata: 
     if column in columnwidth: 
      if len(colomndata) > columnwidth[column]: 
       columnwidth[column] = len(colomndata) 
     else: 
      columnwidth[column] = len(colomndata) 
     ws.write(row, column, colomndata, style0) 
     column = column + 1 
    row = row + 1 
for column, widthvalue in columnwidth.items(): 
    ws.col(column).width = (widthvalue + 4) * 367 
Cuestiones relacionadas