Ich habe eine Reihe von X- und Y-Datenpunkten (ca. 10.000), die sich leicht als Streudiagramm darstellen lassen, die ich aber gerne als Heatmap darstellen möchte.
Ich habe die Beispiele in MatPlotLib durchgesehen und sie scheinen alle bereits mit Heatmap-Zellenwerten zu beginnen, um das Bild zu generieren.
Gibt es eine Methode, die eine Reihe von x, y, die alle unterschiedlich sind, in eine Heatmap konvertiert (wobei Zonen mit einer höheren Frequenz von x, y "wärmer" wären)?
Antworten:
Wenn Sie keine Sechsecke möchten, können Sie die
histogram2d
Funktion von numpy verwenden:Dies ergibt eine 50x50 Heatmap. Wenn Sie beispielsweise 512 x 384 möchten, können Sie
bins=(512, 384)
den Anruf bei tätigenhistogram2d
.Beispiel:
quelle
axes
Instanz zu verstehen, in der ich einen Titel, Achsenbeschriftungen usw. hinzufügen und dann das Normale tun kann,savefig()
wie ich es für jedes andere typische Matplotlib-Diagramm tun würde.plt.savefig('filename.png')
? Wenn Sie einefig = plt.figure()
ax = fig.gca()
ax.imshow(...)
fig.savefig(...)
imshow()
es sich um dieselbe Funktionskategorie handelt wiescatter()
. Ich verstehe ehrlich gesagt nicht, warumimshow()
ein 2D-Array von Floats in Blöcke geeigneter Farbe konvertiert wird, während ich verstehe, wasscatter()
mit einem solchen Array zu tun ist.plt.imshow(heatmap.T, extent=extent, origin = 'lower')
from matplotlib.colors import LogNorm
plt.imshow(heatmap, norm=LogNorm())
plt.colorbar()
Im Matplotlib- Lexikon möchten Sie einen Hexbin- Plot.
Wenn Sie mit dieser Art von Plot nicht vertraut sind, handelt es sich nur um ein bivariates Histogramm, bei dem die xy-Ebene durch ein regelmäßiges Sechseckgitter tesselliert wird.
Aus einem Histogramm können Sie also einfach die Anzahl der Punkte zählen, die in jedes Sechseck fallen, den Plotbereich als eine Reihe von Fenstern diskretisieren und jeden Punkt einem dieser Fenster zuweisen. Schließlich ordnen Sie die Fenster auf ein Farbarray , und Sie haben ein hexbin Diagramm bekam.
Obwohl Sechsecke weniger häufig verwendet werden als z. B. Kreise oder Quadrate, ist es eine intuitive Wahl für die Geometrie des Binning-Containers:
Sechsecke haben Symmetrie zum nächsten Nachbarn (z. B. sind quadratische Bins nicht, z. B. ist der Abstand von einem Punkt an der Grenze eines Quadrats zu einem Punkt innerhalb dieses Quadrats nicht überall gleich) und
Sechseck ist das höchste n-Polygon, das eine regelmäßige ebene Tessellation ergibt (dh Sie können Ihren Küchenboden mit sechseckigen Fliesen sicher neu modellieren, da Sie nach Fertigstellung keinen Hohlraum zwischen den Fliesen haben - nicht wahr alle anderen höheren n, n> = 7, Polygone).
( Matplotlib verwendet den Begriff hexbin Grundstück; so tun (AFAIK) alle der Plotten Bibliotheken für R , noch ich weiß nicht , ob dies die allgemein akzeptierte Bezeichnung für Grundstücke dieser Art ist, obwohl ich es wahrscheinlich gegeben vermuten , dass hexbin kurz ist für hexagonales Binning , das den wesentlichen Schritt bei der Vorbereitung der Daten für die Anzeige beschreibt.)
quelle
gridsize=
Parameter aus ? Ich würde es gerne so wählen, dass sich die Sechsecke einfach berühren, ohne sich zu überlappen. Mir ist aufgefallen, dass dadurchgridsize=100
kleinere Sechsecke entstehen würden, aber wie wählt man den richtigen Wert?Bearbeiten: Für eine bessere Annäherung an Alejandros Antwort siehe unten.
Ich weiß, dass dies eine alte Frage ist, wollte aber Alejandros Antwort etwas hinzufügen: Wenn Sie ein schönes geglättetes Bild ohne Verwendung von py-sphviewer wünschen, können Sie stattdessen
np.histogram2d
einen Gauß-Filter (vonscipy.ndimage.filters
) verwenden und auf die Heatmap anwenden :Produziert:
Das Streudiagramm und s = 16 sind für Agape Gal'lo übereinander aufgetragen (zur besseren Ansicht klicken):
Ein Unterschied, den ich bei meinem Gaußschen Filteransatz und Alejandros Ansatz bemerkte, war, dass seine Methode lokale Strukturen viel besser zeigt als meine. Daher habe ich eine einfache Methode für den nächsten Nachbarn auf Pixelebene implementiert. Diese Methode berechnet für jedes Pixel die inverse Summe der Abstände der
n
nächstgelegenen Punkte in den Daten. Diese Methode ist mit einer hohen Auflösung ziemlich rechenintensiv und ich denke, es gibt einen schnelleren Weg. Lassen Sie mich wissen, wenn Sie Verbesserungen haben.Update: Wie ich vermutet habe, gibt es eine viel schnellere Methode mit Scipy's
scipy.cKDTree
. Siehe Gabriels Antwort für die Implementierung.Wie auch immer, hier ist mein Code:
Ergebnis:
quelle
myplot
Fügen Sie in der Funktion denrange
Parameter hinzu zunp.histogram2d
:np.histogram2d(x, y, bins=bins, range=[[-5, 5], [-3, 4]])
und stellen Sie in der for-Schleife die x- und y-Grenze der Achse ein :ax.set_xlim([-5, 5])
ax.set_ylim([-3, 4])
. Darüber hinaus standardmäßigimshow
das Seitenverhältnis identisch mit dem Verhältnis Ihrer Achsen hält (so in meinem Beispiel ein Verhältnis von 10: 7), aber wenn Sie wollen , dass es Ihren Plotfenster anzupassen, fügen Sie den Parameteraspect='auto'
aufimshow
.Anstatt np.hist2d zu verwenden, das im Allgemeinen ziemlich hässliche Histogramme erzeugt, möchte ich py-sphviewer recyceln , ein Python-Paket zum Rendern von Partikelsimulationen mit einem adaptiven Glättungskern, das einfach über pip installiert werden kann (siehe Webseiten-Dokumentation). Betrachten Sie den folgenden Code, der auf dem Beispiel basiert:
welches das folgende Bild erzeugt:
Wie Sie sehen, sehen die Bilder ziemlich gut aus, und wir können verschiedene Unterstrukturen darauf identifizieren. Diese Bilder werden so konstruiert, dass sie für jeden Punkt innerhalb eines bestimmten Bereichs ein bestimmtes Gewicht verteilen, das durch die Glättungslänge definiert wird, die wiederum durch den Abstand zum näheren nb- Nachbarn gegeben ist (ich habe für die Beispiele 16, 32 und 64 gewählt). Daher sind Regionen mit höherer Dichte im Vergleich zu Regionen mit niedrigerer Dichte typischerweise über kleinere Regionen verteilt.
Die Funktion myplot ist nur eine sehr einfache Funktion, die ich geschrieben habe, um py-sphviewer die x, y-Daten zu geben, um die Magie auszuführen.
quelle
Wenn Sie 1.2.x verwenden
quelle
Seaborn hat jetzt die Joint-Plot-Funktion, die hier gut funktionieren sollte:
quelle
fig = plt.figure(figsize=(12, 12))
, erhalten Sie dann die aktuelle Achse mitax=plt.gca()
und fügen Sie dann das Argumentax=ax
zurjointplot
Funktion hinzu.und die erste Frage war ... wie man Streuwerte in Gitterwerte umwandelt, richtig?
histogram2d
zählt jedoch die Häufigkeit pro Zelle. Wenn Sie jedoch andere Daten pro Zelle als nur die Häufigkeit haben, müssen Sie einige zusätzliche Arbeiten ausführen.Ich habe also einen Datensatz mit Z-Ergebnissen für X- und Y-Koordinaten. Ich berechnete jedoch nur wenige Punkte außerhalb des interessierenden Bereichs (große Lücken) und jede Menge Punkte in einem kleinen interessierenden Bereich.
Ja hier wird es schwieriger, aber auch lustiger. Einige Bibliotheken (sorry):
Pyplot ist heute meine Grafik-Engine. cm ist eine Reihe von Farbkarten mit einer interessanten Auswahl. numpy für die Berechnungen und griddata zum Anhängen von Werten an ein festes Gitter.
Letzteres ist besonders wichtig, weil die Häufigkeit von xy-Punkten in meinen Daten nicht gleichmäßig verteilt ist. Beginnen wir zunächst mit einigen Grenzen, die zu meinen Daten passen, und einer beliebigen Rastergröße. Die Originaldaten haben Datenpunkte auch außerhalb dieser x- und y-Grenzen.
Wir haben also ein Raster mit 500 Pixeln zwischen den Min- und Max-Werten von x und y definiert.
In meinen Daten sind viel mehr als die 500 Werte im Bereich von hohem Interesse verfügbar; in der Erwägung, dass es im Niedrigzinsbereich nicht einmal 200 Werte im Gesamtnetz gibt; zwischen den grafischen Grenzen von
x_min
undx_max
gibt es noch weniger.Um ein schönes Bild zu erhalten, besteht die Aufgabe darin, einen Durchschnitt für die hohen Zinswerte zu erhalten und die Lücken an anderer Stelle zu schließen.
Ich definiere jetzt mein Raster. Für jedes xx-yy Paar möchte ich eine Farbe haben.
Warum die seltsame Form? scipy.griddata möchte eine Form von (n, D).
Griddata berechnet einen Wert pro Punkt im Raster nach einer vordefinierten Methode. Ich wähle "am nächsten" - leere Gitterpunkte werden mit Werten des nächsten Nachbarn gefüllt. Dies sieht so aus, als hätten die Bereiche mit weniger Informationen größere Zellen (auch wenn dies nicht der Fall ist). Man könnte wählen, "linear" zu interpolieren, dann sehen Bereiche mit weniger Informationen weniger scharf aus. Geschmackssache, wirklich.
Und hüpfen, wir übergeben an matplotlib, um die Handlung anzuzeigen
Um den spitzen Teil der V-Form herum haben Sie bei meiner Suche nach dem Sweet Spot viele Berechnungen durchgeführt, während die weniger interessanten Teile fast überall eine niedrigere Auflösung haben.
quelle
Hier ist Jurgys Ansatz für den nächsten Nachbarn, der jedoch mit scipy.cKDTree implementiert wurde . In meinen Tests ist es ungefähr 100x schneller.
quelle
Erstellen Sie ein zweidimensionales Array, das den Zellen in Ihrem endgültigen Bild entspricht
heatmap_cells
und instanziieren Sie es als alle Nullen.Wählen Sie zwei Skalierungsfaktoren aus, die den Unterschied zwischen jedem Array-Element in realen Einheiten für jede Dimension definieren, z. B.
x_scale
undy_scale
. . Wählen Sie diese so aus, dass alle Ihre Datenpunkte innerhalb der Grenzen des Heatmap-Arrays liegen.Für jeden Rohdatenpunkt mit
x_value
undy_value
:heatmap_cells[floor(x_value/x_scale),floor(y_value/y_scale)]+=1
quelle
Hier ist eine, die ich mit einem 1-Millionen-Punkte-Set mit 3 Kategorien (rot, grün und blau) erstellt habe. Hier ist ein Link zum Repository, wenn Sie die Funktion ausprobieren möchten. Github Repo
quelle
Sehr ähnlich der Antwort von @ Piti , aber mit 1 Anruf anstelle von 2, um die Punkte zu generieren:
Ausgabe:
quelle
Ich fürchte, ich bin etwas spät zur Party, aber ich hatte vor einiger Zeit eine ähnliche Frage. Die akzeptierte Antwort (von @ptomato) hat mir geholfen, aber ich möchte sie auch posten, falls sie für jemanden von Nutzen ist.
Hier ist das Ergebnis
quelle