web-dev-qa-db-de.com

Python: Erstellen eines 2D-Histogramms aus einer numpy-Matrix

Ich bin neu im Python.

Ich habe eine numpy-Matrix mit den Abmessungen 42x42 und Werten im Bereich von 0-996. Ich möchte mit diesen Daten ein 2D-Histogramm erstellen. Ich habe mir Tutorials angesehen, aber alle scheinen zu zeigen, wie man 2D-Histogramme aus zufälligen Daten und nicht aus einer numpy-Matrix erstellt.

Bisher habe ich importiert:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors

Ich bin mir nicht sicher, ob es sich um korrekte Importe handelt. Ich versuche nur, aus den Tutorials, die ich sehe, herauszufinden, was ich kann.

Ich habe die numpy-Matrix M mit allen darin enthaltenen Werten (wie oben beschrieben). Am Ende möchte ich, dass es ungefähr so ​​aussieht:

2D histogram

natürlich werden meine Daten anders sein, daher sollte mein Plot anders aussehen. Kann mir jemand eine Hand geben?

Edit: Für meine Zwecke ist Hooked s Beispiel unten mit Matshow genau das, was ich suche.

12
Kestrel

Wenn Sie die Rohdaten aus den Zählungen haben, können Sie plt.hexbin verwenden, um die Diagramme für Sie zu erstellen (IMHO ist dies besser als ein quadratisches Gitter): Angepasst an das Beispiel hexbin

import numpy as np
import matplotlib.pyplot as plt

n = 100000
x = np.random.standard_normal(n)
y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
plt.hexbin(x,y)

plt.show()

enter image description here

Wenn Sie bereits die Z-Werte in einer Matrix haben, verwenden Sie einfach plt.imshow oder plt.matshow:

XB = np.linspace(-1,1,20)
YB = np.linspace(-1,1,20)
X,Y = np.meshgrid(XB,YB)
Z = np.exp(-(X**2+Y**2))
plt.imshow(Z,interpolation='none')

enter image description here

20
Hooked

Wenn Sie nicht nur über die 2D-Histogrammmatrix verfügen, sondern auch über die zugrunde liegenden (x, y)-Daten, können Sie ein Streudiagramm der (x, y)-Punkte erstellen und jeden Punkt gemäß seinem Zählwert in der 2D-Histogrammmatrix farbig markieren:

import numpy as np
import matplotlib.pyplot as plt

n = 10000
x = np.random.standard_normal(n)
y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
xedges, yedges = np.linspace(-4, 4, 42), np.linspace(-25, 25, 42)
hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges))
xidx = np.clip(np.digitize(x, xedges), 0, hist.shape[0]-1)
yidx = np.clip(np.digitize(y, yedges), 0, hist.shape[1]-1)
c = hist[xidx, yidx]
plt.scatter(x, y, c=c)

plt.show()

Example scatter plot of 2D histogram

12
unutbu

@ unutbu's answer enthält einen Fehler: xidx und yidx werden falsch berechnet (zumindest in meinem Datenmuster). Der richtige Weg sollte sein:

xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1)
yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1)

Die Rückgabedimension von np.digitize, die uns interessiert, liegt zwischen 1 und len(xedges) - 1, aber der c = hist[xidx, yidx] benötigt Indizes zwischen 0 und hist.shape - 1.


Unten ist der Vergleich der Ergebnisse. Wie Sie sehen, erhalten Sie ein ähnliches Ergebnis.

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

n = 10000
x = np.random.standard_normal(n)
y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
xedges, yedges = np.linspace(-4, 4, 42), np.linspace(-25, 25, 42)
hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges))

xidx = np.clip(np.digitize(x, xedges), 0, hist.shape[0] - 1)
yidx = np.clip(np.digitize(y, yedges), 0, hist.shape[1] - 1)
c = hist[xidx, yidx]
old = ax1.scatter(x, y, c=c, cmap='jet')

xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1)
yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1)

c = hist[xidx, yidx]
new = ax2.scatter(x, y, c=c, cmap='jet')


plt.show()

 Same Same but Different

1
TheoryX

Ich bin ein großer Fan des "Scatter-Histogramms", aber ich glaube nicht, dass die anderen Lösungen ihnen voll und ganz gerecht werden. Hier ist eine Funktion , die sie implementiert. Der Hauptvorteil dieser Funktion im Vergleich zu anderen Lösungen besteht darin, dass die Punkte nach den Hist-Daten sortiert werden (siehe das Argument mode). Dies bedeutet, dass das Ergebnis eher wie ein herkömmliches Histogramm aussieht (d. H., Sie erhalten nicht die chaotische Überlappung von Markern in verschiedenen Behältern) .  The scatter-histogram

MCVE für diese Figur (mit meiner Funktion ):

import numpy as np
import matplotlib.pyplot as plt
from hist_scatter import scatter_hist2d

fig = plt.figure(figsize=[5, 4])
ax = plt.gca()

x = randgen.randn(npoint)
y = 2 + 3 * x + 4 * randgen.randn(npoint)

scat = scatter_hist2d(x, y,
                      bins=[np.linspace(-4, 4, 42),
                            np.linspace(-25, 25, 42)],
                      s=5,
                      cmap=plt.get_cmap('viridis'))
ax.axhline(0, color='k', linestyle='--', zorder=3, linewidth=0.5)
ax.axvline(0, color='k', linestyle='--', zorder=3, linewidth=0.5)
plt.colorbar(scat)

Raum für Verbesserung?

Der Hauptnachteil dieses Ansatzes besteht darin, dass die Punkte in den dichtesten Bereichen die Punkte in Bereichen mit geringerer Dichte überlappen, was zu einer falschen Darstellung der Bereiche jedes Fachs führt. Ich habe ziemlich viel Zeit damit verbracht, zwei Lösungsansätze zu untersuchen:

1) Verwenden kleinerer Marker für Behälter mit höherer Dichte

2) Anbringen einer 'Schnittmaske' an jedem Behälter

Die erste gibt Ergebnisse die sind viel zu verrückt. Die zweite sieht nett aus - vor allem, wenn Sie nur Behälter mit ~ 20 Punkten ausschneiden - aber es ist extrem langsam ( diese Zahl dauerte etwa eine Minute).

Also habe ich letztendlich entschieden, dass durch sorgfältige Auswahl der Markergröße und der Bin-Größe (s und bins) Ergebnisse erzielt werden können, die optisch ansprechend sind und hinsichtlich der falschen Darstellung der Daten nicht zu schlecht sind. Schließlich sind diese 2D-Histogramme in der Regel als visuelle Hilfsmittel für die zugrunde liegenden Daten gedacht, nicht als strikte quantitative Darstellungen. Daher denke ich, dass dieser Ansatz "traditionellen 2D-Histogrammen" (z. B. plt.hist2d oder plt.hexbin) weit überlegen ist, und ich gehe davon aus, dass Sie, wenn Sie diese Seite gefunden haben, auch kein Fan traditioneller (einfarbiger) Streudiagramme sind.

Wenn ich ein König der Wissenschaft wäre, würde ich sicherstellen, dass alle 2D-Histogramme für den Rest der Ewigkeit so etwas tun.

0
farenorth