En los últimos tiempos he estado leyendo en múltiples sitios que matplotlib es feo, que se ve viejuno, que la librería [ponga usted aquí la librería chachiguay que desee] es ‘más mejor’, que es una biblioteca muy pesada,…, pero nunca he leído una argumentación para refutar esas quejas.
Hoy me voy a centrar en la primera queja que he indicado más arriba.
¿Es matplotlib feo?
Cuando se inició el desarrollo de matplotlib el entorno de trabajo era muy diferente al actual. Se hacían gráficas estáticas 2D para ser publicadas en revistas o en la web de hace 10 o más años (ha cambiado un poco el panorama desde entonces). Se inició para ser una alternativa libre a Matlab y es por ello que su API y apariencia es muy parecida a la que ofrece Matlab. De esta forma matplotlib hace gráficos que, de base, son simples y pensados para ser publicados en cualquier sitio sin necesidad de mucha modificación.
A pesar de ofrecer gráficos aceptables de partida (en mi modesta opinión, por supuesto), desde tiempos inmemoriales se puede acceder a la configuración de base y modificarla para el gusto de cada cual. En la versión más antigua que figura en github (0.91.3) podéis encontrar que rcParams
ya está por ahí (fichero modificado por última vez en 2007). El que hubiera querido modificar algo de la configuración básica que trae matplotlib lo podría haber hecho sin mucho esfuerzo y hubiera tardado menos que el perdido en escribir una queja por alguna lista de correo, entrada en algún blog, comentario en reddit,…(*)
(*) Ahora con twitter puede que sea más rápido lanzar la queja que modificar eso que tanto te molesta pero seguirá sin haber argumentación, gracias twitter!!
¿Modificar matplotlib a mi gusto?
Siempre ha sido relativamente sencillo, de hecho, en su momento desde Pybonacci creamos un repositorio con algo de código que te ofrecía una serie de decoradores para conseguir nuevos estilos de forma sencilla.
Pero desde la versión 1.4 tenemos disponible el paquete styles
que permite cambiar de estilos fácilmente y que trae algunos estilos por defecto. Veamos un poco como funciona todo esto:
Primero de todo hacemos todo el previo de imports y mostrar versiones y demás para que el que quiera pueda reproducir los ejemplos sin problemas.
1 2 |
#%install_ext http://raw.github.com/jrjohansson/version_information/master/version_information.py %load_ext version_information |
1 |
%version_information matplotlib, numpy |
Software | Version |
---|---|
Python | 3.4.0 64bit [GCC 4.8.2] |
IPython | 3.0.0-dev |
OS | Linux 3.13.0 24 generic x86_64 with LinuxMint 17 qiana |
matplotlib | 1.4.2 |
numpy | 1.9.1 |
Sun Jan 25 19:51:49 2015 CET |
1 2 3 |
%matplotlib inline import matplotlib.pyplot as plt import numpy as np |
Un gráfico normal por defecto en matplotlib (de esos que son tan feos) en el notebook de IPython será de la siguiente forma:
1 2 3 |
fig, ax = plt.subplots(figsize=(8,4)) ax.plot(np.random.randn(25), label = 'random') ax.legend() |
Usando el paquete styles
modificar la apariencia a uno de los estilos que trae por defecto el paquete sería algo como lo siguiente:
1 2 3 4 5 6 7 8 |
print('Estilos disponibles: ', plt.style.available) estilo = np.random.choice(plt.style.available) print('Vamos a usar el estilo ', estilo) plt.style.use(estilo) # la misma gráfica que antes fig, ax = plt.subplots(figsize=(8,4)) ax.plot(np.random.randn(25), label = 'random') ax.legend() |
1 2 |
Estilos disponibles: ['fivethirtyeight', 'ggplot', 'grayscale', 'dark_background', 'bmh'] Vamos a usar el estilo ggplot |
Como habéis visto en la salida anterior disponéis de varios estilos por defecto, ['ggplot', 'bmh', 'grayscale', 'dark_background', 'fivethirtyeight']
. Probadlos todos si queréis verlos en vivo o ved este notebook.
Si os gustan los valores por defecto podéis volver a ellos usando plt.rcdefaults()
.
No me gusta ninguno de los estilos que vienen por defecto
“Siemprrre negatifffos, nunca positifffos”, pero que no cunda el desánimo. Crear tu propio estilo es sencillo. Vamos a ver como podemos crear una hoja de estilos que se adecúe a nuestros gustos.
Si queremos que nuestro nuevo estilo esté siempre disponible cada vez que usemos matplotlib deberemos incluir la hoja de estilos en la carpeta
~/.config/matplotlib/stylelib/
. Voy a crearla con IPython (lo hago en Linux, no lo he probado en otros sistemas operativos):
1 2 3 |
%mkdir ~/.config # Seguramente esta ya exista %mkdir ~/.config/matplotlib %mkdir ~/.config/matplotlib/stylelib |
Y ahora vamos a definir un nuevo estilo pybonacci como el que definimos en el repositorio de mpl_styles. Para ello vamos a usar IPython para crear la hoja de estilo que se llamará pybonacci.mplstyle
(debe tener la extensión .mplstyle
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
%%writefile ~/.config/matplotlib/stylelib/pybonacci.mplstyle lines.linewidth: 1.0 lines.color: 5390C1 lines.antialiased: True patch.linewidth: 0.5 patch.facecolor: FFD333 patch.edgecolor: FFE771 patch.antialiased: True font.family: Arial font.size: 10.0 font.monospace: DejaVu Sans Mono, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace axes.facecolor: eeeeee axes.edgecolor: bcbcbc axes.linewidth: 1.0 axes.grid: True axes.titlesize: x-large axes.labelsize: large axes.labelcolor: 555555 axes.axisbelow: True axes.color_cycle: 5390C1, FFD333, FFE771, 70A4CB, 4385BB, 3D79AA, 39719E xtick.major.size: 0.0 xtick.minor.size: 0.0 xtick.major.pad: 6.0 xtick.minor.pad: 6.0 xtick.color: 555555 xtick.direction: in ytick.major.size: 0.0 ytick.minor.size: 0.0 ytick.major.pad: 6.0 ytick.minor.pad: 6.0 ytick.color: 555555 ytick.direction: in legend.fancybox: True legend.numpoints: 1 figure.figsize: 11, 8 figure.facecolor: 1.0 figure.edgecolor: 0.5 figure.subplot.hspace: 0.5 |
1 |
Writing /home/kiko/.config/matplotlib/stylelib/pybonacci.mplstyle |
Y ahora, supuestamente, deberíamos poder acceder al nuevo estilo creado:
1 |
print('Estilos disponibles: ', plt.style.available) |
1 |
Estilos disponibles: ['fivethirtyeight', 'ggplot', 'grayscale', 'dark_background', 'bmh'] |
Si veis que no está disponible podéis hacer lo siguiente:
1 2 |
plt.style.reload_library() plt.style.available |
1 2 3 4 5 6 |
['ggplot', 'grayscale', 'dark_background', 'bmh', 'fivethirtyeight', 'pybonacci'] |
Ahora vamos a recrear el gráfico que definimos en el repositorio de mpl_styles para el estilo pybo que definimos allí:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
plt.style.use('pybonacci') x1 = range(10) x2 = np.random.rand(100) y1 = np.random.randn(10) y2 = np.random.rand(100) plt.subplot(2,2,1) plt.plot(x1,y1) plt.plot(x1,y1-1) plt.plot(x1,y1-2) plt.plot(x1,y1-3) plt.plot(x1,y1-4) plt.subplot(2,2,2) plt.scatter(x2, y2) plt.subplot(2,2,3) plt.bar(x1, y1) |
Que he dicho que no me gusta matplotlib
Si a pesar de todo lo expuesto aquí sigue sin gustarte matplotlib (estás en tu derecho y si lo argumentas en los comentarios lo podré entender mejor) tienes varias posibilidades disponibles:
- Bokeh
- GGplot
- Usad alguna librería javascript como Highcharts (ved un tutorial aquí), d3js,…
- Chaco
- Veusz
- PyQwt
No pongo Seaborn puesto que se basa en matplotlib.
Saludos a todos.
P.D.: Este notebook y la hoja de estilos que acabamos de crear está disponible en el repo de notebooks de Pybonacci.
Off topic: en linux y mac puedes crear todos los directorios hijos de una vez con el parámetro -p
mkdir -p /a/b/c
Gracias por el aporte. Como todo se hace desde un notebook de IPython he usado herramientas del notebook que deberían funcionar en win/lin/mac. El notebook tiene acceso a comandos de la shell pero lo he querido hacer paso a paso.
Saludos.
Interesante y divertida entrada.Yo también he leído en muchos sitios que matplotlib es lento, enorme y tal o cual. No soy un experto en él, ni he usado todas las alternativas 2D que comentas.Sería un buen artículo una comparativa entre ellos.Mi sensación es que no creo que haya ninguno mejor.Lo único que se le puede achacar a matplotlib es su manejo 3D, pero para eso hay otros programas y también miles de alternativas ya que no se diseñó pensando en el 3D.Y romperé una lanza por matplotlib ya que es casi un estándar para Python, y se agradece que haya paquetes que no se dejen de desarrollar, cosa muy habitual en el software libre.Que haya programas que,siendo un poco mejores o un poco peores,tengan visos de continuidad (y mejora,mejora que se aprecia en matplotlib de forma clarísima) es ya para mí una garantía de uso.
Felicidades por la entrada.Ánimo y un saludo.
-Es pesado, normal, es que hace muchas cosas. Hay que escribir código para que haga todo eso.
-Es enorme, normal, soporta mucha funcionalidad, backends, eventos, tipos de gráficos, personalización,…
-Es lento, no es un problema que me haya encontrado hasta ahora y llevo unos cuantos años usándolo.
-Es feo, No te has leído el post 😛
Para el tema del 3D tengo pendiente jugar un poco más con three.js, pero eso será otro día.
Gracias por comentar.
Saludos.
Decir de una libreria que puede hacer graficos como los de xkcd (http://jakevdp.github.io/blog/2013/07/10/XKCD-plots-in-matplotlib/) que es fea no es ni bueno ni malo, sino mentira. 😉
Pero si esos gráficos aparecen en la prensa seria (http://pubs.acs.org/doi/abs/10.1021/cs501585k) 😛
Grande Randall y grande Jake \o/
Supongo que despues de aquello del boson de Higgs presentado en Comic Sans (http://www.theverge.com/2012/7/4/3136652/cern-scientists-comic-sans-higgs-boson) todo vale…
jajajajajajajaja
Y de esta entrada ha salido un gili PR ya ‘mergeado’ a matplotlib:
https://github.com/matplotlib/matplotlib/pull/4039
🙂