Clase 9: Visualización

Para graficar datos y funciones vamos a usar la biblioteca Matplotlib. Vamos a empezar discutiendo algunas de las características más generales del trabajo con esta biblioteca y mostrar algún ejemplo relativamente sencillo. Matplotlib está dividido en tres partes o capas conceptualmente bien delimitadas:

  • Una parte es la que hace el trabajo más básico creando y administrando cada objeto que forma parte del gráfico (líneas, texto, figuras, etc) así como sus relaciones,

  • Una segunda parte que permite un uso simple de las funciones anteriores: una interfaz con el usuario. Un ejemplo es el submódulo pyplot.

  • Una tercera componente que se encarga de presentar la figura en el formato adecuado. Esto es lo que se llama el Backend y se encarga de mostrar la figura en los distintos sistemas de ventanas, o en formatos de archivos correspondientes. Algunos ejemplos de backend son: PS (copias PostScript®), SVG (Scalable Vector Graphics), Agg (salida PNG de muy buena calidad), Cairo (png, pdf, ps, svg), GTK (interactivo, permite integrar matplotlib con aplicaciones Gtk+, que usa GNOME), PDF, WxWidgets (interactivo), Qt (interactivo).

Nosotros vamos a concentrarnos principalmente en aprender a utilizar pyplot

Interactividad

Trabajo con ventanas emergentes

Podemos trabajar en forma interactiva con gráficos desde una terminal de Ipython

import matplotlib.pyplot as plt # o equivalentemente:
# from matplotlib import pyplot as plt
plt.plot([0,1,4,9,16,25])

El comando (la función) plot() crea el gráfico pero no lo muestra. Lo hacemos explícitamente con el comando show()

plt.show()

Vemos que es muy simple graficar datos.

Algunas cosas a notar:

  1. Se abre una ventana

  2. Se bloquea la terminal (no podemos dar nuevos comandos)

  3. Si pasamos el mouse sobre el gráfico nos muestra las coordenadas.

  4. Además del gráfico hay una barra de herramientas: .. image:: figuras/matplotlib_toolbar.png

De derecha

a izquierda tenemos:

  • Grabar: Este botón abre una ventana para guardar el gráfico en alguno de los formatos disponibles.

  • Configuración de subplots: Permite modificar el tamaño y posición de cada gráfico en la ventana.

  • Agrandar (zoom) a rectángulo:

    • Si elegimos una región mientras apretamos el botón izquierdo, esta será la nueva región visible ocupando toda la ventana.

    • Si elegimos una región mientras apretamos el botón derecho, pone toda la vista actual en esta región.

  • Desplazar y agrandar (Pan and zoom): Este botón cumple dos funciones diferentes:

    • Con el botón izquierdo desplaza la vista.

    • Con el botón derecho la vista se agrandará achicará en los ejes horizontal y vertical en una cantidad proporcional al movimiento.

    Si se oprime las teclas x o y las dos funciones quedan restringidas al eje correspondiente.

  • Home, Back, Forward son botones que nos llevan a la vista original, una vista hacia atrás o hacia adelante respectivamente

Si ocurre, como en este caso, que proveemos sólo una lista de datos, la función plot() la interpreta como los valores correspondientes al eje vertical (eje y), y toma el índice del dato para la variable independiente (eje x). Si queremos dar valores explícitamente para el eje x debemos pasarlos como primer argumento.

plt.plot([0,1,2,3,4,5],[0,1,4,9,16,25])
plt.show()

Como vemos, para que muestre la ventana debemos hacer un llamado explícito a la función show(). Esto es así porque muchas veces queremos realizar más de una operación sobre un gráfico antes de mostrarlo. Sin embargo, hay varias alternativas respecto a la interactividad de matplotlib (e ipython) que permiten adecuarla a nuestro flujo de trabajo. La manera más común en una terminal es utilizando las función ion() (interactive on) para hacerlo interactivo y la función ioff() para no interactivo.

plt.ion()           # Prendemos el modo interactivo
plt.plot([0,1,2,3,4,5],[0,1,4,9,16,25])

En el modo interactivo no sólo plot() tiene implícito el comando show() sino que podemos seguir ingresando comandos con el gráfico abierto.

Trabajo sobre notebooks

Para trabajar en ipython notebooks suele ser conveniente realizar los gráficos dentro de la misma página donde realizamos los cálculos

import matplotlib.pyplot as plt
plt.plot([1,2,3,4,5,6],[0,1,4,9,16,25])
[<matplotlib.lines.Line2D at 0x7f87f0b61cd0>]
_images/09_1_intro_visualizacion_10_1.png

En la práctica vamos a usar siempre Matplotlib junto con Numpy.

import numpy as np
import matplotlib.pyplot as plt

Gráficos simples

El paquete Matplotlib permite visualizar datos guardados en un archivo con unas pocas líneas

fdatos = '../data/ej_oscil_aten_err.dat'
x, y, yexp = np.loadtxt(fdatos, unpack=True)
plt.plot(x, y)
[<matplotlib.lines.Line2D at 0x7f87f0bf8ed0>]
_images/09_1_intro_visualizacion_16_1.png

Como vemos, es la curva que graficamos la clase anterior.

Si miramos el archivo vamos a ver que tiene una columna más que corresponde a los valores medidos. En consecuencia le asignamos esta tercera columna a una variable adicional yexp al leerlo.

# Graficamos las segunda y tercera columnas como función de la primera
plt.plot(x,yexp, x,y)
[<matplotlib.lines.Line2D at 0x7f87f0939190>,
 <matplotlib.lines.Line2D at 0x7f87f09394d0>]
_images/09_1_intro_visualizacion_18_1.png

Formato de las curvas

En los gráficos anteriores usamos la función plot() en sus formas más simples.

plot(y)
plot(x,y)
plot(x1,y1, x2, y2)

dando a la función plot() la información mínima necesaria para graficar los datos. Usualmente queremos poder elegir cómo vamos a graficar nuestros datos.

Líneas, símbolos y colores

La forma más simple de elegir el modo de graficación de la curva es a través de un tercer argumento. Este argumento, que aparece inmediatamente después de los datos (x e y), permite controlar el tipo de línea o símbolo utilizado en la graficación. En el caso de la línea sólida se puede especificar con un guión (‘-’) o simplemente no poner nada, ya que línea sólida es el símbolo por defecto. Las dos especificaciones anteriores son equivalentes. También se puede elegir el color, o el símbolo a utilizar con este argumento:

plot(x,y,'g-')
plot(x,y,'ro')
plot(x,y,'r-o')
_images/simple_linea_simb.png

Para obtener círculos usamos una especificación que corresponde a ‘o’. Además podemos poner en este argumento el color. En este caso elegimos graficar en color “rojo (r), con una línea (-) + círculos (o)”.

Con esta idea modificamos el gráfico anterior

plt.plot(x,y,'-', x,yexp, 'ro')
[<matplotlib.lines.Line2D at 0x7f87f096fb90>,
 <matplotlib.lines.Line2D at 0x7f87f09ab110>]
_images/09_1_intro_visualizacion_21_1.png

Para graficar más de una curva, en este formato simple, podemos ponerlo todo en la misma función plot() en la forma plot(x1, y1, [formato], x2, y2, [formato2]) pero muchas veces es más legible separar los llamados a la función, una para cada curva.

plt.plot(x,y, '-')
plt.plot(x,yexp, 'or')
[<matplotlib.lines.Line2D at 0x7f87f0803150>]
_images/09_1_intro_visualizacion_23_1.png

Al separar los llamados a la función plot() obtenemos un código más claro, principalmente cuando agregamos opciones de formato.

Los siguientes caracteres pueden utilizarse para controlar el símbolo de graficación:

Símbolo

Descripción

‘-’

solid line style

‘–’

dashed line style

‘-.’

dash-dot line style

‘:’

dotted line style

‘.’

point marker

‘,’

pixel marker

‘o’

circle marker

‘v’

triangle down marker

‘^’

triangle up marker

‘<’

triangle left marker

‘>’

triangle right marker

‘1’

tri down marker

‘2’

tri up marker

‘3’

tri left marker

‘4’

tri right marker

‘s’

square marker

‘p’

pentagon marker

‘*’

star marker

‘h’

hexagon1 marker

‘H’

hexagon2 marker

‘+’

plus marker

‘x’

x marker

‘D’

diamond marker

‘d’

thin diamond marker

‘|’

vline marker

‘_’

hline marker

Los colores también pueden elegirse usando los siguientes caracteres:

Letra

Color

‘b’

blue

‘g’

green

‘r’

red

‘c’

cyan

‘m’

magenta

‘y’

yellow

‘k’

black

‘w’

white

Por ejemplo, utilizando:

plt.plot(x, y1, 'gs', x, y2, '-k^', x, y3, '--r' )

obtenemos: .. image:: figuras/simple_varios.png

La función plot() acepta un número variable de argumentos. Veamos lo que dice la documentación

Signature: plt.plot(*args, **kwargs)
Docstring:
Plot y versus x as lines and/or markers.

Call signatures::

    plot([x], y, [fmt], data=None, **kwargs)
    plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)

En particular, podemos usar los argumentos keywords (pares nombre-valor) para cambiar el modo en que se grafican los datos. Algunos de los más comunes son:

Argumento

Valor

linestyle

{‘-’, ‘–’, ‘-.’, ‘:’, ’’, …}

linewidth

número real

color

un color

marker

{‘o’, ‘s’, ‘d’, ….}

markersize

número real

markeredgecolor

color

markerfacecolor

color

markevery

número entero

plt.plot(x,y,linewidth=1)
plt.plot(x,yexp, 'o', color='red', markersize=2)
[<matplotlib.lines.Line2D at 0x7f87f087c250>]
_images/09_1_intro_visualizacion_27_1.png
plt.plot(x,y,linewidth=5)
plt.plot(x,yexp, 'o', color='green', markersize=8)
[<matplotlib.lines.Line2D at 0x7f87f08ad850>]
_images/09_1_intro_visualizacion_28_1.png
plt.plot(x,y,linewidth=5, linestyle='dashed')
plt.plot(x,yexp, 'o', color='red', markersize=8, markeredgecolor='black',markevery=6)
[<matplotlib.lines.Line2D at 0x7f87f076c250>]
_images/09_1_intro_visualizacion_29_1.png

Nombres de ejes y leyendas

Vamos ahora a agregar nombres a los ejes y a las curvas.

Para agregar nombres a las curvas, tenemos que agregar un label, en este caso en el mismo comando plot(), y luego mostrarlo con `legend()

plt.plot(x,y, '-b', label="teoría")
plt.plot(x,yexp, 'or', label="medición")
#plt.legend()
plt.legend(loc="lower right", title="Mis datos")
<matplotlib.legend.Legend at 0x7f87f08712d0>
_images/09_1_intro_visualizacion_31_1.png

Para agregar nombres a los ejes usamos xlabel y ylabel:

plt.plot(x,yexp, 'or', label="medición")
plt.plot(x,y, '-b', label="teoría")
plt.legend(loc="lower right", title="Mis datos")
plt.xlabel('Tiempo (micro-segundos)')
plt.ylabel("Voltaje (mV)");
_images/09_1_intro_visualizacion_33_0.png

Los títulos a la figura se pueden agregar con title

plt.plot(x,y, '-b', label="teoría")
plt.plot(x,yexp, 'or', label="medición")
plt.legend(loc="lower right", title="Mis datos")
plt.xlabel('Tiempo (micro-segundos)')
plt.ylabel("Voltaje (mV)")
plt.title("Medición de ayer")
plt.axvline(x=1, color='gray')
plt.axhline(color='gray')
<matplotlib.lines.Line2D at 0x7f87f051d690>
_images/09_1_intro_visualizacion_35_1.png

Acá además agregamos una línea vertical y una horizontal.


Ejercicios 09 (a)

  1. Realizar un programa para visualizar la función

    \[f(x,n,w) = x^n |\sin(w x)|\]

    El programa debe realizar el gráfico para \(w=10\), con cuatro curvas para \(n=1,2,3,4\), similar al que se muestra en la siguiente figura

    _images/ejerc_vis_f1.png

Escalas y límites de graficación (vista)

Para cambiar los límites de graficación se puede usar las funciones xlim para el eje horizontal y ylim para el vertical

plt.plot(x,y, '-b', label="teoría")
plt.plot(x,yexp, 'or', label="medición")
plt.legend(loc="lower right", title="Mis datos")
plt.xlabel('Tiempo (micro-segundos)')
plt.ylabel("Voltaje (mV)")
plt.title("Medición de ayer")
plt.axvline(x=1, color='gray')
plt.axhline(color='gray')
plt.xlim((0,2.5))
plt.ylim((-0.4, 0.32))
(-0.4, 0.32)
_images/09_1_intro_visualizacion_39_1.png

Para pasar a escala logarítmica usamos xscale o yscale

plt.plot(x,y, '-b', label="teoría")
plt.plot(x,yexp, 'or', label="medición")
plt.legend(loc="best", title="Mis datos")
plt.xlabel('Tiempo (micro-segundos)')
plt.ylabel("Voltaje (mV)")
plt.title("Medición de ayer")
plt.axvline(x=1, color='gray')
plt.axhline(color='gray')
plt.xlim((1.e-1,3))
plt.xscale('log')
plt.ylim((-0.4, 0.32))
(-0.4, 0.32)
_images/09_1_intro_visualizacion_41_1.png
plt.plot(x,1+y, '-b', label="teoría")
plt.plot(x,1+yexp, 'or', label="medición")
plt.legend(loc="best", title="Mis datos")
plt.xlabel('Tiempo (micro-segundos)')
plt.ylabel("Voltaje (mV)")
plt.title("Medición de ayer")
plt.axvline(x=1, color='gray')
plt.axhline(color='gray')
plt.xlim((1.e-1,3))
plt.xscale('log')
plt.yscale('log')
plt.ylim((0.6, 1.4))
(0.6, 1.4)
_images/09_1_intro_visualizacion_42_1.png

Exportar las figuras

Para guardar las figuras en alguno de los formatos disponibles utilizamos la función savefig().

foname = 'ej_plot_osc'
plt.plot(x,y, '-b', label=r"$\frac{\sin(x^2)}{[2 + \cos (x)]^2}$")
plt.plot(x,yexp, 'or', label="$\mathrm{Medición}$")
plt.legend(loc="best", title="Mis datos", fontsize='x-large')
plt.xlabel(r'Tiempo ($\mu$-segundos)', fontsize='x-large')
plt.ylabel("Voltaje (mV)", fontsize='x-large')
plt.title("Medición de ayer")
plt.axvline(x=1, color='gray')
plt.axhline(color='gray')
plt.xlim((0,3))
plt.ylim((-0.4, 0.32))
plt.grid()
#plt.grid(color='green', linestyle='dashed', linewidth=1)
plt.savefig(f'{foname}.png')
plt.savefig(f'{foname}.pdf')
_images/09_1_intro_visualizacion_44_0.png
%pwd
'/home/fiol/Clases/IntPython/clases-python/clases'
help(plt.grid)
Help on function grid in module matplotlib.pyplot:

grid(visible=None, which='major', axis='both', **kwargs)
    Configure the grid lines.

    Parameters
    ----------
    visible : bool or None, optional
        Whether to show the grid lines.  If any kwargs are supplied, it
        is assumed you want the grid on and visible will be set to True.

        If visible is None and there are no kwargs, this toggles the
        visibility of the lines.

    which : {'major', 'minor', 'both'}, optional
        The grid lines to apply the changes on.

    axis : {'both', 'x', 'y'}, optional
        The axis to apply the changes on.

    **kwargs : ~matplotlib.lines.Line2D properties
        Define the line properties of the grid, e.g.::

            grid(color='r', linestyle='-', linewidth=2)

        Valid keyword arguments are:

        Properties:
        agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image
        alpha: scalar or None
        animated: bool
        antialiased or aa: bool
        clip_box: .Bbox
        clip_on: bool
        clip_path: Patch or (Path, Transform) or None
        color or c: color
        dash_capstyle: .CapStyle or {'butt', 'projecting', 'round'}
        dash_joinstyle: .JoinStyle or {'miter', 'round', 'bevel'}
        dashes: sequence of floats (on/off ink in points) or (None, None)
        data: (2, N) array or two 1D arrays
        drawstyle or ds: {'default', 'steps', 'steps-pre', 'steps-mid', 'steps-post'}, default: 'default'
        figure: .Figure
        fillstyle: {'full', 'left', 'right', 'bottom', 'top', 'none'}
        gapcolor: color or None
        gid: str
        in_layout: bool
        label: object
        linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
        linewidth or lw: float
        marker: marker style string, ~.path.Path or ~.markers.MarkerStyle
        markeredgecolor or mec: color
        markeredgewidth or mew: float
        markerfacecolor or mfc: color
        markerfacecoloralt or mfcalt: color
        markersize or ms: float
        markevery: None or int or (int, int) or slice or list[int] or float or (float, float) or list[bool]
        mouseover: bool
        path_effects: .AbstractPathEffect
        picker: float or callable[[Artist, Event], tuple[bool, dict]]
        pickradius: unknown
        rasterized: bool
        sketch_params: (scale: float, length: float, randomness: float)
        snap: bool or None
        solid_capstyle: .CapStyle or {'butt', 'projecting', 'round'}
        solid_joinstyle: .JoinStyle or {'miter', 'round', 'bevel'}
        transform: unknown
        url: str
        visible: bool
        xdata: 1D array
        ydata: 1D array
        zorder: float

    Notes
    -----
    The axis is drawn as a unit, so the effective zorder for drawing the
    grid is determined by the zorder of each axis, not by the zorder of the
    .Line2D objects comprising the grid.  Therefore, to set grid zorder,
    use .set_axisbelow or, for more control, call the
    ~.Artist.set_zorder method of each axis.

Acá también hemos utilizado formato tipo LaTeX para parte del texto. Si utilizamos una expresión encerrada entre los símbolos $, matplotlib interpreta que está escrito en (un subconjunto) de LaTeX.

Matplotlib tiene un procesador de símbolos interno para mostrar la notación en LaTeX que reconoce los elementos más comunes, o puede elegirse utilizar un procesador LaTeX externo.

Dos gráficos en la misma figura

Hay varias funciones que permiten poner más de un gráfico en la misma figura. Veamos un ejemplo utilizando la función subplots()

# %load scripts/ejemplo_08_5.py
#! /usr/bin/ipython3

""" Script realizado durante la clase 9. Dos figuras """
from pathlib import Path

import numpy as np
import matplotlib.pyplot as plt
plt.ion()

fname = 'ej_oscil_aten_err'
# Levantamos los datos
pardir = Path("..")
datfile = pardir / f'data/{fname}.dat'

x1, y1, y2 = np.loadtxt(datfile, unpack=True)
# Vamos a graficar sólo algunos valores (uno de cada 5)
x = x1[3:-10:5]
y = y1[3:-10:5]
yexp = y2[3:-10:5]

# Ejemplo de barras de error que dependen del eje x
error = 0.05 + 0.3 * np.abs(y)

fig, (ax0, ax1) = plt.subplots(num='subplots', nrows=2, sharex=True)
ax0.errorbar(x, yexp, yerr=error, fmt='-o')
ax1.plot(x, 2 * (yexp - y) / (yexp + y), 'or', markersize=8)


# Límites de graficación y títulos
ax0.set_title('Datos con error variable')
ax1.set_title('Error relativo')
ax0.set_ylabel('Voltaje (mV)', fontsize='x-large')
ax1.set_xlabel(r'Tiempo ($\mu$-seg)', fontsize='x-large')
ax1.set_ylabel('Error relativo', fontsize='x-large')
ax1.set_xlim((0, 3))

# Guardamos el resultado
plt.savefig(f'{fname}.png', dpi=150)
_images/09_1_intro_visualizacion_49_0.png
# %load scripts/ejemplo_08_5.py
#! /usr/bin/ipython3

""" Script realizado durante la clase 9. Dos figuras """
from pathlib import Path

import numpy as np
import matplotlib.pyplot as plt
plt.ion()

fname = 'ej_oscil_aten_err'
# Levantamos los datos
pardir = Path("..")
datfile = pardir / f'data/{fname}.dat'

x1, y1, y2 = np.loadtxt(datfile, unpack=True)
# Vamos a graficar sólo algunos valores (uno de cada 5)
x = x1[3:-10:5]
y = y1[3:-10:5]
yexp = y2[3:-10:5]

# Ejemplo de barras de error que dependen del eje x
error = 0.05 + 0.3 * np.abs(y)

fig, (ax0, ax1) = plt.subplots(num='subplots', figsize=(10,4), nrows=1, ncols=2)
ax0.errorbar(x, yexp, yerr=error, fmt='-o')
ax1.plot(x, 2 * (yexp - y) / (yexp + y), 'or', markersize=8)


# Límites de graficación y títulos
ax0.set_title('Datos con error variable')
ax1.set_title('Error relativo')
ax0.set_ylabel('Voltaje (mV)', fontsize='x-large')
ax1.set_xlabel(r'Tiempo ($\mu$-seg)', fontsize='x-large')
ax1.set_ylabel('Error relativo', fontsize='x-large')
ax1.set_xlim((0, 3))

# Guardamos el resultado
plt.savefig(f'{fname}_B.png', dpi=150)
_images/09_1_intro_visualizacion_50_0.png

En este ejemplo utilizamos un enfoque diferente al utilizado anteriormente. Matplotlib presenta también una interface orientada a objetos. La función subplots() devuelve un par fig, axis que son dos objetos utilizados para representar la figura y un eje. Los métodos de estos objetos presentan funcionalidad similar a las funciones del módulo pyplot.


Ejercicios 09 (b)

  1. Para la función definida a trozos:

    \[\begin{split}f(x) = \begin{cases} f_{1}(x) = x^{2}/8 & - \pi < x \le \pi/2 \\ f_{2}(x) = -0.3 x & \pi/2 < x < \pi \\ f_{3}(x) = -(x - 2 \pi)^{2}/6 & \pi \le x \le 5 \pi/2 \\ f_{4}(x) = (x - 2 \pi)/5 & 5 \pi/2 < x \le 3 \pi \end{cases}\end{split}\]

    realizar la siguiente figura de la manera más fiel posible.

    _images/ejercicio_08_1.png

    Pistas: Buscar información sobre plt.text(), plt.fill_between() y sobre plt.xticks y plt.yticks.

  2. Rehacer la siguiente figura:

    _images/ejercicio_08_2.png

.

Personalizando el modo de visualización

Matplotlib da la posibilidad de modificar el estilo de la graficación en distintas “etapas”.

Archivo de configuración

Cuando uno carga el módulo busca un archivo de configuración llamado matplotlibrc

  1. Primero busca un archivo de configuración en el directorio de trabajo también lo lee. En cada caso sobreescribe las variables.

  2. Si la variable MATPLOTLIBRC existe (para el usuario), busca el archivo $MATPLOTLIBRC/matplotlibrc

  3. Luego lee un archivo de configuración global del usuario, que dependiendo del sistema operativo puede ser: * En Linux, .config/matplotlib/matplotlibrc (o en $XDG_CONFIG_HOME/matplotlib/matplotlibrc si la variable XDG_CONFIG_HOME existe) * En otras plataformas puede estar en algún lugar como: C:\Documents and Settings\USUARIO\.matplotlib

  4. Finalmente lee el archivo global de la instalación, INSTALL/matplotlib/mpl-data/matplotlibrc, donde INSTALL se refiere al lugar de instalación

En cualquier caso, podemos obtener el directorio y archivo de configuración con las funciones:

import matplotlib
matplotlib.get_configdir()
'/home/fiol/.config/matplotlib'
matplotlib.matplotlib_fname()
'/usr/share/matplotlib/mpl-data/matplotlibrc'
!head -n 120 '/usr/share/matplotlib/mpl-data/matplotlibrc'
#### MATPLOTLIBRC FORMAT

## NOTE FOR END USERS: DO NOT EDIT THIS FILE!
##
## This is a sample Matplotlib configuration file - you can find a copy
## of it on your system in site-packages/matplotlib/mpl-data/matplotlibrc
## (relative to your Python installation location).
## DO NOT EDIT IT!
##
## If you wish to change your default style, copy this file to one of the
## following locations:
##     Unix/Linux:
##         $HOME/.config/matplotlib/matplotlibrc OR
##         $XDG_CONFIG_HOME/matplotlib/matplotlibrc (if $XDG_CONFIG_HOME is set)
##     Other platforms:
##         $HOME/.matplotlib/matplotlibrc
## and edit that copy.
##
## See https://matplotlib.org/stable/tutorials/introductory/customizing.html#customizing-with-matplotlibrc-files
## for more details on the paths which are checked for the configuration file.
##
## Blank lines, or lines starting with a comment symbol, are ignored, as are
## trailing comments.  Other lines must have the format:
##     key: val  # optional comment
##
## Formatting: Use PEP8-like style (as enforced in the rest of the codebase).
## All lines start with an additional '#', so that removing all leading '#'s
## yields a valid style file.
##
## Colors: for the color values below, you can either use
##     - a Matplotlib color string, such as r, k, or b
##     - an RGB tuple, such as (1.0, 0.5, 0.0)
##     - a double-quoted hex string, such as "#ff00ff".
##       The unquoted string ff00ff is also supported for backward
##       compatibility, but is discouraged.
##     - a scalar grayscale intensity such as 0.75
##     - a legal html color name, e.g., red, blue, darkslategray
##
## String values may optionally be enclosed in double quotes, which allows
## using the comment character # in the string.
##
## This file (and other style files) must be encoded as utf-8.
##
## Matplotlib configuration are currently divided into following parts:
##     - BACKENDS
##     - LINES
##     - PATCHES
##     - HATCHES
##     - BOXPLOT
##     - FONT
##     - TEXT
##     - LaTeX
##     - AXES
##     - DATES
##     - TICKS
##     - GRIDS
##     - LEGEND
##     - FIGURE
##     - IMAGES
##     - CONTOUR PLOTS
##     - ERRORBAR PLOTS
##     - HISTOGRAM PLOTS
##     - SCATTER PLOTS
##     - AGG RENDERING
##     - PATHS
##     - SAVING FIGURES
##     - INTERACTIVE KEYMAPS
##     - ANIMATION

##### CONFIGURATION BEGINS HERE


## ***********************************************************************
## * BACKENDS                                                                *
## ***********************************************************************
## The default backend.  If you omit this parameter, the first working
## backend from the following list is used:
##     MacOSX QtAgg Gtk4Agg Gtk3Agg TkAgg WxAgg Agg
## Other choices include:
##     QtCairo GTK4Cairo GTK3Cairo TkCairo WxCairo Cairo
##     Qt5Agg Qt5Cairo Wx  # deprecated.
##     PS PDF SVG Template
## You can also deploy your own backend outside of Matplotlib by referring to
## the module name (which must be in the PYTHONPATH) as 'module://my_backend'.
##backend: Agg

## The port to use for the web server in the WebAgg backend.
#webagg.port: 8988

## The address on which the WebAgg web server should be reachable
#webagg.address: 127.0.0.1

## If webagg.port is unavailable, a number of other random ports will
## be tried until one that is available is found.
#webagg.port_retries: 50

## When True, open the web browser to the plot that is shown
#webagg.open_in_browser: True

## If you are running pyplot inside a GUI and your backend choice
## conflicts, we will automatically try to find a compatible one for
## you if backend_fallback is True
#backend_fallback: True

#interactive: False
#figure.hooks:          # list of dotted.module.name:dotted.callable.name
#toolbar:     toolbar2  # {None, toolbar2, toolmanager}
#timezone:    UTC       # a pytz timezone string, e.g., US/Central or Europe/Paris


## ***********************************************************************
## * LINES                                                                   *
## ***********************************************************************
## See https://matplotlib.org/stable/api/artist_api.html#module-matplotlib.lines
## for more information on line properties.
#lines.linewidth: 1.5               # line width in points
#lines.linestyle: -                 # solid line
#lines.color:     C0                # has no affect on plot(); see axes.prop_cycle
#lines.marker:          None        # the default marker
#lines.markerfacecolor: auto        # the default marker face color

Hojas de estilo

Matplotlib ha incorporado en los últimos años un paquete que permite cambiar estilos fácilmente utilizando los mismos nombres para los parámetros que hay en el archivo de configuración matplotlibrc.

Este paquete tiene pre-definidos unos pocos estilos, entre ellos varios que emulan otros paquetes o programas. Veamos un ejemplo:

import numpy as np
import matplotlib.pyplot as plt
fdatos = '../data/ej_oscil_aten_err.dat'
x, y, yexp = np.loadtxt(fdatos, unpack=True)
plt.plot(x,y, x, 0.9*y)
[<matplotlib.lines.Line2D at 0x7f54b06180d0>,
 <matplotlib.lines.Line2D at 0x7f54b06187d0>]
_images/09_2_personal_plot_8_1.png
with plt.style.context('ggplot'):
  plt.plot(x,y, x,0.9*y)
_images/09_2_personal_plot_9_0.png
with plt.style.context('grayscale'):
  plt.plot(x,y,'--', x,0.9*y)
_images/09_2_personal_plot_10_0.png
with plt.style.context('fivethirtyeight'):
  plt.plot(x,y, x,0.9*y)
_images/09_2_personal_plot_11_0.png
with plt.style.context('seaborn-dark'):
  plt.plot(x,y, x,0.9*y)
_images/09_2_personal_plot_12_0.png

Los estilos disponibles están guardados en la variable available (una lista)

plt.style.available
['Solarize_Light2',
 '_classic_test_patch',
 '_mpl-gallery',
 '_mpl-gallery-nogrid',
 'bmh',
 'classic',
 'dark_background',
 'darker',
 'fast',
 'fivethirtyeight',
 'ggplot',
 'grayscale',
 'latex',
 'paper',
 'presentation',
 'seaborn-v0_8',
 'seaborn-v0_8-bright',
 'seaborn-v0_8-colorblind',
 'seaborn-v0_8-dark',
 'seaborn-v0_8-dark-palette',
 'seaborn-v0_8-darkgrid',
 'seaborn-v0_8-deep',
 'seaborn-v0_8-muted',
 'seaborn-v0_8-notebook',
 'seaborn-v0_8-paper',
 'seaborn-v0_8-pastel',
 'seaborn-v0_8-poster',
 'seaborn-v0_8-talk',
 'seaborn-v0_8-ticks',
 'seaborn-v0_8-white',
 'seaborn-v0_8-whitegrid',
 'tableau-colorblind10']

Combinando estilos

Los estilos pueden combinarse. En este caso, debe pasarse una lista de strings con los nombres de los estilos a aplicar. Se aplican en forma secuencial. Si dos estilos definen diferentes valores para una variable, el posterior sobreescribe los valores previos.

with plt.style.context(['fivethirtyeight','grayscale']):
  plt.plot(x,y, x,0.9*y)
_images/09_2_personal_plot_16_0.png
with plt.style.context(['grayscale','fivethirtyeight']):
  plt.plot(x,y, x,0.9*y)
_images/09_2_personal_plot_17_0.png

Creación de estilos propios

Podemos crear estilos propios, modificando los defaults con una sintaxis similar a la del archivo de configuración. Por ejemplo creemos un archivo ‘estilo_test’ con algunos parámetros

#!echo "lines.linewidth : 5" > estilo_test
#!echo "xtick.labelsize: 24" >> estilo_test
#!cat estilo_test
plt.plot(x,y)
[<matplotlib.lines.Line2D at 0x7f54b0694450>]
_images/09_2_personal_plot_21_1.png
%pwd
'/home/fiol/Clases/IntPython/clases-python/clases'
with plt.style.context('estilo_test'):
  plt.plot(x,y)
_images/09_2_personal_plot_23_0.png
with plt.style.context('darker'):
  plt.plot(x,y,'C1')
_images/09_2_personal_plot_24_0.png
with plt.style.context('presentation'):
  plt.plot(x,y,'g')
_images/09_2_personal_plot_25_0.png

Para encontrar el lugar donde guardar las hojas de estilo podemos utilizar las funciones de matplotib:

matplotlib.get_configdir()
'/home/fiol/.config/matplotlib'
!ls -1 /home/fiol/.config/matplotlib/stylelib/
darker.mplstyle
latex.mplstyle
paper.mplstyle
presentation.mplstyle
!cat /home/fiol/.config/matplotlib/stylelib/darker.mplstyle
# -- mode: conf --
font.size   : 14
lines.color : white
lines.linewidth   : 2     # line width in points
lines.markersize  : 8
patch.edgecolor : white

text.color : white

axes.facecolor : black
axes.edgecolor : white
axes.labelcolor : white
# Seaborn dark palette
axes.prop_cycle: cycler('color', ['001C7F', '017517', '8C0900', '7600A1', 'B8860B', '006374'])

xtick.color : white
ytick.color : white

grid.color : white

figure.facecolor : black
figure.edgecolor : black

savefig.facecolor : black
savefig.edgecolor : black

Modificación de parámetros dentro de programas

Podemos cambiar directamente los parámetros dentro de nuestros programas modificando el diccionario matplotlib.rcParams

import matplotlib as mpl
mpl.rcParams
# Plot con valores default
plt.plot(x,y)
[<matplotlib.lines.Line2D at 0x7f54a8577590>]
_images/09_2_personal_plot_32_1.png
# Modificamos el valor default de ancho de línea
mpl.rcParams['lines.linewidth'] = 7
plt.plot(x,y)
[<matplotlib.lines.Line2D at 0x7f54a85a8e90>]
_images/09_2_personal_plot_33_1.png
# El nuevo valor default podemos sobreescribirlo para este plot particular
plt.plot(x,y, lw=3)
[<matplotlib.lines.Line2D at 0x7f54a845b890>]
_images/09_2_personal_plot_34_1.png
# Sin embargo, el nuevo valor default no es modificado
plt.plot(x,y)
[<matplotlib.lines.Line2D at 0x7f54a84d09d0>]
_images/09_2_personal_plot_35_1.png

Ejercicios 09 (c)

  1. Notando que la curva en color negro corresponde a la suma de las dos curvas en rojo, rehacer la siguiente figura:

    _images/ejercicio_08_3.png
  2. Crear una hoja de estilo que permita hacer gráficos adecuados para posters y presentaciones. Debe modificar los tamaños para hacerlos legibles a mayores distancias (sugerencia 16pt). El tamaño de la letra de los nombres de ejes y en las leyendas debe ser mayor también. Las líneas deben ser más gruesas (sugerencia: ~4), los símbolos de mayor tamaño (sugerencia ~10).