2012-04-25 12 views
5

Quiero tener algunas líneas de cuadrícula en una trama, pero en realidad las líneas de longitud completa son demasiado/distracción, incluso las líneas discontinuas de color gris claro. Fui y de forma manual hice alguna edición de la salida SVG para obtener el efecto que estaba buscando. ¿Se puede hacer esto con matplotlib? Eché un vistazo a la api pyplot para cuadrícula, y lo único que puedo ver que podría acercarse a ella son los xdata y ydata Line2D kwargs.En lugar de líneas de cuadrícula en un trazado, ¿matplotlib imprime cruces de cuadrícula?

enter image description here

Respuesta

3

Esto no se puede hacer a través de la API básica, debido a que las líneas de la cuadrícula se crean utilizando sólo dos puntos. Las líneas de la cuadrícula necesitarían un punto de 'datos' en cada marca para que haya un marcador dibujado. Esto se muestra en el siguiente ejemplo:

import matplotlib.pyplot as plt 

ax = plt.subplot(111) 
ax.grid(clip_on=False, marker='o', markersize=10) 
plt.savefig('crosses.png') 
plt.show() 

Esto se traduce en:

enter image description here

Observe cómo el 'o' marcadores son sólo al principio y el final de los bordes Ejes, debido a que las líneas de la cuadrícula solo involucra dos puntos.

Puede escribir un método para emular lo que desee, creando las marcas cruzadas con una serie de Artists, pero es más rápido simplemente aprovechar las capacidades básicas de trazado para dibujar el patrón cruzado.

Esto es lo que hago en el siguiente ejemplo:

import matplotlib.pyplot as plt 
import numpy as np 

NPOINTS=100 

def set_grid_cross(ax, in_back=True): 
    xticks = ax.get_xticks() 
    yticks = ax.get_yticks() 
    xgrid, ygrid = np.meshgrid(xticks, yticks) 
    kywds = dict() 
    if in_back: 
     kywds['zorder'] = 0 
    grid_lines = ax.plot(xgrid, ygrid, 'k+', **kywds) 

xvals = np.arange(NPOINTS) 
yvals = np.random.random(NPOINTS) * NPOINTS 

ax1 = plt.subplot(121) 
ax2 = plt.subplot(122) 

ax1.plot(xvals, yvals, linewidth=4) 
ax1.plot(xvals, xvals, linewidth=7) 
set_grid_cross(ax1) 
ax2.plot(xvals, yvals, linewidth=4) 
ax2.plot(xvals, xvals, linewidth=7) 
set_grid_cross(ax2, in_back=False) 

plt.savefig('gridpoints.png') 
plt.show() 

Esto se traduce en la siguiente figura:

enter image description here

Como se puede ver, tomo las marcas de graduación en xy y para definir una serie de puntos donde quiero marcas de cuadrícula ('+'). Yo uso meshgrid para tomar dos matrices 1D y hacer 2 matrices 2D correspondientes al doble bucle sobre cada punto de la grilla. Tracé esto con el estilo de marca como '+', y he terminado ... casi. Esto traza las cruces en la parte superior, y agregué una palabra clave adicional para reordenar la lista de líneas asociadas con la trama. Ajusto el zorder de las marcas de la rejilla si van a dibujarse detrás de todo. *****

El ejemplo muestra la subparcela izquierda donde, por defecto, la rejilla se coloca hacia atrás, y la subtrama derecha deshabilita esta opción. Puedes notar la diferencia si sigues la línea verde en cada parcela.

Si te molesta por tener rejilla cruces en la frontera, puede quitar el primer y último marcas de graduación para tanto x como y antes de definir la red en set_grid_cross, así:

xticks = ax.get_xticks()[1:-1] #< notice the slicing 
yticks = ax.get_yticks()[1:-1] #< notice the slicing 
xgrid, ygrid = np.meshgrid(xticks, yticks) 

hago esto en el siguiente ejemplo, usando un marcador diferente más grande para hacer mi punto:

enter image description here

***** Gracias a la respuesta por @fraxel por señalar esto.

+0

informativo e innovador! Y los kwargs se pueden usar para establecer el color y el tamaño con más detalle. –

+0

También tiene el problema de que traza marcadores en los ejes. Si pudiera simplemente cortar las matrices xgrid, ygrid –

3

Puede dibujar en segmentos de línea en cada intersección de los puntos de marca.Es bastante fácil de hacer, solo toma las posiciones de tilde get_ticklocs() para ambos ejes, luego recorre todas las combinaciones, dibujando segmentos de línea cortos usando axhline y axvline, creando así una cruz en cada intersección. Establecí zorder=0 para que las líneas cruzadas se dibujen primero, de modo que estén detrás de los datos de trazado. Es fácil controlar el color/alfa y el tamaño del cabello cruzado. Un par de ligeras 'trampas' ... hacen la trama antes de obtener las ubicaciones de ticks ... y también parece que los parámetros xmin y xmax requieren normalización.

import matplotlib.pyplot as plt 

fig = plt.figure() 
ax = fig.add_subplot(1,1,1)  
ax.plot((0,2,3,5,5,5,6,7,8,6,6,4,3,32,7,99), 'r-',linewidth=4) 

x_ticks = ax.xaxis.get_ticklocs() 
y_ticks = ax.yaxis.get_ticklocs()  
for yy in y_ticks[1:-1]: 
    for xx in x_ticks[1:-1]: 
     plt.axhline(y=yy, xmin=xx/max(x_ticks) - 0.02, 
       xmax=xx/max(x_ticks) + 0.02, color='gray', alpha=0.5, zorder=0) 
     plt.axvline(x=xx, ymin=yy/max(y_ticks) - 0.02, 
       ymax=yy/max(y_ticks) + 0.02, color='gray', alpha=0.5, zorder=0) 
plt.show() 

enter image description here

+0

¡Genial! Mucha flexibilidad para ajustar el tamaño/longitud de las cruces. Tiene razón sobre el bit de normalización, tendrá que trabajar para obtener la proporción correcta, especialmente para tamaños de figuras no cuadrados. Veo que hay líneas adicionales en los ejes donde también están las marcas, así que intentaré deshacerme de ellas. –

+0

@a ben diferente - ¡Oye, no había notado acerca de las cruces en los ejes xey! He actualizado para deshacerse de ellos con rebanadas. Y sí, ¡los valores mínimo y máximo dependen del tamaño de la gráfica en lugar de los valores de los ejes, pero es muy extraño! – fraxel

Cuestiones relacionadas