Hinzufügen einer beliebigen Zeile zu einem Matplotlib-Plot in ipython notebook

119

Ich bin ziemlich neu in Python / Matplotlib und benutze es über das Ipython-Notizbuch. Ich versuche, einem vorhandenen Diagramm einige Anmerkungslinien hinzuzufügen, und kann nicht herausfinden, wie die Linien in einem Diagramm gerendert werden. Also zum Beispiel, wenn ich Folgendes zeichne:

import numpy as np
np.random.seed(5)
x = arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
p =  plot(x, y, "o")

Ich erhalte die folgende Grafik:

schönes Streudiagramm

Wie würde ich also eine vertikale Linie von (70.100) bis (70.250) hinzufügen? Was ist mit einer diagonalen Linie von (70.100) bis (90.200)?

Ich habe ein paar Dinge ausprobiert, die Line2D()meinerseits nur zu Verwirrung geführt haben. In Rwürde ich einfach die Funktion segmente () verwenden, die Liniensegmente hinzufügen würde. Gibt es ein Äquivalent in matplotlib?

JD Long
quelle

Antworten:

184

Sie können die gewünschten Linien direkt zeichnen, indem Sie dem plotBefehl die entsprechenden Daten (Grenzen der Segmente) zuführen :

plot([x1, x2], [y1, y2], color='k', linestyle='-', linewidth=2)

(Natürlich können Sie die Farbe, die Linienbreite, den Linienstil usw. auswählen.)

Aus Ihrem Beispiel:

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(5)
x = np.arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
plt.plot(x, y, "o")


# draw vertical line from (70,100) to (70, 250)
plt.plot([70, 70], [100, 250], 'k-', lw=2)

# draw diagonal line from (70, 90) to (90, 200)
plt.plot([70, 90], [90, 200], 'k-')

plt.show()

neues Diagramm

gcalmettes
quelle
tolle Antwort mit ausgezeichneten und vollständigen Abbildungen! vielen, vielen Dank!
JD Long
2
Kleinere Korrekturen, der obige Code sollte lauten x = np.arange(1, 101).
WP McNeill
Dadurch wird keine Linie gezeichnet, sondern nur ein Segment. Die Frage, wie man eine Linie mit zwei gegebenen Punkten zieht, bleibt unbeantwortet.
Alexey
6
@Rmano Sie können vermeiden, dass die Segmente in der Legende berücksichtigt werden, indem Sie ein Beschriftungsargument hinzufügen, das mit "_" beginnt. Beispiel:plt.plot([70, 70], [100, 250], 'k-', lw=2, label="_not in legend")
gcalmettes
1
Die Tatsache, dass 90sowohl als x2als auch verwendet wird, y1führt zu viel Unklarheit. Beachten Sie beim Anzeigen, dass sich [70, 90]dies nicht auf einen einzelnen Punkt am Standort bezieht x1,y1. Als Referenz sind hier die Bedeutungen der Werte:[x1: 70, x2: 90], [y1: 90, y2: 200]
Pookie
61

Für die Neuankömmlinge ist es noch nicht zu spät .

plt.axvline(x, color='r')

Mit ymin und ymax wird auch der Bereich von y angenommen.

Lebenslogger
quelle
1
Die Min / Max-Parameter von Axhline und Axvline sind Skalarwerte zwischen 0 und 1, die Linien in Bezug auf die Plotkante zeichnen. Obwohl es ein gutes Werkzeug ist, ist es wahrscheinlich nicht die beste Lösung für die Problemstellung des Autors beim Zeichnen von Anmerkungslinien.
Binarysubstrate
3
Dies ist ideal, um im Hintergrund eine Anmerkungslinie hinzuzufügen, die sich über das gesamte Diagramm erstreckt. Wenn ich die oben gewählte Lösung verwende, um eine vertikale Linie bei x = 1 zu zeichnen, muss ich das min und max y angeben, und dann wird die Größe des Diagramms automatisch mit einem Puffer geändert, damit sich die Linie nicht über das gesamte Diagramm erstreckt, und Das ist ein Ärger. Dies ist eleganter und ändert die Größe des Grundstücks nicht.
Bonnie
40

Verwenden von vlines:

import numpy as np
np.random.seed(5)
x = arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
p =  plot(x, y, "o")
vlines(70,100,250)

Die grundlegenden Anrufsignaturen sind:

vlines(x, ymin, ymax)
hlines(y, xmin, xmax)
Austin Richardson
quelle
2
das ist exzellent. Ich hatte die vline()oder hline()Funktionen nicht gesehen . Was ist mit diagonalen Linien? Ich habe die Frage bearbeitet, um das diagonale Bit hinzuzufügen, nachdem Sie mir die H & V-Linien gezeigt haben.
JD Long
Versuchen Sie DataFrame, die x, y-Koordinaten zu enthalten und sie mitstyle='k-'
Austin Richardson
Vielen Dank, das ist sehr praktisch
Alex
6

Matplolib erlaubt jetzt "Anmerkungszeilen", wie das OP gesucht hat. Die annotate()Funktion ermöglicht verschiedene Arten von Verbindungspfaden, und ein kopfloser und schwanzloser Pfeil, dh eine einfache Linie, ist eine davon.

ax.annotate("",
            xy=(0.2, 0.2), xycoords='data',
            xytext=(0.8, 0.8), textcoords='data',
            arrowprops=dict(arrowstyle="-",
                      connectionstyle="arc3, rad=0"),
            )

In der Dokumentation heißt es, dass Sie nur einen Pfeil mit einer leeren Zeichenfolge als erstes Argument zeichnen können.

Aus dem Beispiel des OP:

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(5)
x = np.arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
plt.plot(x, y, "o")


# draw vertical line from (70,100) to (70, 250)
plt.annotate("",
              xy=(70, 100), xycoords='data',
              xytext=(70, 250), textcoords='data',
              arrowprops=dict(arrowstyle="-",
                              connectionstyle="arc3,rad=0."), 
              )

# draw diagonal line from (70, 90) to (90, 200)
plt.annotate("",
              xy=(70, 90), xycoords='data',
              xytext=(90, 200), textcoords='data',
              arrowprops=dict(arrowstyle="-",
                              connectionstyle="arc3,rad=0."), 
              )

plt.show()

Beispiel für ein Inline-Bild

Genau wie beim Ansatz in der Antwort von gcalmettes können Sie die Farbe, die Linienbreite, den Linienstil usw. auswählen.

Hier ist eine Änderung an einem Teil des Codes, durch die eine der beiden Beispielzeilen rot, breiter und nicht 100% undurchsichtig wird.

# draw vertical line from (70,100) to (70, 250)
plt.annotate("",
              xy=(70, 100), xycoords='data',
              xytext=(70, 250), textcoords='data',
              arrowprops=dict(arrowstyle="-",
                              edgecolor = "red",
                              linewidth=5,
                              alpha=0.65,
                              connectionstyle="arc3,rad=0."), 
              )

Sie können der Verbindungslinie auch eine Kurve hinzufügen, indem Sie die connectionstyle.

Wayne
quelle
1
Das brauchte ich letztendlich. Ich wollte eine Linie ziehen, die über die Grenzen der Handlung hinausgeht, was .plot()nicht geht.
Nick S
4

Anstatt zu missbrauchen plotoder annotate, was für viele Zeilen ineffizient sein wird, können Sie Folgendes verwenden matplotlib.collections.LineCollection:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection

np.random.seed(5)
x = np.arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
plt.plot(x, y, "o")

# Takes list of lines, where each line is a sequence of coordinates
l1 = [(70, 100), (70, 250)]
l2 = [(70, 90), (90, 200)]
lc = LineCollection([l1, l2], color=["k","blue"], lw=2)

plt.gca().add_collection(lc)

plt.show()

Abbildung mit zwei über LineCollection gezeichneten Linien

Es wird eine Liste von Zeilen erstellt [l1, l2, ...], wobei jede Zeile eine Folge von N Koordinaten ist ( N kann mehr als zwei sein).

Die Standardformatierungsschlüsselwörter sind verfügbar und akzeptieren entweder einen einzelnen Wert. In diesem Fall gilt der Wert für jede Zeile oder eine Folge von M. values In diesem Fall ist der Wert für die i- te Zeile values[i % M].

Qualia
quelle