Notxor tiene un blog

Defenestrando la vida


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 SES1 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:

  1. Crear ─o visitar─ mediante C-x C-f un archivo que se va a llamar gastos.ses: hay que observar que la extensión .ses es importante para que Emacs entre en modo SES. Al hacerlo me encuentro un buffer casi vacío con una etiqueta A y una zona subrayada, con el cursor allí situado... nuestra hoja sólo tiene, de momento, una celda: la A1. Si observamos la línea de estado, nos mostrará en qué celda está situado el cursor... ¡seguimos!
  2. Pulso ", las comillas dobles, y me pregunta por una cadena de texto. Escribo Concepto y de nuevo <RET>. Ahora en la celda A1 aparece el texto Concept, no nos cabe todo ello en una celda de 7 caracteres.
  3. Pulso <TAB> y vemos que aparece una etiqueta para la columna B. El cursor se sitúa en la celda B1. De nuevo, para introducir una cadena pulso la tecla " y escribo Cantidad, cuando me lo pregunta.
  4. Como también me lo corta, vamos a dimensionar la columna pulsando w (width), y cuando pregunta le doy 10 de ancho.
  5. Me sitúo de nuevo en la columna A y la dimensiono, también con w a 25.
  6. Al pulsar <RET> en cualquiera de las celdas, nos muestra en el minibuffer su contenido y podemos editarlo.
  7. Bajo una línea con C-n, o la flecha abajo, y el cursor parece haberse salido de la tabla. Pulso C-o para insertar otra línea de celdas. El cursos se nos ha situado en la casilla A2 y podemos empezar a meter un concepto, como hemos hecho antes con las dos celdas anteriores. Por ejemplo, Refrescos en el bar.
  8. Pulso <TAB> y el cursos se sitúa en la celda B2. 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.

Nota al pie de página:

1

Simple Emacs Spreadshet o «Sencilla Hoja de Cálculo de Emacs».


Comentarios

Debido a algunos ataques mailintencionados a través de la herramienta de comentarios, he decidido no proporcionar dicha opción en el Blog. Si alguien quiere comentar algo, me puede encontrar en Mastodon y en Diaspora con el nick de Notxor.

También se ha abierto un grupo en Telegram, para usuarios de esa red.

Disculpen las molestias.