2012-04-25 15 views
5

Chcę mieć kilka linii siatki na wykresie, ale w rzeczywistości linie o pełnej długości są za dużo/rozpraszające, nawet przerywane jasnoszare linie. Poszedłem i ręcznie dokonałem edycji pliku SVG, aby uzyskać efekt, którego szukałem. Czy można to zrobić za pomocą matplotlib? Spojrzałem na apik dla pyplota, a jedyną rzeczą, która może być w stanie zbliżyć się do niego, są pliki xdata i ydata Line2D kwargs.Zamiast linii siatki na wykresie, czy matplotlib może drukować krzyże siatki?

enter image description here

Odpowiedz

3

ta nie może być wykonana przez podstawowe API, ponieważ linie siatki są tworzone przy użyciu tylko dwóch punktów. Linie siatki wymagałyby "punktu danych" przy każdym znaku podziałki, aby można było narysować znacznik. Jest to pokazane w poniższym przykładzie:

import matplotlib.pyplot as plt 

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

Wynika to z:

enter image description here

zauważyć, jak 'o' markery są tylko na początku i na końcu krawędzi Osie, ponieważ linii siatki obejmuje tylko dwa punkty.

Można napisać metodę emulowania tego, co chcemy, tworząc krzyżyki przy użyciu serii Artists, ale szybciej można wykorzystać podstawowe funkcje kreślenia, aby narysować krzyżyk.

To jest to, co robię w poniższym przykładzie:

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() 

Wynika to na poniższym rysunku:

enter image description here

Jak widać, biorę znaków podziałki w xi y, aby zdefiniować serię punktów, w których chcę uzyskać znaki siatki ("+"). Używam meshgrid do robienia dwóch tablic 1D i tworzę 2 tablice 2D odpowiadające podwójnej pętli nad każdym punktem siatki. Wykreślam to ze stylem znacznika jako '+', i skończyłem ... prawie. To kreśli krzyże na górze i dodałem dodatkowe słowo kluczowe, aby zmienić kolejność linii powiązanych z fabułą. Dopasowuję zorder znaczników siatki, jeśli mają zostać narysowane za wszystkim. *****

Przykład pokazuje lewy subplot, gdzie domyślnie kratka jest umieszczona z tyłu, a prawy subplot wyłącza tę opcję. Możesz zauważyć różnicę, jeśli podążasz zieloną linią na każdym poletku.

Jeśli przeszkadza poprzez siatkę krzyże na granicy, można usunąć pierwszy i ostatni znaków podziałki dla obu xiy przed zdefiniować siatkę w set_grid_cross, tak:

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

zrobić to w poniższym przykładzie, stosując większą, inny znacznik, aby mój punkt widzenia:

enter image description here

***** Dzięki za odpowiedź @fraxel za wskazanie na to.

+0

informacyjny i innowacyjne! Za pomocą kwargs można ustawić kolor i rozmiar bardziej szczegółowo. –

+0

Ma również problem z wykreślaniem znaczników na osiach. Gdybym mógł po prostu przeciąć xgrid, tablice ygrid –

3

Możesz rysować na segmentach linii na każdym przecięciu punktów tickowych.Jest to dość łatwe do zrobienia, wystarczy chwycić obie lokalizacje, get_ticklocs() dla obu osi, a następnie przechodzić przez wszystkie kombinacje, rysując krótkie segmenty linii, używając axhline i axvline, tworząc w ten sposób krzyżyk w każdym punkcie przecięcia. Ustawiłem zorder=0, więc krzyżyki są rysowane najpierw, tak że znajdują się za danymi wykresu. Łatwo kontrolować rozmiar koloru/alfa i krzyża. Kilka drobnych "gotchas" ... wykonaj fabułę zanim zdobędziesz lokalizacje zaznaczania ... a także parametry xmin i xmax wydają się wymagać normalizacji.

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

Świetnie! Mnóstwo elastyczności, aby dostroić rozmiar/długość krzyży. Masz rację, jeśli chodzi o bit normalizacji, będziesz musiał pracować nad poprawieniem proporcji, szczególnie w przypadku rozmiarów nie-kwadratowych. Widzę, że są dodatkowe linie na osiach, gdzie znaki są zbyt, więc spróbuję się ich pozbyć. –

+0

@a inny ben - Hej, nie zauważyłem krzyży na osi X i Y! Zaktualizowałem, aby pozbyć się ich plasterkami. I tak, wartości min i max zależne od rozmiaru wykresu, a nie od wartości osi, są bardzo dziwne! – fraxel

Powiązane problemy