Archivo por meses: noviembre 2020

Cómo dibujar los ejes coordenados en MATLAB y Octave

Como sabemos, al dibujar gráficos con el comando plot(x,y), la gráfica queda dibujada ajustando los ejes a la ventana, entre los valores máximos y mínimos de los vectores x e y. La gráfica muestra unos ejes graduados en la parte inferior e izquierda de la gráfica, que no tienen por qué estar en las posiciones y=0, x=0. Si añadimos etiquetas a los ejes con los comandos xlabel() e ylabel(), dichas etiquetas aparecerán en los ejes de la gráfica, no en los ejes coordenados X e Y.

Vamos a explicar en este artículo cómo dibujar los ejes coordenados en sus posiciones. Para ello vamos a utilizar como ejemplo el gráfico de la siguiente parábola:

para valores de x en el intervalo [-4, 4]. El gráfico anterior se puede hacer de la siguiente manera:

El eje X es la recta cuya expresión es y=0. El eje Y es la recta x=0. Habrá que dibujar dichas rectas entre los valores mínimo y máximo de la gráfica donde queramos dibujarlos. Podemos hacerlo de la siguiente manera:

Hasta aquí es lo que pediríamos en los exámenes del curso de la escuela de Caminos. Vamos a añadir algunos refinamientos para mejorar los ejes.

En primer lugar, conviene hacer los ejes un poco mayores que los valores máximos. Por ejemplo podemos hacerlos un 15% más grandes:

Aquí, si los valores mínimos fueran positivos, o los valores máximos fueran negativos, habría que actuar de manera diferente.

Además, podemos añadir unos marcadores de flecha, para indicar el sentido de crecimiento de los ejes:

Por último, podríamos añadir unas etiquetas con el nombre de los ejes, y un título al gráfico:

El resultado final sería el siguiente:

(Santiago Higuera. 29 noviembre 2020)

Ficheros: lectura de lineas con datos de distinto tipo

Un problema habitual al leer datos de un fichero de texto es que cada linea de datos contenga datos de distinto tipo: cadenas de caracteres y datos numéricos. La lectura y extracción de dichos datos a variables es un poco más complicada que los casos en los que toda la información es del mismo tipo. Se va a resolver un ejemplo que permita aprender las técnicas que son necesarias en estos casos.

Para la resolución se va a utilizar el fichero datos.txt que, tras una línea de cabecera, contiene en cada línea los datos de incidencia COVID de un municipio de la provincia de Madrid a fecha 24 de noviembre de 2020. El fichero es el siguiente:

El alumno deberá crear este fichero con el editor, copiando los datos que contiene, y grabarlo con el nombre ‘datos.txt’, en el mismo directorio de trabajo donde se va a crear el programa .m de lectura del mismo.

La lectura del fichero debe comenzar con la apertura del mismo en modo lectura, ‘read’. El listado siguiente realiza la apertura del fichero y la comprobación de que el fichero se ha abierto correctamente. Al final del programa se pone la orden fclose(fid), para cerrar el fichero. El alumno deberá copiar estas instrucciones en el editor y guardarlo en el disco, en el mismo directorio en el que ha guardado el fichero ‘datos.txt’. El fichero del programa lo podemos llamar ‘readcovid.m‘, por ejemplo:

Conviene probar esta parte del programa. El programa se ejecuta desde la ventana de comandos, tecleando el nombre del programa ‘readcovid’. Antes de ejecutar el programa haga un ‘clear’, para borrar las variables del espacio de trabajo. Si al ejecutarlo no aparece nada en pantalla, es que ha funcionado bien. En el espacio de trabajo veremos la variable ‘fid’ con el identificador de fichero que le haya sido asignado, y la variable ‘ans’ con el valor cero, correspondiente a la ejecución correcta de la instrucción ‘fclose()’. Si en pantalla se muestra el mensaje ‘Error al abrir fichero’, es que el programa no encuentra el fichero de datos, quizás por poner mal el nombre en la instrucción ‘fopen’, o quizás porque el fichero de datos no está en el mismo directorio que el fichero del programa.

Una vez que se comprueba que funciona correctamente, vamos a proceder a completar las instrucciones de lectura antes de la orden ‘fclose(fid)’. El problema que vamos a resolver es leer los datos del fichero, determinar el municipio con mayor incidencia de COVID, y mostrar en pantalla sus datos: Municipio, Habitantes, Cod e Incidencia.

Vamos a empezar leyendo solo una línea, para entender el funcionamiento. La siguiente versión del programa lee los datos del primer municipio y los guarda en variables.

Lo primero que hace el programa es saltarse la línea de las cabeceras, mediante ‘fgetl()’. A continuación, lee los datos de una línea, de uno en uno, y los guarda en variables. Por último, hace un ‘fgets()’, para completar la lectura de la línea, leyendo el caracter fin de línea. De esta manera, el ‘cabezal de lectura’ quedará posicionado al principio de la siguiente línea de datos, preparado para seguir leyendo. El alumno debe observar que, para leer cada dato, la instrucción ‘fscanf’ utiliza el formato adecuado e indica que solo lee 1 dato. Tras ejecutar el programa y si todo va bien, la ventana del espacio de trabajo deberá mostrar las variables con los valores correctos (conviene hacer un ‘clear’, antes de cada ejecución del programa, para vaciar la memoria y el espacio de trabajo. Si se hace así, el espacio de trabajo mostrará, además de las variables del municipio, la variable ‘ans’ con el valor 0, correspondiente al resultado correcto de la orden ‘fclose’).

Una vez comprobado que podemos leer una línea de manera correcta, podemos proceder a leer todo el fichero, mediante un bucle ‘while’ con la condición ‘~feof(fid)’, o sea, ‘mientras no estemos en el FILE END OF FILE’. Para localizar el municipio con mayor incidencia de COVID en los últimos catorce días, aplicaremos el algoritmo del máximo. Inicializamos a cero unas variables donde guardar los datos máximos: munimax, habmax, codmax y incidmax. Cada vez que encontremos un municipio con incidencia máxima, guardaremos sus datos en las variables. Al final del bucle, tendremos guardados en las variables los datos del municipio con mayor incidencia, y los mostraremos en pantalla:

Al ejecutar el programa, y si todo va bien, deberíamos obtener una salida como la siguiente:

Otra técnica para leer este tipo de ficheros consiste en utilizar la instrucción ‘sscanf()’, que permite decodificar una cadena de texto. La instrucción ‘sscanf (String Scan Formatted) funciona igual que la instrucción ‘fscanf’ (File Scan Formatted), con la salvedad de que ‘sscanf’ lee datos desde una cadena de texto, mientras que ‘fscanf’ lee datos desde un fichero.

La técnica es similar, pero se leen líneas completas del fichero a una cadena de texto con ‘fgetl()’, y luego se decodifica la cadena con ‘sscanf()’. Para explicar el funcionamiento de la instrucción ‘sscanf’, vamos a jugar un poco en la ventana de comandos, antes de hacer el programa que lee el fichero COVID.

Ejecute en la ventana de comandos las siguientes instrucciones:

Creamos primero una cadena de texto en la variable cad, y luego utilizamos la instrucción ‘sscanf’ para extraer el primer valor, como cadena de texto, a la variable ‘muni’. Observese que el primer parámetro que pasamos a la instrucción ‘sscanf’ es la cadena que queremos decodificar, luego el formato de la decodificación y, por último, el número de elementos que queremos extraer con ese formato.

Para extraer el segundo valor de la cadena, hay que saltarse el primer valor y leer el segundo. Esto se consigue poniendo un formato ‘%*s’. El asterisco que ponemos entre el símbolo % y la letra s hace que dicho formato lo lea, pero no lo guarde. El valor que guarda en la variable es el del segundo formato. Seguimos diciendo a ‘sscanf’ que lea un solo valor, el valor que se salta no cuenta:

Para leer el tercer valor, hay que saltarse los dos primeros. Aquí hay que tener cuidado: aunque el segundo valor sea un entero, para saltarlo hay que utilizar ‘%*s’, como si fuera una cadena de texto. Si lo intentáramos saltar con un formato ‘%*d’, el tercer valor no lo leería como cadena, sino como un array de doubles. Por tanto, para saltarse valores, siempre hay que hacerlo con ‘%*s’, como si fueran cadenas, aunque sean números lo que queremos saltar:

La lectura del cuarto dato no presenta mayores dificultades:

Una vez entendido cómo funciona la instrucción ‘sscanf’, reproducimos a continuación el listado del mismo programa que hicimos antes, para extraer los datos del municipio con mayor incidencia:

La salida de este programa debería ser idéntica a la de la otra versión.

Vamos a ver, por último, cómo resolver si no se quieren guardar todos los datos de cada línea, sino solo alguno de ellos, descartando los demás. Por ejemplo, vamos a leer el número de habitantes de cada municipio a un vector, pero descartando todo el resto de información. La técnica consiste en leer en cada línea hasta el dato que buscamos, y descartar el resto de la línea haciendo ‘fgets()’:

La salida de este programa debería ser la siguiente:

Analogamente a lo realizado en el caso resuelto con ‘sscanf’, aquí también podríamos utilizar la técnica de saltarnos datos, con lo que el programa quedaría:

Al ejecutar el programa, el resultado sería idéntico al anterior.

Para este caso de querer leer solo los datos numéricos de una de las columnas del fichero a un vector, podemos combinar la técnica de saltarse datos con la de repetir el formato hasta que se acabe el fichero, y leer el vector con el número de habitantes de los municipios en una única instrucción y sin utilizar bucles:

La salida de resultados sería la misma que en los dos casos anteriores.

Por último, utilizando esta técnica, podríamos leer una matriz que tenga en la primera columna el número de habitantes, y en la segunda columna la incidencia COVID:

Autocompletado de instrucciones de bloque en Octave

Durante la corrección del examen parcial hemos observado que algunos alumnos utilizan claúsulas del tipo endifendfor y similares para cerrar las instrucciones de bloque iffor, etc.

Esta sintaxis, que es totalmente correcta en Octave, no es compatible con MATLAB, donde genera un error de sintaxis.

En este curso tratamos de que todo el código que generamos sea compatible entre MATLAB y Octave y que se pueda utilizar de manera indistinta en uno u otro software. Por ello, no se debe utilizar dicha sintaxis en los programas del curso. Todas las instrucciones de bloque se deben terminar simplemente con la claúsula end (sin apellido).

Algunas versiones de Octave están configuradas de modo que, al teclear un bloque if, un bloque for u otros, autocompleta añadiendo la línea endif o endfor correspondiente.

Este comportamiento se puede modificar en la pantalla de preferencias que se encuentra en el menú ‘Editar->Preferencias’, en la pestaña del ‘Editor’, en la sección correspondiente al ‘Sangrado (Indentation)’. Ahí existe un desplegable que permite seleccionar el tipo de autocompletado que queremos: endif, solo end, o ninguno. La siguiente figura muestra dicha opción.

Configuración de Octave Autocompletado

Os recomendamos que configuréis vuestros programas Octave con la opción ‘solo end’, o ‘ningún autocompletado’, para ahorraros el trabajo de modificar la claúsula del autocompletado en cada instrucción de bloque de vuestros programas.

(Santiago Higuera. 22 noviembre 2020)

Matlab versus Octave

Logos MATLAB Octave

La asignatura ‘Informática’ que se imparte en el primer curso de la Escuela de Ingenieros de Caminos de la Universidad Politécnica de Madrid (UPM), consiste en enseñar a los alumnos a utilizar MATLAB y Octave. En ambos casos, se trata de software matemático orientado al cálculo numérico. También ofrecen un lenguaje de programación, denominado lenguaje m, que permite la realización de programas.

MATLAB es un software privativo de la empresa Mathworks. Es un software caro, cada licencia cuesta unos dos mil euros al año. Octave es la versión de código abierto de MATLAB. Su utilización es libre y gratuita.

En la UPM se dispone de un acuerdo con Mathworks mediante el cual, tanto alumnos como profesores, disponemos de una licencia de MATLAB que podemos utilizar sin coste. Es la vieja técnica de regalar droga en la puerta del colegio para enganchar a los chicos a futuro. Y surte efecto. En la UPM se enseña preferentemente MATLAB frente a Octave.

Siempre que se trata de utilizar versiones de código abierto de algún software comercial, surge la pregunta de cuál es mejor de los dos. En la mayor parte de las ocasiones la pregunta está mal planteada, pues “ser mejor” es un concepto subjetivo, que depende en gran medida de los condicionantes del uso que se vaya a hacer del software.

Si nos fijamos únicamente en la velocidad de operación de los cálculos, MATLAB es más rápido. Lo que sucede es que, en la práctica, dicha velocidad es difícil de apreciar. Desde luego en los programas que hacemos en nuestro curso de informática no se nota en absoluto. Si uno hace el cálculo de la inversa de una matriz de 1000 filas y 1000 columnas, pues sí que se nota la diferencia. Lo que pasa es que no es habitual tener que hacer ese tipo de cálculos.

Pero hay otros aspectos que hay que valorar a la hora de decidir si un software es mejor que otro. Es paradigmático el caso del uso del lenguaje Python, que pese a ser mucho más lento que alternativas como el C u otras, no deja por ello de ser la principal opción a la hora de desarrollar aplicaciones de inteligencia artificial y muchos otros cálculos científicos. La existencia de librerías de funciones, la facilidad de uso, la facilidad programación y otros aspectos son fundamentales a la hora de decidirse por un lenguaje de programación concreto para su uso en determinado campo del conocimiento.

Pasa lo mismo con la comparación entre MATLAB y Octave. Octave, por ejemplo, es muy sencillo de utilizar desde otros lenguajes. Esto permite programar en cualquier lenguaje y utilizar por debajo Octave para la realización de los cálculos matemáticos complejos. Esta característica, por sí sola, puede ser clave a la hora de decidirse por su utilización. Creo que es uno de los motivos por los que Octave es la solución de cálculo numérico preferida en el CERN, seguramente el laboratorio de física de partículas más avanzado del mundo [1].

El funcionamiento de MATLAB y Octave es casi idéntico. Hay pocas diferencias y, la mayoría, ni siquiera es uno consciente de ellas en el funcionamiento normal. Siempre recomiendo a mis alumnos que, puesto que disponemos de licencia de uso de MATLAB, aprendan a utilizar los dos, que se instalen los dos programas en sus computadoras. En las clases yo utilizo preferentemente Octave, aunque siempre hago indicaciones de cómo resolver cuestiones concretas en MATLAB, que suelen estar relacionadas con la localización de opciones en el interfaz gráfico.

Hay otros aspectos más objetivos que me hacen pensar que Octave es una opción mejor que MATLAB para su utilización en el ámbito científico. Me llevan los demonios cada vez que leo un paper científico aceptado que utiliza MATLAB para resolver cálculos complejos. En mi opinión, esto no debería estar admitido en el ámbito científico. Cualquier experimento científico tiene que permitir que otros científicos puedan repetir el experimento de manera independiente. Pero, ¿cómo puede uno repetir un experimento que se resuelve mediante un algoritmo que no es de código abierto y que realiza los cálculos con una caja negra que es imposible de repasar? ¿Cómo se han resuelto las condiciones de borde? ¿Qué tratamiento da el algoritmo a determinados valores? De hecho, se han producido a veces errores importantes en diferentes campos científicos motivados por bugs en los algoritmos de software de código cerrado que no se habían detectado. Un ejemplo dramático se dio hace unos años en relación con el software que gestiona los scanner cerebrales [2]. Seguramente esta es otra de las razones por las que el CERN utiliza Octave: cualquier algoritmo se puede repasar y analizar, para detectar posibles errores, lo que no es posible hacer con MATLAB.

Y entonces, si esto es así, ¿por qué se permite la publicación de artículos científicos que basan sus cálculos en algoritmos de código cerrado de MATLAB? Pues para mí es inexplicable. La ignorancia y el dinero están detrás, no me cabe duda.

Hay un aspecto que suele condicionar la utilización de software privativo por parte de algunos usuarios. Se trata del interfaz gráfico. Los programas “caros” suelen tener interfaces gráficos más vistosos. El software libre lo desarrolla una comunidad de desarrolladores que actúa, en su mayor parte, de forma artesanal y en muchos casos de manera altruista. En ese sentido, no se suele dedicar mucho esfuerzo a la vistosidad o al marketing.

La versión actual de MATLAB utiliza un interfaz gráfico basado en la barra de herramientas que impuso hace unos años Microsoft en Windows, en su popular suite Office. Se basa en una barra de herramientas con botones grandes que permiten que cada opción lleve asociada una imagen coloreada. Hay botones que son eso, un botón. Otros son desplegables que abren a su vez otras opciones. También hay unas pestañas que permiten seleccionar diferentes barras de herramientas. Empresas como Microsoft o Apple nos tratan de imponer desde hace años la sustitución de las palabras por las imágenes, en las formas de navegar a través de las opciones que ofrecen los programas. Personalmente no me gusta esa forma de interpretar la navegación por un mapa de opciones. Me sitúo mejor navegando al viejo estilo Menú->Submenú, que me proporciona una estructura de árbol en la cuál mi cerebro se posiciona con más facilidad. En las barras de herramientas se pierde esa organización de la información en forma de árbol.

Además, los botones me suelen obligar a utilizar más el ratón y menos el teclado. Normalmente tengo que sobrevolar el botón con el cursor del ratón para que aparezca el tip de texto e interpretar adecuadamente la opción que busco, lo que me parece una pérdida de tiempo. Estoy acostumbrado a utilizar el teclado. Los menús son fáciles de acceder mediante combinaciones de teclas. Cada vez que tengo que soltar el teclado y agarrar el ratón, me parece que pierdo el tiempo.

Por ello, y aunque comprendo que a algunos les parezca mejor el interfaz gráfico de MATLAB, a mí personalmente me gusta menos que el de Octave.

Hay una razón de tipo social, que supongo que también es opinable. Imponer a nuestros futuros científicos e ingenieros la utilización de un software “caro”, cuando existen alternativas libres perfectamente equiparables, me parece ineficiente. La utilización de soluciones libres y de código abierto, permite que el dinero, en vez de utilizarse en pagar licencias a multinacionales, se utilice en otras cosas, por ejemplo, en pagar a desarrolladores, científicos e ingenieros locales.

En mi uso particular, siempre uso Octave. A mí me gusta más. No tengo ninguna duda de que es un software mucho mejor, en el contexto de utilización que yo hago. Y por ello, mientras siga siendo posible, seguiré utilizando en mis clases de manera preferente Octave frente a MATLAB, y seguiré recomendando a mis alumnos que aprendan a utilizar los dos programas.

[1] https://information-technology.web.cern.ch/services/software/octave

[2] https://elpais.com/elpais/2016/07/26/ciencia/1469532340_615895.html