Creación, edición y análisis de XLSX
| Tarea | Enfoque |
|---|---|
| Crear o editar con fórmulas/formato | openpyxl — ver notas importantes abajo |
| Datos masivos de entrada o salida | pandas (read_excel, to_excel) |
| Vistazo rápido a una hoja | markitdown archivo.xlsx — ## NombreHoja por hoja; también lee .xlsm. Sin coordenadas de celdas, así que no planifiques ediciones a partir de él |
| Leer un modelo (fórmulas y valores) | dos pasadas de load_workbook — ver notas importantes |
openpyxl,pandasymarkitdownestán preinstalados — no ejecutespip installprimero; escribe el script e importa directamente. Solo si una importación falla (o falta el comandomarkitdown):pip installel paquete faltante.
Las rutas de los scripts a continuación son relativas al directorio de esta habilidad.
Requisitos para cada salida
- Fuente profesional (Arial, Times New Roman) en todo, a menos que el usuario indique lo contrario.
- Cero errores de fórmula. Nunca entregues mientras
recalc.pyreporteerrors_found. Si crees que un error es anterior a tu trabajo, demuéstralo: carga el original condata_only=Truey revisa esa celda. Un error que introdujiste se ve exactamente igual que uno heredado. - Usa fórmulas, nunca resultados fijos. Escribe
sheet['B10'] = '=SUMA(B2:B9)', no el total calculado en Python. La hoja debe recalcularse cuando sus entradas cambien. - Sigue la especificación del usuario al pie de la letra. Nombres de pestañas exactos, encabezados de columna exactos y la fórmula que ellos detallaron. Un rediseño que calcula algo diferente falla, por más elegante que sea.
- Documenta cada suposición y número fijo donde el lector pueda verlo: un comentario de celda o una celda adyacente al final de una tabla. Cita una fuente real cuando exista (
Fuente: 10-K de la empresa, FY2024, Página 45, Nota de Ingresos, [URL SEC EDGAR]); cuando el número provenga del usuario, dilo claramente. - Un libro que tú creas para que alguien lo llene necesita una breve leyenda que nombre qué celdas editar, y una fila de ejemplo con valores realistas que muestre el formato esperado. Nunca agregues esa fila a un archivo que te pidieron editar.
- Editar un archivo existente: respeta sus convenciones exactamente. Ellas anulan cada directriz aquí. Encuentra primero sus celdas de entrada designadas — un color de fuente, relleno o sombreado distinto las marca — escribe solo allí y deja intacta cada fórmula existente.
Recalcular (obligatorio cuando el archivo contiene fórmulas)
openpyxl escribe fórmulas como cadenas sin valores cacheados. Hasta que recalcules, cada celda de fórmula se lee como None para todo lo que lea valores cacheados — pandas, load_workbook(data_only=True) y la mayoría de los visores.
python scripts/recalc.py salida.xlsx [segundos_timeout] # por defecto 30
LibreOffice calcula cada fórmula, el archivo se reescribe en el lugar y obtienes JSON: status (success | errors_found), total_formulas, total_errors, y un error_summary que nombra hasta 100 celdas por tipo de error (locations_truncated dice cuántas omitió — confía en total_errors, no en la longitud de la lista). Arregla lo que nombre y ejecútalo de nuevo. JSON con una clave error en lugar de status significa que no se recalculó nada, y solo ese caso termina con código distinto de cero — errors_found termina con 0, así que nunca trates una salida limpia como un libro limpio.
Un recálculo exitoso prueba que tus fórmulas evalúan, no que son correctas. Un rango con error por uno o una referencia a la fila incorrecta produce un archivo limpio y sin errores con números incorrectos. Escribe 2–3 fórmulas primero y verifica que tomen los valores esperados, antes de construir una cuadrícula completa.
Un libro que enlaza a otro archivo pierde esos enlaces si lo re-guardas con openpyxl y luego recalculas. Tal fórmula lee ='[1]Análisis de Retornos'!$B$2 — el [1] es un índice en la lista de referencias externas del libro, que nombra un archivo separado en disco, no una hoja. Ese archivo rara vez está presente aquí, por lo que el valor cacheado de la celda es lo único que contiene sus datos. openpyxl elimina ese valor al guardar; entonces LibreOffice tiene que resolver la referencia realmente, falla, escribe #¿NOMBRE? y elimina todos los enlaces. recalc.py se niega a ejecutarse en ese estado — copia los valores de esas celdas del original antes de guardar sobre él (--force anula y acepta la pérdida).
Elegir fórmulas que sobrevivan la verificación
LibreOffice implementa menos funciones que Excel, y una que no puede evaluar se convierte en un literal #¿NOMBRE? grabado en el archivo que entregas.
- Prefiere funciones de la era de Excel 2007 —
SUMAR.SI.CONJUNTO,INDICE,COINCIDIR,SI.ERROR,SUMAPRODUCTO— que no necesitan prefijo. - Seis funciones posteriores a 2007 funcionan, pero solo con el prefijo
_xlfn., porque openpyxl escribe tu fórmula textualmente en el XML y Excel almacena los nombres posteriores a 2007 con prefijo (su UI oculta el prefijo):_xlfn.TEXTOJUNTAR,_xlfn.CONCATENAR,_xlfn.SI.CONJUNTO,_xlfn.CAMBIAR,_xlfn.MAX.SI.CONJUNTO,_xlfn.MIN.SI.CONJUNTO. Escritas sin prefijo, producen#¿NOMBRE?. - Nunca uses
XLOOKUP,XMATCH,SORT,FILTER,UNIQUEoSEQUENCE. El runtime de LibreOffice no puede evaluarlas bajo ningún prefijo. Las construcciones más nuevas sí las evalúan, pero son funciones de matriz dinámica y un archivo escrito por openpyxl no tiene metadatos de propagación, por lo que solo la celda superior izquierda del rango obtiene un valor — yrecalc.pyreportatotal_errors: 0sobre el resultado truncado. UsaINDICE/COINCIDIRpara búsquedas, y ordena, filtra y elimina duplicados en Python antes de escribir las celdas. - Una fórmula que LibreOffice no pudo analizar se escribe de vuelta en minúsculas — una pista rápida junto a un
#¿NOMBRE?.
Notas importantes de openpyxl
- Leer un modelo requiere dos cargas.
data_only=Trueproduce valores cacheados con las fórmulas desaparecidas; el valor por defecto produce cadenas de fórmula sin valores. Una sola pasada no puede darte ambas cosas. data_only=Truees destructivo si guardas. Ese libro no tiene fórmulas restantes, por lo que guardar reemplaza cada una con un valor literal — permanentemente.data_only=Trueen un archivo que openpyxl acaba de escribir devuelveNoneen todas partes — ejecutarecalc.pyprimero. (Una fórmula cuyo resultado es""también se lee comoNone).- Celdas combinadas: escribe solo el ancla superior izquierda. Cada otra celda en el rango es una
MergedCellcuyo.valuees solo de lectura. .xlsmpierde sus macros a menos que paseskeep_vba=Trueaload_workbook.- Un nombre de hoja que contiene un espacio debe ir entre comillas en una referencia entre hojas:
='Supuestos Entradas'!$B$5. Sin comillas, evalúa a#¡VALOR!.
Modelos financieros
A menos que el usuario indique lo contrario, o que el archivo existente ya haga otra cosa.
Color: texto azul (0,0,255) para entradas fijas y palancas de escenario · negro para fórmulas · verde (0,128,0) para enlaces a otra hoja · rojo (255,0,0) para enlaces a otro archivo · relleno amarillo (255,255,0) para supuestos clave y celdas que el usuario debe llenar.
Números: moneda $#,##0, con la unidad nombrada en el encabezado (Ingresos ($mm)) · los ceros se muestran como -, incluso en porcentajes ($#,##0;($#,##0);-) · negativos entre paréntesis · porcentajes 0.0%, almacenados como fracciones (0.15 muestra 15.0%; almacenar 15 muestra 1500.0%) · múltiplos de valoración 0.0x · años como texto ("2024", nunca 2,024).
Estructura: cada supuesto en su propia celda etiquetada, referenciado por las fórmulas que lo usan (=B5*(1+$B$6), nunca =B5*1.05) · fórmulas consistentes en cada período de proyección, ya que una celda modificada aislada en medio de una fila es el error silencioso más común · protege denominadores que pueden ser cero.
Dependencias
openpyxl, pandas, markitdown (pip, preinstalados — instala solo si una importación falla o falta el comando) · LibreOffice (soffice, auto-configurado para entornos aislados mediante scripts/office/soffice.py)