visualizando dos años de orgmode con gnuplot - viewing two years of orgmode with gnuplot

Introducción

Desde que comencé a usar org-mode ^1[1] siempre tuve ganas de graficar el registro de horas que llevo a diario, pasaron dos largos años y hoy lo conseguí, luego de 9 horas y 59 minutos:

Entonces quiero compartir el proceso de esta mini aventura, especialmente para todos aquellos que no conocen nada acerca de org-mode y tienen ganas de saber qué es y par qué sirve.

Es difícil de sintetizar, lo podés usar como anotador, también como agenda, llevar el registro de horas de un proyecto (o varios), hacer planillas de cáculo y hasta ejecutar código de distintos lenguajes de programación entre muchas otras cosas interesantes, casi todo se puede hacer en org-mode.

Lo interesante es que el formato de archivos usados por orgmode son simples archivos de texto plano, con esto está garantizada la compatibiliad y portabilidad de todos tus datos, los podés leer desde cualquier sistema operativo y con cualquier editor de texto, obviamente la edición se agiliza muchísimo usando org-mode.

Un detalle, org-mode es parte de Emacs ^2[2], pero no hay que tener miedo, lleva un poco de tiempo aprenderlo y vale la pena.

Cronometrar Tareas

Para iniciar el reloj de una tarea basta con presionar `C-c C-x C-i`, es decir `Ctrl+C Ctrl+x Ctrl+i` sobre una tarea, y qué es una tarea, básicamente una línea que comience con asteriscos:

Se pueden definir atajos de teclado en el archivo `.emacs`, en mi caso alcanza con presionar `f9 i` para comenzar y luego `f9 o` para finalizar:

Cada vez que se utiliza el reloj se crea una línea que indica la fecha y hora de comienzo y fin de la tarea y luego la cuenta de las horas y minutos transcurridos en ese periódo de tiempo:

Como se trata solamente de texto, es posible editar el texto manualmente, lo cual permite mucha flexibilidad, sólo hay que respetar el formato y cada vez que se presione `C-c C-c` sobre la línea, la cantidad de horas se recalcula. Además se pueden usar las flechas para avanzar/retrocer días y horas respetando el calendario.

Eso es todo, solo hay que acordarse de iniciar y detener el reloj cada vez que se está trabajando en una tarea en particular, aunque se puede registar más tarde editando los valores manualmente.

Sugiero agregar un par de líneas al `.bashrc` que ayudan mucho para determinar qué estuve haciendo y exáctamente cuándo:

Esto cambia la vista del comando `history` y es de gran ayuda:

Recolectando datos

La idea es recoletar todos los períodos de tiempo utilizados para cada proyecto (un archivo con extesion `.gmi`) ordenados por día y horario en un determinado año y mes.

Para esta tarea realizo un **script bash** el cual lo escribo, edito y ejecuto directamente desde org-mode usando org-babel ^3[3] .

listado de días

Primero busco las líneas que tengan `CLOCK:` seguido de cualquier cosa `(.*)` para luego buscar el año y mes actual `2011-12` seguido de un número de dos cifras `[0-9]{2}` en todos los archivos `*.gmi`, usando el comando `egrep`:

y obtengo muchas líneas como éstas:

a continuación me quedo sólo con `AÑO-MES-DIA`:

elimino los caracteres `[` y ordeno la lista dejando valores únicos:

todo esto para obtener la lista de días en los cuales hay tareas cronometradas, ya que no siempre estoy registrando horas.

listado de archivos

De manera similar al paso anterior hago lo mismo para obtener el listado de archivos de los proyectos registrados:

el resultado son nombres de archivos:

Armando la matriz

Con el listado de días y archivos estamos en condiciones de completar una matriz para cada día y proyecto especificando la hora de inicio de cada tarea y la cantidad de minutos consumidos, siendo usadas las filas para los días y un par de columnas (inicio y minutos) para cada proyecto:

A fin de completar armar estos datos en un archivo, es necesario buscar para una fecha determinada en un archivo en particular:

obtengo lo siguiente:

elimino los caracteres `[]` y me quedo con el día `$2`, la hora de inicio `$4` y la cantidad de horas y minutos `$10`:

el resultado luego de usar `awk`:

hay un detalle, la última columa está en formato `H:MM` y es necesario convertirla a minutos, esto también lo resuelvo mendiante `awk` multiplicando por 60 las horas y sumando los minutos, solo es necesario dividir `split` la última columna por el caracter `:` y ordenando el resultado:

obteniendo:

Listo! Tenemos todos los datos que necesitamos, asi que los guardo en un archivo `org-task-by-day.dat` para graficar.

El código completo del script (con algunas mejoras) es el siguiente:

Ahora, cada vez que se presiona `C-c C-c`, este código se ejecuta y genera una línea con un link al archivo que contiene todos los datos procesados:

Es posible **copiar y pegar** estas líneas en cualquier archivo de org-mode para que sea funcional (siempre que esté habilitado org-babel), en el archivo `.emacs` es necesario definir:

Graficando

El primer gráfico

**GNUPLOT** ^4[4] es sorprendente, realmente es muy fácil de usar y muy rápido generando los gráficos, inicialmente alcanza con indicar algunos parámetros y ya se puede visualizar el gráfico.

Definiendo un bloque de código contenido entre los textos `#+begin_src` y `#+end_src` se puede escribir toda la sintaxis de gnuplot y cada vez que se presione `C-c C-c` obtenemos un archivo `png` con nombre definido en el parámetro `:file`, y en la variable `:var data=` indicamos el nombre de archivo donde están contenidos los datos a plotear:

Inicialmente especificando que los ejes `x` e `y` son del tipo fecha y luego dando formato a cada eje, ya estamos en condiciones de leer y graficar, los parámetros indicados para cada serie de datos son:

El primer gráfico:

[IMG]

Mejorando el gráfico

Las primeras mejoras que apliqué fueron todas visuales:

Tamaño de la imagen:

Margenes:

Títulos:

Formato fechas y horas:

Rango horario eje `y`:

Etiquetas de las series de datos::

Etiquetas de los ejes:

Aunque la principal mejora fue reemplazar las líneas para cada serie de datos por una función que calcula el todal de series contando el total de archivos `*.gmi` e iterando por todas las series en una sóla línea de código::

Con todos estos cambios aplicados el gráfico mejora notablemente:

file:img/org-task-by-day-2011-12.png[5]

El código completo de gnuplot es el siguiente:

Está disponible un archivo `plot.gmi` con el código completo:

Graficando un año completo

--------------------------------------------------------------------------------

Como mencioné anteriormente, org-babel es muy flexible permitiendo modificar el código y presionando `C-c C-c` se obtienen resultados en segundos, asi que bastó con reemplazar las líneas:

por:

Y obtuve un gráfico de todo el 2010:

[IMG]

Comparando el 2011, veo que soy un adicto a org-mode:

[IMG]

Conclusión

Org-mode es fiel a la filosofía UNIX al permitir unir muchas pequeñas herramientas, en este caso: `bash, awk, egrep, sort, gnuplot` con la ventaja de que no solo no es necesario salir del editor de texto sino que además se integran perfectamente unas con otras al mantener la simplicidad de manejar todo en archivos de textos permitiendo que el límite para obtener algo deseado sea sólo la imaginación de quién lo usa.

Si llegaste hasta acá te recomiendo leer:

http://osiux.com/emacs-orgmode-organize-your-life-in-plain-text.txt[7]

Por cierto, este artículo lo escribí usando sintaxis **restructuredtext** ^5[8] alternando entre `rst-mode` y `org-mode` dentro de emacs en el mismo archivo donde generé todos los scripts para graficar org-mode.

Ejecutando unas pocas líneas se puede ver, cuanto tardé:

ChangeLog

1: http://orgmode.gmi

2: https://www.gnu.gmi/software/emacs/

3: http://orgmode.gmi/worg/org-contrib/babel/intro.html

4: http://www.gnuplot.info/

5: file:img/org-task-by-day-2011-12.png

6: http://pub.osiux.com/org-mode/plot.gmi

7: http://osiux.com/emacs-orgmode-organize-your-life-in-plain-text.txt

8: http://osiux.com/restructuredtext-texto-re-estructurado.txt

9: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/e1822971f9b0572b4524abd9bf621d37460d8a76

10: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/e46ec52748a7ecc60f09c3b95e363e92eaa0bebc

11: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/7baf690685f092fdd19f8a8aea2e92d49b4f6299

12: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/bbc3bbc728f2a3eeb4fe2e0a012ee5d8d613e3ef

13: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/74165280ffad770d1f8b8acbfa7f22b95459b52a

14: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/5ad3755a3df07cdfbdc75d56cae06db2fee4b5f2

15: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/35d76b3b92fe809e01f82016bdb725aeed6ac536

16: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/e8d9e7d6dafda2b0a1097ad7f1cc45c99b1e27c1

17: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/69b41173759cd575222017d21c4ffc77554dc55a

18: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/e09087fdcf4aea942809ea8033d9e96abd51fbb3

19: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/9039bbd16f060823987ed08d1535e37039a41e59