Beschriften Sie Python-Datenpunkte auf dem Plot

78

Ich habe nach Alter gesucht (Stunden, die wie Alter sind), um die Antwort auf ein wirklich nerviges (scheinbar grundlegendes) Problem zu finden, und weil ich keine Frage finde, die ganz zur Antwort passt, poste ich eine Frage und beantworte sie in der Hoffnung, dass sie es ist spart jemand anderem die enorme Zeit, die ich gerade für meine Noobie-Plot-Fähigkeiten aufgewendet habe.

Wenn Sie Ihre Plotpunkte mit Python Matplotlib beschriften möchten

from matplotlib import pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

A = anyarray
B = anyotherarray

plt.plot(A,B)
for i,j in zip(A,B):
    ax.annotate('%s)' %j, xy=(i,j), xytext=(30,0), textcoords='offset points')
    ax.annotate('(%s,' %i, xy=(i,j))

plt.grid()
plt.show()

Ich weiß, dass xytext = (30,0) mit den Textkoordinaten einhergeht. Sie verwenden diese 30,0-Werte, um den Datenbeschriftungspunkt so zu positionieren, dass er auf der 0 y-Achse und 30 auf der x-Achse auf seiner eigenen kleinen Fläche liegt.

Sie benötigen beide Linien, die i und j darstellen, andernfalls zeichnen Sie nur die x- oder y-Datenbeschriftung.

Sie erhalten so etwas heraus (beachten Sie nur die Etiketten):
Mein eigenes Grundstück mit beschrifteten Datenpunkten

Es ist nicht ideal, es gibt immer noch einige Überlappungen - aber es ist besser als nichts, was ich hatte.

Ashley
quelle
1
Warum nicht einfach tun ax.annotate('(%s, %s)' % (i, j), ...)? (Oder wenn Sie die neuere Zeichenfolgenformatierung verwenden , '({}, {})'.format(i, j).)
Joe Kington
1
Lassen
Sie
pyplot.text scheint eine Alternative zum Kommentieren zu sein: pythonmembers.club/2018/05/08/… Ich bin mir nicht sicher, ob es etwas anderes macht
10762409 sagt Reinstate Monica
Betreuer von pythonmembers.club hier. XD das hat mich als Anfänger verärgert. Dieser Artikel wurde populär genug, um in den NLP-Kurs der Stanford University aufgenommen zu werden (yaps ein kühner direkter Link zum Artikel)
Abdur-Rahmaan Janhangeer

Antworten:

93

Wie wäre es (x, y)mit sofort drucken .

from matplotlib import pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

A = -0.75, -0.25, 0, 0.25, 0.5, 0.75, 1.0
B = 0.73, 0.97, 1.0, 0.97, 0.88, 0.73, 0.54

plt.plot(A,B)
for xy in zip(A, B):                                       # <--
    ax.annotate('(%s, %s)' % xy, xy=xy, textcoords='data') # <--

plt.grid()
plt.show()

Geben Sie hier die Bildbeschreibung ein

falsetru
quelle
4
Nur eine Anmerkung für alle, die dies verwenden: textcoords = 'Versatzpunkte' scheint je nach Maßstab des Diagramms einen variablen Effekt zu haben (für mich führte dies dazu, dass die meisten Beschriftungen außerhalb des Diagramms angezeigt wurden)
Eric G
1
Ja, Sie sollten stattdessen textcoords = 'data' verwenden.
Navari
@navari, Danke für die Information. Ich habe die Antwort entsprechend aktualisiert.
Falsetru
@EricG - Ich glaube, das textcoords='offset points'erfordert auch den xytextParameter. Mit anderen Worten, stellen Sie xytext=(x points, y points)den Offset ein und textcoords='offset points'es funktioniert wie erwartet.
DaveL17
2
Angenommen, Sie haben eine Million dreidimensionaler Datenpunkte. Sie müssen einige davon auswählen und einzeln beschriften. Wie würdest du das machen?
Juni Wang
5

Ich hatte ein ähnliches Problem und endete mit folgendem:

Geben Sie hier die Bildbeschreibung ein

Für mich hat dies den Vorteil, dass sich Daten und Anmerkungen nicht überschneiden.

from matplotlib import pyplot as plt
import numpy as np

fig = plt.figure()
ax = fig.add_subplot(111)

A = -0.75, -0.25, 0, 0.25, 0.5, 0.75, 1.0
B = 0.73, 0.97, 1.0, 0.97, 0.88, 0.73, 0.54

plt.plot(A,B)

# annotations at the side (ordered by B values)
x0,x1=ax.get_xlim()
y0,y1=ax.get_ylim()
for ii, ind in enumerate(np.argsort(B)):
    x = A[ind]
    y = B[ind]
    xPos = x1 + .02 * (x1 - x0)
    yPos = y0 + ii * (y1 - y0)/(len(B) - 1)
    ax.annotate('',#label,
          xy=(x, y), xycoords='data',
          xytext=(xPos, yPos), textcoords='data',
          arrowprops=dict(
                          connectionstyle="arc3,rad=0.",
                          shrinkA=0, shrinkB=10,
                          arrowstyle= '-|>', ls= '-', linewidth=2
                          ),
          va='bottom', ha='left', zorder=19
          )
    ax.text(xPos + .01 * (x1 - x0), yPos,
            '({:.2f}, {:.2f})'.format(x,y),
            transform=ax.transData, va='center')

plt.grid()
plt.show()

Die Verwendung des Textarguments in .annotateführte zu ungünstigen Textpositionen. Das Zeichnen von Linien zwischen einer Legende und den Datenpunkten ist ein Chaos, da der Ort der Legende schwer zu adressieren ist.

Markus Dutschke
quelle