Python: Crearea unei histograme 2D dintr-o matrice numpy (Programare, Python, Numpy, Matrix, Matplotlib, Histogramă)

Kestrel a intrebat.

Sunt nou în python.

Am o matrice numpy, de dimensiuni 42×42, cu valori în intervalul 0-996. Vreau să creez o histogramă 2D folosind aceste date. M-am uitat la tutoriale, dar toate par să arate cum se creează histograme 2D din date aleatorii și nu dintr-o matrice numpy.

Până acum, am importat:

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

Nu sunt sigur dacă acestea sunt importuri corecte, încerc doar să preiau ce pot din tutoriale pe care le văd.

Am matricea numpy M cu toate valorile din ea (așa cum am descris mai sus). În final, vreau să arate cam așa:

evident, datele mele vor fi diferite, așa că graficul meu ar trebui să arate diferit. Poate cineva să mă ajute?

Editați: Pentru scopurile mele, Hooked‘s de mai jos, folosind matshow, este exact ceea ce caut.

Comentarii

  • care este x și y în matricea numpy, este practic 42 de rânduri și 42 de coloane. care sunt valorile x, y? –  > Por Kirubaharan J.
  • Da, matricea mea are 42 de rânduri și 42 de coloane. În fiecare index, există un număr întreg de la 0-996 care a fost calculat și plasat acolo mai devreme în program. –  > Por Kestrel.
4 răspunsuri
Hooked

Dacă aveți datele brute de la numărători, ați putea folosi plt.hexbin pentru a crea diagramele pentru dvs. (IMHO acest lucru este mai bun decât o rețea pătrată): Adaptat din exemplul de 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()

Dacă aveți deja valorile Z într-o matrice, așa cum ați menționat, utilizați doar plt.imshow sau 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')

Comentarii

  • matshow este exact ceea ce caut. Vă mulțumesc foarte mult! –  > Por Kestrel.
  • Pentru ca axele să fie etichetate corect, puteți trece extent la imshow cu valorile min și max ale marginilor bin. –  > Por Jim Hunziker.
unutbu

Dacă aveți nu numai matricea histogramei 2D, ci și matricea de bază a histogramei (x, y) datele, atunci puteți realiza o diagramă de dispersie a (x, y) puncte și să colorați fiecare punct în funcție de valoarea de numărare binată a acestuia în matricea histogramei 2D:

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()

TheoryX

Răspunsul lui @unutbu conține o greșeală: xidx și yidx sunt calculate în mod greșit (cel puțin pe eșantionul meu de date). Modul corect ar trebui să fie:

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)

Deoarece dimensiunea de randament a np.digitize care ne interesează este cuprinsă între 1 și len(xedges) - 1, , dar dimensiunea c = hist[xidx, yidx] are nevoie de indici între 0 și hist.shape - 1.


Mai jos este prezentată comparația rezultatelor. După cum puteți vedea, obțineți un rezultat similar, dar nu același.

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()

Comentarii

  • Atunci când postați un răspuns asigurați-vă că răspunsul dvs. nu se bazează pe informații date în alte răspunsuri. Ați descris corect problema într-un alt răspuns (ceea ce este un lucru bun de făcut), dar apoi ați oferit doar o soluție parțială care nu poate fi folosită fără a consulta celălalt răspuns. Vă rugăm să vă adresați la editați răspunsul dvs. și includeți un fragment complet, altfel mesajul dvs. va fi probabil șters. –  > Por Noel Widmer.
farenorth

Sunt un mare fan al „histogramei de împrăștiere”, dar nu cred că celelalte soluții le fac pe deplin dreptate. Iată o funcție care le implementează. Avantajul major al acestei funcții în comparație cu celelalte soluții este că sortează punctele în funcție de datele hist (a se vedea mode argument). Acest lucru înseamnă că rezultatul seamănă mai mult cu o histogramă tradițională (adică nu se obține suprapunerea haotică a markerilor în diferite bins).

MCVE pentru această figură (utilizând funcția mea):

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)

Mai este loc pentru îmbunătățiri?

Principalul dezavantaj al acestei abordări este că punctele din zonele cele mai dense se suprapun peste punctele din zonele cu densitate mai mică, ceea ce duce la o oarecare reprezentare eronată a zonelor din fiecare bin. Am petrecut destul de mult timp explorând două abordări pentru rezolvarea acestui aspect:

1) utilizarea unor markeri mai mici pentru bini de densitate mai mare.

2) aplicarea unei măști de „decupare” pentru fiecare bin.

Prima variantă oferă rezultate care sunt mult prea nebunești. Cea de-a doua arată bine – mai ales dacă decupați doar bins care au >~20 de puncte – dar este extrem de lent (această figură a durat aproximativ un minut).

Deci, în cele din urmă am decis că prin selectarea cu atenție a dimensiunii markerului și a dimensiunii bin (s și bins), se pot obține rezultate care sunt plăcute din punct de vedere vizual și care nu sunt prea rele în ceea ce privește denaturarea datelor. La urma urmei, aceste histograme 2D sunt, de obicei, menite să fie ajutoare vizuale pentru datele de bază, nu reprezentări strict cantitative ale acestora. Prin urmare, cred că această abordare este mult superioară „histogramelor 2D tradiționale” (de ex, plt.hist2d sau plt.hexbin), și presupun că, dacă ați găsit această pagină, nici dumneavoastră nu sunteți un fan al diagramelor de dispersie tradiționale (cu o singură culoare).

Dacă aș fi regele științei, m-aș asigura că toate histogramele 2D fac ceva de genul acesta pentru tot restul veacurilor.