Una hoja de cálculo con sus celdas en mi Emacs
He aprovechado la Semana Santa para desconectar en el pueblo, con su olor a campo y a leña quemada en el hogar. La intención era haberme movido algo más, salir a pasear al campo o a la anual recolecta de espárragos o cardillos. Sin embargo, la climatología tenía otros planes y me ha tenido en casa encerrado. Ya le hacía falta al campo un poco de agua, pero a mí no hacía falta regarme, no voy a crecer estando ya agostado... En fin, a lo que iba. Que como he tenido tiempo estuve cotilleando un modo de Emacs que me había comentado alguien a raíz de mi artículo sobre el uso del texto plano y que hasta ahora no había probado.
Utilizando una hoja de cálculo SES
En ese artículo comentaba que utilizo las tablas de org-mode
como
si de hojas de cálculo se tratasen y la verdad es que dan bastante
juego para editar, calcular e imprimirlas en nuestros documentos; o
incluso para realizar gráficos desde ellas con gnuplot
. Al poco de
publicar aquel artículo, alguien me habló del modo SES
1 que
viene por defecto con nuestro querido Emacs.
La diferencia fundamental con el uso de las tablas de org-mode
es
que SES
monta un buffer especial que se ordena en filas y columnas
como lo hace una hoja de cálculo al uso... Pero no esperéis grandes
cosas: lo de Simple que lleva en el nombre no es por falsa modestia.
Es todo muy sencillo y muy básico. Voy a hacer un ejemplo, bastante
similar al que viene en la documentación de SES
pero luego lo
destriparé un poco más para ver cómo funciona el formato.
Imaginemos que lo he utilizado para controlar algunos gastos de esta Semana Santa y me he hago una tabla como sigue:
- Crear ─o visitar─ mediante
C-x C-f
un archivo que se va a llamargastos.ses
: hay que observar que la extensión.ses
es importante para que Emacs entre en modoSES
. Al hacerlo me encuentro un buffer casi vacío con una etiquetaA
y una zona subrayada, con el cursor allí situado... nuestra hoja sólo tiene, de momento, una celda: laA1
. Si observamos la línea de estado, nos mostrará en qué celda está situado el cursor... ¡seguimos! - Pulso
"
, las comillas dobles, y me pregunta por una cadena de texto. EscriboConcepto
y de nuevo<RET>
. Ahora en la celdaA1
aparece el textoConcept
, no nos cabe todo ello en una celda de 7 caracteres. - Pulso
<TAB>
y vemos que aparece una etiqueta para la columnaB
. El cursor se sitúa en la celdaB1
. De nuevo, para introducir una cadena pulso la tecla"
y escriboCantidad
, cuando me lo pregunta. - Como también me lo corta, vamos a dimensionar la columna pulsando
w
(width), y cuando pregunta le doy10
de ancho. - Me sitúo de nuevo en la columna
A
y la dimensiono, también conw
a 25. - Al pulsar
<RET>
en cualquiera de las celdas, nos muestra en el minibuffer su contenido y podemos editarlo. - Bajo una línea con
C-n
, o la flecha abajo, y el cursor parece haberse salido de la tabla. PulsoC-o
para insertar otra línea de celdas. El cursos se nos ha situado en la casillaA2
y podemos empezar a meter un concepto, como hemos hecho antes con las dos celdas anteriores. Por ejemplo, Refrescos en el bar. - Pulso
<TAB>
y el cursos se sitúa en la celdaB2
. Ahora voy a introducir un número y la cosa cambia: hay que pulsar=
.
Bien ahora hay que repetir el proceso para crear todas las filas que necesite, hasta crear algo parecido a lo siguiente:
A B Concepto Cantidad Refrescos en el bar 7.25 Comida en restaurante 35.8 Combustible 52.15 ---------- ---------- Total __________
Bien, ya tenemos algunos valores en nuestra tabla: ¿Cómo los sumamos?
Pues metiendo en la celda donde irá el total una expresión elisp que
haga la suma: (+ B1 B2 B3)
. Nos arroja un valor de 95.2
... pero
queremos cambiarle el formato, para que nos lo dé de manera más
legible. Al pulsar M-p
nos dice que el formato de columna es nil
,
así que introducimos "%.2f€"
y el resultado será algo así:
A B Concepto Cantidad Refrescos en el bar 7.25€ Comida en restaurante 35.80€ Combustible 52.15€ ---------- ---------- Total 95.20€
Como se puede apreciar, con M-p
se modifica el formato de toda la
columna, si queremos cambiar sólo algunas de las celdas también lo
podemos hacer pulsando p
en cada una de las que queremos afectar.
Para el cálculo, también hubiéramos podido utilizar un rango de
celdas que sumar. Lo haríamos mediante la fórmula (apply '+
(ses-range B2 B4 !))
. El símbolo !
hace que de la lista de celdas
devueltas por ses-range
, se eliminen las que estén vacías.
En general, para introducir contenidos en las celdas vemos que se pueden utilizar diversos caracteres:
- «0..9»
- Pulsar sobre cualquier número hace que se ponga en modo
ses-read-cell
, utilizando un número. - «-»
- Para introducir un número negativo.
- «.»
- Para introducir una fracción decimal.
- «"»
- Para introducir una cadena.
- «(»
- Para introducir una expresión o fórmula.
<RET>
- Editar el contenido de la celda.
C-c C-c
- Recalcular el contenido de la celda (o el rango marcado).
C-c C-l
- Recalcular la hoja entera.
Otras teclas sirven para redimensionar la hoja:
C-o
- Insertar una fila.
M-o
- Insertar una columna.
C-k
- Eliminar una fila.
M-k
- Eliminar una columna.
<TAB>
- Se mueve a la siguiente columna, si hay una, o añade una columna si está el cursor en la última.
No voy a mostrar muchas más opciones que hay, porque la ayuda está suficientemente clara. Además se pueden utilizar otras muchas teclas y combinaciones de las habituales de Emacs.
También se pueden poner nombres a algunas celdas, para utilizarlos en fórmulas o como enlace para saltar a ellas. O cambiar la línea de cabecera, que normalmente muestra letras como nombres para las columnas.
¿Cómo funciona?
El contenido del fichero cuando lo abrimos con otro editor de texto que no sea Emacs es el siguiente.
Concepto Cantidad Refrescos en el bar 7.25€ Comida en restaurante 35.80€ Combustible 52.15€ ---------- ---------- Total 95.20€ (ses-cell A1 "Concepto" nil nil nil) (ses-cell B1 "Cantidad" nil nil nil) (ses-cell A2 "Refrescos en el bar" nil nil nil) (ses-cell B2 7.25 nil nil (B6)) (ses-cell A3 "Comida en restaurante" nil nil nil) (ses-cell B3 35.8 nil nil (B6)) (ses-cell A4 "Combustible" nil nil nil) (ses-cell B4 52.15 nil nil (B6)) (ses-cell A5 "----------" nil nil nil) (ses-cell B5 "----------" nil nil nil) (ses-cell A6 "Total" nil nil nil) (ses-cell B6 95.19999999999999 (apply (quote +) (ses-range B2 B4 !)) nil nil) (ses-column-widths [25 10]) (ses-column-printers [nil "%.2f€"]) (ses-default-printer "%.7g") (ses-header-row 0) ( ;Global parameters (these are read first) 2 ;SES file-format 6 ;numrows 2 ;numcols )
Como se puede observar, las primeras líneas del fichero se
corresponden a la visualización que tenemos de nuestra hoja y tras una
línea en blanco, otra que contiene ^L
, como marca de separación,
viene una serie de definiciones de celdas. Si tomamos, por ejemplo la
expresión:
(ses-cell B2 7.25 nil nil (B6))
Ahí, se define la celda B2
, con un contenido 7.25
. El siguiente
valor nil
se refiere a la fórmula para calcular el contenido (en
nuestro caso es nil
porque no hay ninguna fórmula). El siguiente
valor nil
se refiere a que esa celda no tiene asignada ninguna
cadena de formato. Lo definimos para la columna entera y por tanto lo
encontramos en la expresión ses-column-printers
más adelante. El
último valor (B6)
es una lista de las celdas que se verían afectadas
por un cambio en el valor de la celda.
Conclusión
El sistema SES
es muy sencillo, como se puede ver. Tiene a su favor
que nos movemos por filas y columnas como lo haríamos en una hoja de
cálculo convencional; que podemos utilizar cualquier expresión válida
de elisp en el contenido de una celda para calcular su contenido, lo
que le da una potencia enorme, a pesar de su sencillez.
Sin embargo, a la hora de presentar contenido integrado dentro de
documentos creo que seguiré utilizando las tablas de org-mode
,
aunque sea más críptico el modo de uso o cómo se establecen las
fórmulas de las celdas a través de comentarios especiales, dan más
flexibilidad a la hora de ajustarlas a un documento, o hacer
gráficos con gnuplot
a partir de las mismas.
Footnotes:
Simple Emacs Spreadshet o «Sencilla Hoja de Cálculo de Emacs».
Comentarios