2011-10-29 12 views
23

W R istnieje funkcja o nazwie abline, w której można narysować linię na wykresie opartym na specyfikacji nachylenia przechwyconego (pierwszego argumentu) (drugi argument). Na przykład:dodać linię opartą na nachyleniu i przechwyceniu w matplotlib?

plot(1:10,1:10) 
abline(0,1) 

gdzie linia z przecięciem 0 i nachyleniem 1 obejmuje cały zakres wykresu. Czy jest taka funkcja w matplotlib.pyplot?

+2

Nie, nie ma. Byłaby przydatna funkcja. Są "axvline", "axvspan", "axhline" i "axhspan", które są podobnymi funkcjami pionowymi i poziomymi, ale zwykłym sposobem w matplotlib jest po prostu narysowanie linii na danym zboczu (co oznacza, że ​​w końcu powiększaj poza nią, jeśli pracujesz interaktywnie.). "Prawidłowy" sposób robienia tego (tj. Tak, że zawsze obejmuje on oś bez względu na to, gdzie się przybliża) jest rzeczywiście nieco skomplikowany, chociaż istnieje framework ('matplotlib.transforms'). –

+1

Tak, to niefortunne ... Matlab również nie ma tej funkcji. Z drugiej strony, wykresy R są statyczne ("podstawowy" system graficzny, dla którego istnieje "abline"), więc mniej martwić się o to (jest to dobre i złe, co przypuszczam). – hatmatrix

Odpowiedz

4

Przypuszczam, że w przypadku (intercept, slope) z (0, 1) można użyć następującej funkcji i rozszerzyć ją, aby uwzględnić inne nachylenia i przechwyty, ale nie zostanie ona zmieniona, jeśli ograniczenia osi zostaną zmienione lub autoskalowanie zostanie ponownie włączone.

def abline(): 
    gca = plt.gca() 
    gca.set_autoscale_on(False) 
    gca.plot(gca.get_xlim(),gca.get_ylim()) 

import matplotlib.pyplot as plt 
plt.scatter(range(10),range(10)) 
abline() 
plt.draw() 
+1

Cóż, jeśli chcesz tylko linię, która przechodzi od lewego dolnego rogu do prawego górnego rogu, niezależnie od tego, jak powiększasz, możesz po prostu zrobić: plt.plot ([0,1], [0,1 ], transform = plt.gca(). transAxes) '. Nie będzie to jednak nachylenie 1 na 1 we współrzędnych danych i będzie jechać od lewego dolnego rogu do prawego górnego rogu, gdziekolwiek się przybliżasz ... Tak jak powiedziałeś, bardziej ogólny "abline" wymiana jest trudniejsza do interaktywnego użycia ... –

+0

Ah, to jest całkiem interesujące transAxes. Mogę sobie wyobrazić, że wykorzystam to w pewnym momencie ... (często mam wiele wątków, w których xlim = ylim, albo powinno być). – hatmatrix

8

nie mogłem zrozumieć sposób, aby to zrobić bez uciekania się do wywołania zwrotne, ale to wydaje się dość dobrze.

import numpy as np 
from matplotlib import pyplot as plt 


class ABLine2D(plt.Line2D): 

    """ 
    Draw a line based on its slope and y-intercept. Additional arguments are 
    passed to the <matplotlib.lines.Line2D> constructor. 
    """ 

    def __init__(self, slope, intercept, *args, **kwargs): 

     # get current axes if user has not specified them 
     if not 'axes' in kwargs: 
      kwargs.update({'axes':plt.gca()}) 
     ax = kwargs['axes'] 

     # if unspecified, get the current line color from the axes 
     if not ('color' in kwargs or 'c' in kwargs): 
      kwargs.update({'color':ax._get_lines.color_cycle.next()}) 

     # init the line, add it to the axes 
     super(ABLine2D, self).__init__([], [], *args, **kwargs) 
     self._slope = slope 
     self._intercept = intercept 
     ax.add_line(self) 

     # cache the renderer, draw the line for the first time 
     ax.figure.canvas.draw() 
     self._update_lim(None) 

     # connect to axis callbacks 
     self.axes.callbacks.connect('xlim_changed', self._update_lim) 
     self.axes.callbacks.connect('ylim_changed', self._update_lim) 

    def _update_lim(self, event): 
     """ called whenever axis x/y limits change """ 
     x = np.array(self.axes.get_xbound()) 
     y = (self._slope * x) + self._intercept 
     self.set_data(x, y) 
     self.axes.draw_artist(self) 
+0

niewielka poprawa: zamienić linie: ax.figure.canvas.draw() i self._update_lim (None) więc fabuła jest właściwie aktualizowane bez konieczności klikania @tal okno – tal

+0

wreszcie na mojej wersji matplotlib (1.4.3) konieczne jest wyrenderowanie osi nadrzędnych co najmniej raz przed wywołaniem 'self.axes.draw_artist (self)', w przeciwnym razie otrzymam 'AssertionError' na linii' assert self._cachedRenderer nie jest None' w 'Axes. draw_artist'. Zawsze można dodać dodatkowe losowanie po wywołaniu '_update_lim'. Zwykle inicjuję 'ABLine' od wewnątrz funkcji wygody, która robi to dla mnie, zamiast bezpośredniego tworzenia instancji. –

26

Wiem, że to pytanie jest kilka lat, ale ponieważ nie jest akceptowana odpowiedź, dodam, co działa dla mnie.

Można tylko wykreślić wartości na wykresie, a następnie wygenerować inny zestaw wartości dla współrzędnych linii najlepszego dopasowania i wykreślić wykres na oryginalnym wykresie. Na przykład, patrz poniższy kod:

import matplotlib.pyplot as plt 
import numpy as np 

# Some dummy data 
x = [1, 2, 3, 4, 5, 6, 7] 
y = [1, 3, 3, 2, 5, 7, 9] 

# Find the slope and intercept of the best fit line 
slope, intercept = np.polyfit(x, y, 1) 

# Create a list of values in the best fit line 
abline_values = [slope * i + intercept for i in x] 

# Plot the best fit line over the actual values 
plt.plot(x, y, '--') 
plt.plot(x, abline_values, 'b') 
plt.title(slope) 
plt.show() 
5
X = np.array([1, 2, 3, 4, 5, 6, 7]) 
Y = np.array([1.1,1.9,3.0,4.1,5.2,5.8,7]) 

scatter (X,Y) 
slope, intercept = np.polyfit(X, Y, 1) 
plot(X, X*slope + intercept, 'r') 
16

Wiele z tych rozwiązań są koncentrując się na dodanie odpowiedniego wiersza do terenu, który pasuje do danych. Oto proste rozwiązanie do dodawania dowolnej linii do wykresu na podstawie nachylenia i punktu przecięcia.

def abline(slope, intercept): 
    """Plot a line from slope and intercept""" 
    axes = plt.gca() 
    x_vals = np.array(axes.get_xlim()) 
    y_vals = intercept + slope * x_vals 
    plt.plot(x_vals, y_vals, '--') 
Powiązane problemy