2011-10-29 18 views
23

En R, hay una función llamada abline en la que se puede dibujar una línea en un trazado basado en la especificación de la pendiente de intercepción (primer argumento) (segundo argumento). Por ejemplo,¿agregar línea basada en la pendiente e interceptar en matplotlib?

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

donde la línea con intersección de 0 y la pendiente de 1 abarca toda la gama de la trama. ¿Hay tal función en matplotlib.pyplot?

+2

No, no lo hay. Sería una función útil tener. Hay 'axvline',' axvspan', 'axhline', y' axhspan', que son funciones verticales y horizontales similares, pero la forma habitual en matplotlib es trazar una línea en la pendiente dada (lo que significa que eventualmente ir más allá, si trabajas de forma interactiva). La forma "correcta" de hacerlo (es decir, siempre se extiende por el eje, no importa dónde haga zoom) es en realidad un poco complicado, aunque el marco ('matplotlib.transforms') está ahí. –

+1

Sí, eso es desafortunado ... Matlab tampoco tiene esta función. Por otro lado, las tramas de R son estáticas (el sistema de gráficos 'base' para el que 'abline' existe) así que hay menos de qué preocuparse (es algo bueno y malo, supongo). – hatmatrix

Respuesta

4

Supongo que en el caso de (intercept, slope) de (0, 1) la siguiente función podría utilizarse y extenderse para acomodar otras pendientes e intersecciones, pero no se reajustará si se modifican los límites de los ejes o si se vuelve a activar la autoescala.

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

Bueno, si solo quieres una línea que vaya desde la esquina inferior izquierda hasta la esquina superior derecha, no importa cómo hagas zoom, entonces puedes hacer 'plt.plot ([0,1], [0,1 ], transform = plt.gca(). transAxes) '. Sin embargo, esto no representará una pendiente de 1 a 1 en las coordenadas de datos, y _siempre_ irá de la esquina inferior izquierda a la superior derecha, donde sea que haga un acercamiento a ... Como usted dijo, sin embargo, un 'abline' más general el reemplazo es más difícil para el uso interactivo ... –

+0

Ah, esto es bastante interesante el transAxes. Puedo imaginar que voy a utilizarlo en algún momento ... (a menudo tengo muchas parcelas donde xlim = ylim, o debería ser). – hatmatrix

8

yo no podía entender una manera de hacerlo sin recurrir a las devoluciones de llamada, pero esto parece que funciona bastante bien.

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

pequeña mejora: intercambiar las líneas: ax.figure.canvas.draw() y self._update_lim (Ninguno) por lo que la trama se actualiza en realidad sin tener que hacer clic en el @tal ventana – tal

+0

Por fin en mi versión de matplotlib (1.4.3) es necesario renderizar los ejes padre al menos una vez antes de llamar a 'self.axes.draw_artist (self)', de lo contrario, obtengo un 'AssertionError' en la línea' assert self._cachedRenderer is not None' en 'Axes. draw_artist'. Siempre puede insertar un sorteo adicional después de que se haya llamado a '_update_lim'. Normalmente inicializo el 'ABLine' desde dentro de una función de conveniencia que hace esto por mí, en lugar de crear una instancia directamente. –

26

Sé que esta pregunta es un par de años, pero ya que no hay una respuesta aceptada, voy a añadir lo que funciona para mí.

Puede trazar los valores en su gráfico, y luego generar otro conjunto de valores para las coordenadas de la mejor línea de ajuste y trazar eso sobre su gráfico original. Por ejemplo, véase el siguiente código:

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

Muchas de estas soluciones están centrando en la adición de una línea de la trama que se ajuste a los datos. Aquí hay una solución simple para agregar una línea arbitraria a la trama basada en una pendiente e intersección.

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, '--') 
Cuestiones relacionadas