¿Hacer que los gráficos de matplotlib se vean como R por defecto?

¿Hay alguna manera de hacer que matplotlib comporte de manera idéntica a R, o casi como R, en términos de trazar los valores predeterminados? Por ejemplo, R trata sus ejes de forma bastante diferente a matplotlib . El siguiente histogtwig introduzca la descripción de la imagen aquí

tiene “ejes flotantes” con tics hacia afuera, de manera que no hay tics internos (a diferencia de matplotlib ) y los ejes no se cruzan “cerca” del origen. Además, el histogtwig puede “desbordarse” a valores que no están marcados por la marca, por ejemplo, el eje x termina en 3, pero los histogtwigs se extienden ligeramente más allá. ¿Cómo se puede lograr esto automáticamente para todos los histogtwigs en matplotlib ?

Pregunta relacionada: los diagtwigs de dispersión y los gráficos de línea tienen diferentes configuraciones de ejes predeterminadas en R, por ejemplo: introduzca la descripción de la imagen aquí

No hay garrapatas internas de nuevo y las garrapatas miran hacia afuera. Además, las marcas comienzan ligeramente después del punto de origen (donde los ejes y y x se cruzan en la parte inferior izquierda de los ejes) y las marcas terminan ligeramente antes de que terminen los ejes. De esta manera, las tags de la marca del eje x más bajo y la marca del eje y más bajo no pueden realmente cruzarse, porque hay un espacio entre ellas y esto da a las plots un aspecto limpio muy elegante. Tenga en cuenta que también hay mucho más espacio entre las marcas de verificación de los ejes y las marcas.

Además, de forma predeterminada, no hay marcas en los ejes x o y no etiquetados, lo que significa que el eje y a la izquierda que es paralelo al eje y etiquetado a la derecha no tiene marcas, y lo mismo para el eje x, otra vez eliminando el desorden de las plots.

¿Hay alguna manera de hacer que matplotlib se vea así? ¿Y en general, buscar por defecto tanto como por defecto los gráficos R? Me gusta mucho matplotlib pero creo que el comportamiento de trazado de valores predeterminados / fuera de la caja realmente ha funcionado bien y su configuración predeterminada rara vez lleva a tags de garrapatas superpuestas, desorden o datos aplastados, por lo que me gustaría que los valores predeterminados sean tanto como sea posible.

Editar 1 año después:

Con seaborn , el siguiente ejemplo se convierte en:

 import numpy as np import matplotlib.pyplot as plt import seaborn seaborn.set(style='ticks') # Data to be represented X = np.random.randn(256) # Actual plotting fig = plt.figure(figsize=(8,6), dpi=72, facecolor="white") axes = plt.subplot(111) heights, positions, patches = axes.hist(X, color='white') seaborn.despine(ax=axes, offset=10, trim=True) fig.tight_layout() plt.show() 

Bastante dang fácil

Publicación original:

Esta entrada de blog es la mejor que he visto hasta ahora. http://messymind.net/making-matplotlib-look-like-ggplot/

No se enfoca en sus diagtwigs de R estándar, como se ve en la mayoría de los ejemplos del tipo “cómo empezar”. En su lugar, trata de emular el estilo de ggplot2, que parece casi universalmente anunciado como elegante y bien diseñado.

Para obtener las espinas del eje como se ve en el diagtwig de barras, intente seguir uno de los primeros ejemplos aquí: http://www.loria.fr/~rougier/coding/gallery/

Por último, para obtener las marcas de verificación del eje que apuntan hacia afuera, puede editar sus archivos matplotlibrc para que digan xtick.direction : out y ytick.direction : out .

Combinando estos conceptos juntos obtenemos algo como esto:

 import numpy as np import matplotlib import matplotlib.pyplot as plt # Data to be represented X = np.random.randn(256) # Actual plotting fig = plt.figure(figsize=(8,6), dpi=72, facecolor="white") axes = plt.subplot(111) heights, positions, patches = axes.hist(X, color='white') axes.spines['right'].set_color('none') axes.spines['top'].set_color('none') axes.xaxis.set_ticks_position('bottom') # was: axes.spines['bottom'].set_position(('data',1.1*X.min())) axes.spines['bottom'].set_position(('axes', -0.05)) axes.yaxis.set_ticks_position('left') axes.spines['left'].set_position(('axes', -0.05)) axes.set_xlim([np.floor(positions.min()), np.ceil(positions.max())]) axes.set_ylim([0,70]) axes.xaxis.grid(False) axes.yaxis.grid(False) fig.tight_layout() plt.show() 

La posición de las espinas se puede especificar de varias maneras. Si ejecuta el código anterior en IPython, puede hacer axes.spines['bottom'].set_position? para ver todas sus opciones.

Parcela de barra de estilo R en python

Así que sí. No es exactamente trivial, pero puedes acercarte.

matplotlib> = 1.4 soporta estilos (y ggplot-style está integrado):

 In [1]: import matplotlib as mpl In [2]: import matplotlib.pyplot as plt In [3]: import numpy as np In [4]: mpl.style.available Out[4]: [u'dark_background', u'grayscale', u'ggplot'] In [5]: mpl.style.use('ggplot') In [6]: plt.hist(np.random.randn(100000)) Out[6]: ... 

introduzca la descripción de la imagen aquí

# # # # # #

EDITAR 14/10/2013: para información, ggplot ahora se ha implementado para python (construido en matplotlib).

Vea este blog o vaya directamente a la página de github del proyecto para obtener más información y ejemplos.

# # # # # #

Que yo sepa, no hay una solución incorporada en matplotlib que le dé directamente a sus figuras un aspecto similar al de R.

Algunos paquetes, como mpltools , agregan soporte para las hojas de estilo usando los rc-parámetros de Matplotlib, y pueden ayudarlo a obtener una apariencia de ggplot (vea el estilo de ggplot para un ejemplo).

Sin embargo, dado que todo se puede ajustar en matplotlib, puede ser más fácil para usted desarrollar directamente sus propias funciones para lograr exactamente lo que desea. A modo de ejemplo, a continuación se muestra un fragmento que le permitirá personalizar fácilmente los ejes de cualquier gráfico de matplotlib.

 def customaxis(ax, c_left='k', c_bottom='k', c_right='none', c_top='none', lw=3, size=20, pad=8): for c_spine, spine in zip([c_left, c_bottom, c_right, c_top], ['left', 'bottom', 'right', 'top']): if c_spine != 'none': ax.spines[spine].set_color(c_spine) ax.spines[spine].set_linewidth(lw) else: ax.spines[spine].set_color('none') if (c_bottom == 'none') & (c_top == 'none'): # no bottom and no top ax.xaxis.set_ticks_position('none') elif (c_bottom != 'none') & (c_top != 'none'): # bottom and top ax.tick_params(axis='x', direction='out', width=lw, length=7, color=c_bottom, labelsize=size, pad=pad) elif (c_bottom != 'none') & (c_top == 'none'): # bottom but not top ax.xaxis.set_ticks_position('bottom') ax.tick_params(axis='x', direction='out', width=lw, length=7, color=c_bottom, labelsize=size, pad=pad) elif (c_bottom == 'none') & (c_top != 'none'): # no bottom but top ax.xaxis.set_ticks_position('top') ax.tick_params(axis='x', direction='out', width=lw, length=7, color=c_top, labelsize=size, pad=pad) if (c_left == 'none') & (c_right == 'none'): # no left and no right ax.yaxis.set_ticks_position('none') elif (c_left != 'none') & (c_right != 'none'): # left and right ax.tick_params(axis='y', direction='out', width=lw, length=7, color=c_left, labelsize=size, pad=pad) elif (c_left != 'none') & (c_right == 'none'): # left but not right ax.yaxis.set_ticks_position('left') ax.tick_params(axis='y', direction='out', width=lw, length=7, color=c_left, labelsize=size, pad=pad) elif (c_left == 'none') & (c_right != 'none'): # no left but right ax.yaxis.set_ticks_position('right') ax.tick_params(axis='y', direction='out', width=lw, length=7, color=c_right, labelsize=size, pad=pad) 

EDITAR: para espinas que no se tocan, vea la función a continuación que induce un desplazamiento de 10 puntos de las espinas (tomado de este ejemplo en el sitio web de matplotlib).

 def adjust_spines(ax,spines): for loc, spine in ax.spines.items(): if loc in spines: spine.set_position(('outward',10)) # outward by 10 points spine.set_smart_bounds(True) else: spine.set_color('none') # don't draw spine 

Por ejemplo, el código y las dos gráficas a continuación le muestran la salida predeterminada de matplotib (a la izquierda), y la salida cuando se llama a las funciones (a la derecha):

 import numpy as np import matplotlib.pyplot as plt fig,(ax1,ax2) = plt.subplots(figsize=(8,5), ncols=2) ax1.plot(np.random.rand(20), np.random.rand(20), 'ok') ax2.plot(np.random.rand(20), np.random.rand(20), 'ok') customaxis(ax2) # remove top and right spines, ticks out adjust_spines(ax2, ['left', 'bottom']) # non touching spines plt.show() 

imagen

Por supuesto, le llevará tiempo averiguar qué parámetros deben modificarse en matplotlib para que sus gráficos se vean exactamente como los de R, pero no estoy seguro de que haya otras opciones en este momento.

Me gustaría ver Bokeh que tiene como objective “proporcionar un equivalente Python convincente de ggplot en R”. Ejemplo aquí

EDITAR: También puedes ver Seaborn , que intenta reproducir el estilo visual y la syntax de ggplot2.

Aquí hay una entrada de blog que te puede interesar leer:

Trazado para Pandas GSoC2012

http://pandasplotting.blogspot.com/

Decidí intentar implementar una interfaz de trazado de gráficos de tipo ggplot2 … Todavía no estoy seguro de cuánta funcionalidad de ggplot2 implementar …

El autor bifurcó pandas y construyó lo que parece ser una gran cantidad de gramática de estilo ggplot2 para pandas.

Parcelas de densidad

 plot = rplot.RPlot(tips_data, x='total_bill', y='tip') plot.add(rplot.TrellisGrid(['sex', 'smoker'])) plot.add(rplot.GeomHistogram()) plot.render(plt.gcf()) 

La bifurcación de pandas está aquí: https://github.com/orbitfold/pandas

Parece que la carne del código para hacer los gráficos con influencia R está en un archivo llamado rplot.py que se puede encontrar en una twig en el repository.

 class GeomScatter(Layer): """ An efficient scatter plot, use this instead of GeomPoint for speed. """ class GeomHistogram(Layer): """ An efficient histogram, use this instead of GeomBar for speed. """ 

Enlace a la sucursal:

https://github.com/orbitfold/pandas/blob/rplot/pandas/tools/rplot.py

Pensé que esto era realmente genial, pero no puedo averiguar si este proyecto se está manteniendo o no. El último commit fue hace un tiempo.

Establecer espinas en matplotlibrc explica por qué no es posible editar simplemente los valores predeterminados de Matplotlib para producir histogtwigs de estilo R. Para los diagtwigs de dispersión, el búfer del eje de datos del estilo R en matplotlib y en matplotlib, ¿cómo dibuja las marcas del eje del estilo R que apuntan hacia afuera desde los ejes? muestra algunos valores predeterminados que se pueden cambiar para dar un aspecto más R-ish. Construyendo a partir de algunas de las otras respuestas, la siguiente función hace un buen trabajo imitando el estilo del histogtwig de R, asumiendo que has llamado hist() en tu instancia de Axes con facecolor='none' .

 def Rify(axes): ''' Produce R-style Axes properties ''' xticks = axes.get_xticks() yticks = axes.get_yticks() #remove right and upper spines axes.spines['right'].set_color('none') axes.spines['top'].set_color('none') #make the background transparent axes.set_axis_bgcolor('none') #allow space between bottom and left spines and Axes axes.spines['bottom'].set_position(('axes', -0.05)) axes.spines['left'].set_position(('axes', -0.05)) #allow plot to extend beyond spines axes.spines['bottom'].set_bounds(xticks[0], xticks[-2]) axes.spines['left'].set_bounds(yticks[0], yticks[-2]) #set tick parameters to be more R-like axes.tick_params(direction='out', top=False, right=False, length=10, pad=12, width=1, labelsize='medium') #set x and y ticks to include all but the last tick axes.set_xticks(xticks[:-1]) axes.set_yticks(yticks[:-1]) return axes 

La biblioteca de visualización Seaborn puede hacer eso. Por ejemplo, para reproducir el estilo del uso del histogtwig R:

 sns.despine(offset=10, trim=True) 

como en https://seaborn.pydata.org/tutorial/aesthetics.html#removing-axes-spines

introduzca la descripción de la imagen aquí

Para reproducir el estilo del diagtwig de dispersión R use:

 sns.set_style("ticks") 

como se muestra en https://seaborn.pydata.org/tutorial/aesthetics.html#seaborn-figure-styles

introduzca la descripción de la imagen aquí

import matplotlib.pyplot as plt plt.style.use('ggplot')

haz algo aquí, y disfrútalo.