Índice:
- Introducción.
- El libro.
- La hoja de cálculos (este capítulo).
- La celda.
- Los estilos.
- Los gráficos.
Después de ver un poco como eran los libros ahora nos vamos a centrar en las hojas o pestañas, que es donde se recogen los datos, fórmulas, gráficos, enlaces,…
Empezamos importando cosas que usaremos en este capítulo:
1 2 3 4 5 6 7 8 |
import io import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt import openpyxl from openpyxl.drawing.image import Image |
Vamos a empezar creando un notebook con algunos datos:
1 2 3 4 5 6 7 |
wb = openpyxl.Workbook() ws = wb.active for row in range(1, 101): for col in list("ABCDEFGHIJKL"): value = f"{col}{row}" ws[value] = value |
Hemos insertado 100 filas y 12 columnas donde el valor de cada celda en la primera columna es A1
, A2
, …, A100
, en la segunda columna es B1
, B2
, …, B100
,…
Si guardamos el notebook y lo abrimos podemos ver cómo queda:
1 |
wb.save("new.xlsx") |

Antes de seguir vamos a ver las cosas que tiene una hoja o pestaña:
1 2 3 |
for name in dir(ws): if not name.startswith("__"): print(name) |
Lo anterior mostrará:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
BREAK_COLUMN BREAK_NONE BREAK_ROW HeaderFooter ORIENTATION_LANDSCAPE ORIENTATION_PORTRAIT PAPERSIZE_A3 PAPERSIZE_A4 PAPERSIZE_A4_SMALL PAPERSIZE_A5 PAPERSIZE_EXECUTIVE PAPERSIZE_LEDGER PAPERSIZE_LEGAL PAPERSIZE_LETTER PAPERSIZE_LETTER_SMALL PAPERSIZE_STATEMENT PAPERSIZE_TABLOID SHEETSTATE_HIDDEN SHEETSTATE_VERYHIDDEN SHEETSTATE_VISIBLE _WorkbookChild__title _add_cell _add_column _add_row _cells _cells_by_col _cells_by_row _charts _clean_merge_range _comments _current_row _default_title _drawing _get_cell _hyperlinks _id _images _invalid_row _move_cell _move_cells _parent _path _pivots _print_area _print_cols _print_rows _rel_type _rels _setup _tables active_cell add_chart add_data_validation add_image add_pivot add_table append auto_filter calculate_dimension cell col_breaks column_dimensions columns conditional_formatting data_validations delete_cols delete_rows dimensions encoding evenFooter evenHeader firstFooter firstHeader formula_attributes freeze_panes insert_cols insert_rows iter_cols iter_rows legacy_drawing max_column max_row merge_cells merged_cell_ranges merged_cells mime_type min_column min_row move_range oddFooter oddHeader orientation page_breaks page_margins page_setup paper_size parent path print_area print_options print_title_cols print_title_rows print_titles protection row_breaks row_dimensions rows scenarios selected_cell set_printer_settings sheet_format sheet_properties sheet_state sheet_view show_gridlines show_summary_below show_summary_right tables title unmerge_cells values views |
Como podéis ver tenemos muchas más cosas que con un Workbook
ya que aquí es donde realmente se tiene información de datos, no solo metainformación, como en el libro.
Modificando propiedades generales de la hoja
Podemos modificar la hoja para definir el ancho de la columna, el valor por defecto de ancho, al altura de la fila,…
1 |
ws.sheet_format |
Lo anterior mostrará:
1 2 3 |
<openpyxl.worksheet.dimensions.SheetFormatProperties object> Parameters: baseColWidth=8, defaultColWidth=None, defaultRowHeight=15.0, customHeight=None, zeroHeight=None, thickTop=None, thickBottom=None, outlineLevelRow=None, outlineLevelCol=None |
Modificamos algunas cosas:
1 2 3 |
ws.sheet_format.baseColWidth = 4 ws.sheet_format.defaultRowHeight = 30 # etc |
Guardamos y visualizamos:
1 |
wb.save("new.xlsx") |

También tenemos una serie de propiedades. La mayoría de las cuales no sé muy bien para qué funcionan. Una referencia aquí. Por ejemplo, vamos a cambiar el color del lugar donde se visualiza la hoja o pestaña:
1 |
ws.sheet_properties |
Lo anterior nos muestra:
1 2 3 4 5 6 7 |
<openpyxl.worksheet.properties.WorksheetProperties object> Parameters: codeName=None, enableFormatConditionsCalculation=None, filterMode=None, published=None, syncHorizontal=None, syncRef=None, syncVertical=None, transitionEvaluation=None, transitionEntry=None, tabColor=None, outlinePr=<openpyxl.worksheet.properties.Outline object> Parameters: applyStyles=None, summaryBelow=True, summaryRight=True, showOutlineSymbols=None, pageSetUpPr=<openpyxl.worksheet.properties.PageSetupProperties object> Parameters: autoPageBreaks=None, fitToPage=None |
1 |
ws.sheet_properties.tabColor = "00cc00" |
Como anteriormente, guardamos y visualizamos:
1 |
wb.save("new.xlsx") |

Podemos hacer que la hoja aparezca oculta o visible:
1 |
ws.sheet_state |
Si el libro solo tiene una hoja esta no podrá ser invisible por lo que para que no dé error, en el caso de que queramos ocultarla, deberíamos tener dos o más hojas en el libro.
1 |
ws.sheet_state = "hidden" |
1 |
wb.save("new.xlsx") # esto dará error |
Lo anterior, como hemos comentado, dará un error:
1 |
ValueError: The only worksheet of a workbook cannot be hidden |
Le añadimos una hora, lo guardamos y lo abrimos:
1 |
wb.create_sheet() |
1 |
wb.save("new.xlsx") |

La volvemos a dejar visible:
1 |
ws.sheet_state = "visible" |
Podemos controlar como queremos que se vea la hoja. Si queremos que se vean las fórmulas o los valores obtenidos al aplicar la fórmula, si queremos que se vea el cabecero con el nombre de las columnas (A, B, C, D,…), podemos indicar si queremos que se vea el grid, si queremos cambiar el color del grid,… Toqueteamos un poco para ver esto en acción:
1 |
ws.sheet_view |
Lo anterior mostrará:
1 2 3 4 5 |
<openpyxl.worksheet.views.SheetView object> Parameters: windowProtection=None, showFormulas=None, showGridLines=None, showRowColHeaders=None, showZeros=None, rightToLeft=None, tabSelected=None, showRuler=None, showOutlineSymbols=None, defaultGridColor=None, showWhiteSpace=None, view=None, topLeftCell=None, colorId=None, zoomScale=None, zoomScaleNormal=None, zoomScaleSheetLayoutView=None, zoomScalePageLayoutView=None, zoomToFit=None, workbookViewId=0, pane=None, selection=[<openpyxl.worksheet.views.Selection object> Parameters: pane=None, activeCell='A1', activeCellId=None, sqref='A1'] |
1 2 |
# Definimos que la celda seleccionada sea la B3 en la hoja "Sheet" ws.sheet_view.selection[0].activeCell = "B3" |
1 |
wb.save("new.xlsx") |
Si lo abrís veréis que la celda seleccionada es la B3.
Algunas utilidades
Para conocer el rango de celdas usadas en la hoja:
1 |
ws.calculate_dimension() |
Lo anterior devolverá 'A1:L100'
.
Podemos colocar una imagen donde queramos. Vamos a crear una con matplotlib
y la vamos a añadir a la hoja (necesitaremos installar pillow
):
1 2 3 4 5 6 7 8 |
# Creamos la imagen fig, ax = plt.subplots() ax.plot((1,2,3)) stream = io.BytesIO() fig.savefig(stream, format="png") # La pegamos ws.add_image(Image(stream), "A10") |
Y lo guardamos y visualizamos:
1 |
wb.save("new.xlsx") |

Podemos ocultar filas y/o columnas:
1 2 3 |
# Ocultar o mostrar celdas ws.column_dimensions.group('A','D', hidden=True) ws.row_dimensions.group(3, 4, hidden=True) |
Guardamos y visualizamos:
1 |
wb.save('new.xlsx') |

Como veis en la anterior figura no se ven varias columnas y filas. Para volverlo a dejar como estaba podéis hacer:
1 2 3 |
# Ocultar o mostrar celdas ws.column_dimensions.group('A','D', hidden=False) ws.row_dimensions.group(3, 4, hidden=False) |
Podemos desplazar las celdas de la siguiente forma:
1 |
ws.move_range(ws.calculate_dimension(), rows=1, cols=1) |
Indicamos el rango de celdas que queremos mover y después indicamos el número de filas y/o columnas hasta donde lo queremos desplazar.
1 |
wb.save('new.xlsx') |
El resultado debajo donde se ve que hemos desplazado todas las celdas una columna y una fila hacia abajo y hacia la derecha, respectivamente:

Podemos unir celdas. En este caso voy a unir las celdas B1 a M1 para poner un cabecero a esas celdas:
1 2 3 |
# Antes metemos un valor en la celda B1 que será el que tomen las celdas unidas ws["B1"] = "Cabecero" ws.merge_cells(start_row=1, start_column=2, end_row=1, end_column=13) |
Indicamos desde donde hasta donde queremos unir.
[recordad que empezamos a contar por 1 y no por 0].
[CUIDADO: Al unir celdas se perderá el valor de todas menos la primera que será la que se use para las celdas unidas. Estos valores no se pueden volver a recuperar].
Si guardamos y abrimos el documento:
1 |
wb.save('new.xlsx') |

Vemos las celdas unidas con el texto ‘Cabecero’.
También podemos añadir/eliminar filas y/o columnas con los métodos:
insert_rows
: añade filas.insert_cols
: añade columnas.delete_rows
: elimina filas.delete_cols
: elimina columnas.
Vamos a eliminar, por ejemplo, la columna D, que actualmente contiene los valores (C1, C2, C3,..):
1 |
ws.delete_cols(4, amount=1) |
En el método hemos indicado desde qué columna (por su índice empezando por 1) y cuantas queremos eliminar en cantidad.
Guardamos y visualizamos:
1 |
wb.save('new.xlsx') |

Resumiendo
Vemos que la hoja nos permite hacer muchas más cosas que el libro, lo cual tiene todo el sentido del mundo. Hemos aprendido a hacer las cosas para manejar nuestros datos dentro de una hoja, hemos visto como pegar imágenes, mover celdas, eliminar columnas, unir celdas,… Estamos listos para ver una unidad más pequeña del rompecabezas, la celda.