Generare una mappa di calore in MatPlotLib utilizzando un set di dati scatter


187

Ho una serie di punti dati X, Y (circa 10k) che sono facili da tracciare come un diagramma a dispersione ma che vorrei rappresentare come una mappa di calore.

Ho esaminato gli esempi in MatPlotLib e tutti sembrano già iniziare con i valori delle celle della mappa di calore per generare l'immagine.

Esiste un metodo che converte un gruppo di x, y, tutti diversi, in una mappa di calore (dove le zone con una frequenza maggiore di x, y sarebbero "più calde")?


Risposte:


182

Se non vuoi esagoni, puoi usare la histogram2dfunzione numpy :

import numpy as np
import numpy.random
import matplotlib.pyplot as plt

# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)

heatmap, xedges, yedges = np.histogram2d(x, y, bins=50)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]

plt.clf()
plt.imshow(heatmap.T, extent=extent, origin='lower')
plt.show()

Questo crea una mappa di calore 50x50. Se vuoi, diciamo, 512x384, puoi effettuare bins=(512, 384)la chiamata a histogram2d.

Esempio: Esempio di mappa termica di Matplotlib


1
Non intendo essere un idiota, ma come si fa effettivamente a produrre questo output in un file PNG / PDF invece di visualizzarlo solo in una sessione IPython interattiva? Sto cercando di ottenere questo come una sorta di axesistanza normale , in cui posso aggiungere un titolo, etichette degli assi, ecc. E quindi fare il normale savefig()come farei per qualsiasi altro grafico tipico di matplotlib.
gotgenes,

3
@gotgenes: non plt.savefig('filename.png')funziona? Se vuoi ottenere un'istanza di assi, usa l'interfaccia orientata agli oggetti di fig = plt.figure() ax = fig.gca() ax.imshow(...) fig.savefig(...)
Matplotlib

1
Grazie davvero! Immagino di non capire appieno che si imshow()trova nella stessa categoria di funzioni di scatter(). Onestamente non capisco perché imshow()converta una matrice 2d di float in blocchi di colore appropriato, mentre capisco cosa scatter()dovrebbe fare con una tale matrice.
gotgenes,

14
Un avvertimento sull'uso di imshow per la stampa di un istogramma 2D di valori x / y come questo: per impostazione predefinita, imshow traccia l'origine nell'angolo in alto a sinistra e traspone l'immagine. Quello che farei per ottenere lo stesso orientamento di un diagramma a dispersione èplt.imshow(heatmap.T, extent=extent, origin = 'lower')
Jamie,

7
Per coloro che desiderano fare una barra colorata logaritmica vedi questa domanda stackoverflow.com/questions/17201172/... e semplicemente farefrom matplotlib.colors import LogNorm plt.imshow(heatmap, norm=LogNorm()) plt.colorbar()
tommy.carstensen

109

Nel lessico di Matplotlib , penso che tu voglia un complotto di hexbin .

Se non hai familiarità con questo tipo di trama, è solo un istogramma bivariato in cui il piano xy è tassellato da una griglia regolare di esagoni.

Quindi da un istogramma, puoi semplicemente contare il numero di punti che cadono in ciascun esagono, discretizzare la regione di disegno come un insieme di finestre , assegnare ciascun punto a una di queste finestre; infine, mappa le finestre su un array di colori e hai un diagramma hexbin.

Sebbene meno comunemente usato, ad esempio, di cerchi o quadrati, gli esagoni sono una scelta migliore per la geometria del contenitore binning è intuitiva:

  • gli esagoni hanno una simmetria del vicino più vicino (ad esempio, i bidoni quadrati non, ad esempio, la distanza da un punto sul bordo di un quadrato a un punto all'interno di quel quadrato non è ovunque uguale) e

  • hexagon è il poligono n più alto che fornisce una tassellatura piana regolare (ad esempio, puoi rimodellare in sicurezza il pavimento della tua cucina con piastrelle di forma esagonale perché non avrai spazio vuoto tra le piastrelle quando hai finito - non è vero per tutti gli altri più alti-n, n> = 7, poligoni).

( Matplotlib usa il termine grafico hexbin ; così (AFAIK) tutte le librerie di stampa per R ; ancora non so se questo è il termine generalmente accettato per grafici di questo tipo, anche se sospetto che sia probabile che hexbin sia breve per il binning esagonale , che descrive il passaggio essenziale nella preparazione dei dati per la visualizzazione.)


from matplotlib import pyplot as PLT
from matplotlib import cm as CM
from matplotlib import mlab as ML
import numpy as NP

n = 1e5
x = y = NP.linspace(-5, 5, 100)
X, Y = NP.meshgrid(x, y)
Z1 = ML.bivariate_normal(X, Y, 2, 2, 0, 0)
Z2 = ML.bivariate_normal(X, Y, 4, 1, 1, 1)
ZD = Z2 - Z1
x = X.ravel()
y = Y.ravel()
z = ZD.ravel()
gridsize=30
PLT.subplot(111)

# if 'bins=None', then color of each hexagon corresponds directly to its count
# 'C' is optional--it maps values to x-y coordinates; if 'C' is None (default) then 
# the result is a pure 2D histogram 

PLT.hexbin(x, y, C=z, gridsize=gridsize, cmap=CM.jet, bins=None)
PLT.axis([x.min(), x.max(), y.min(), y.max()])

cb = PLT.colorbar()
cb.set_label('mean value')
PLT.show()   

inserisci qui la descrizione dell'immagine


Cosa significa che "gli esagoni hanno una simmetria del vicino più prossimo"? Dici che "la distanza da un punto sul bordo di un quadrato e un punto all'interno di quel quadrato non è ovunque uguale" ma distanza da cosa?
Jaan,

9
Per un esagono, la distanza dal centro a un vertice che unisce due lati è anche più lunga che dal centro al centro di un lato, solo il rapporto è più piccolo (2 / sqrt (3) ≈ 1,15 per esagono vs. sqrt (2) ≈ 1,41 per piazza). L'unica forma in cui la distanza dal centro ad ogni punto sul bordo è uguale è il cerchio.
Jaan,

5
@Jaan Per un esagono, ogni vicino è alla stessa distanza. Non ci sono problemi con 8-vicinato o 4-vicinato. Nessun vicino diagonale, solo un tipo di vicino.
Isarandi,

@doug Come si sceglie il gridsize=parametro. Vorrei sceglierlo in modo tale che gli esagoni si tocchino e non si sovrappongano. Ho notato che gridsize=100produrrebbe esagoni più piccoli, ma come scegliere il valore corretto?
Alexander Cska,

40

Modifica: per una migliore approssimazione della risposta di Alejandro, vedi sotto.

So che questa è una vecchia domanda, ma volevo aggiungere qualcosa alla risposta di Alejandro: se vuoi una bella immagine levigata senza usare py-sphviewer puoi invece usare np.histogram2de applicare un filtro gaussiano (da scipy.ndimage.filters) alla mappa di calore:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.ndimage.filters import gaussian_filter


def myplot(x, y, s, bins=1000):
    heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
    heatmap = gaussian_filter(heatmap, sigma=s)

    extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
    return heatmap.T, extent


fig, axs = plt.subplots(2, 2)

# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)

sigmas = [0, 16, 32, 64]

for ax, s in zip(axs.flatten(), sigmas):
    if s == 0:
        ax.plot(x, y, 'k.', markersize=5)
        ax.set_title("Scatter plot")
    else:
        img, extent = myplot(x, y, s)
        ax.imshow(img, extent=extent, origin='lower', cmap=cm.jet)
        ax.set_title("Smoothing with  $\sigma$ = %d" % s)

plt.show()

produce:

Immagini in uscita

Il diagramma a dispersione e s = 16 tracciati uno sopra l'altro per Agape Gal'lo (clicca per una visione migliore):

A vicenda


Una differenza che ho notato con il mio approccio al filtro gaussiano e l'approccio di Alejandro era che il suo metodo mostra strutture locali molto meglio del mio. Pertanto ho implementato un semplice metodo del vicino più vicino a livello di pixel. Questo metodo calcola per ogni pixel la somma inversa delle distanze dei npunti più vicini nei dati. Questo metodo è ad alta risoluzione piuttosto costoso dal punto di vista computazionale e penso che ci sia un modo più rapido, quindi fatemi sapere se avete qualche miglioramento.

Aggiornamento: Come sospettavo, c'è un metodo molto più veloce usando Scipy scipy.cKDTree. Vedi la risposta di Gabriel per l'implementazione.

Comunque, ecco il mio codice:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm


def data_coord2view_coord(p, vlen, pmin, pmax):
    dp = pmax - pmin
    dv = (p - pmin) / dp * vlen
    return dv


def nearest_neighbours(xs, ys, reso, n_neighbours):
    im = np.zeros([reso, reso])
    extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]

    xv = data_coord2view_coord(xs, reso, extent[0], extent[1])
    yv = data_coord2view_coord(ys, reso, extent[2], extent[3])
    for x in range(reso):
        for y in range(reso):
            xp = (xv - x)
            yp = (yv - y)

            d = np.sqrt(xp**2 + yp**2)

            im[y][x] = 1 / np.sum(d[np.argpartition(d.ravel(), n_neighbours)[:n_neighbours]])

    return im, extent


n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)
resolution = 250

fig, axes = plt.subplots(2, 2)

for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 64]):
    if neighbours == 0:
        ax.plot(xs, ys, 'k.', markersize=2)
        ax.set_aspect('equal')
        ax.set_title("Scatter Plot")
    else:
        im, extent = nearest_neighbours(xs, ys, resolution, neighbours)
        ax.imshow(im, origin='lower', extent=extent, cmap=cm.jet)
        ax.set_title("Smoothing over %d neighbours" % neighbours)
        ax.set_xlim(extent[0], extent[1])
        ax.set_ylim(extent[2], extent[3])
plt.show()

Risultato:

Smoothing Neighbor più vicino


1
Ama questo. Il grafico è bello come la risposta di Alejandro, ma non sono richiesti nuovi pacchetti.
Nathan Clement

Molto bella ! Ma si genera un offset con questo metodo. Puoi vederlo confrontando un normale grafico a dispersione con quello colorato. Potresti aggiungere qualcosa per correggerlo? O semplicemente per spostare il grafico di valori xey?
Agape Gal'lo,

1
Agape Gal'lo, cosa intendi con offset? Se li complotti uno sopra l'altro, corrispondono (vedi modifica del mio post). Forse sei rimandato perché l'ampiezza della dispersione non coincide esattamente con le altre tre.
Jurgy,

Grazie mille per aver tracciato il grafico solo per me! Ho capito il mio errore: avevo modificato la "misura" per definire i limiti xey. Ora capisco che ha modificato l'origine del grafico. Quindi, ho un'ultima domanda: come posso espandere i limiti del grafico, anche per un'area in cui non ci sono dati esistenti? Ad esempio, tra -5 a +5 per xey.
Agape Gal'lo,

1
Supponiamo che desideri che l'asse x passi da -5 a 5 e l'asse y da -3 a 4; in myplotfunzione, aggiungere il rangeparametro np.histogram2d: np.histogram2d(x, y, bins=bins, range=[[-5, 5], [-3, 4]])e nel ciclo for impostare la xey lim dell'asse: ax.set_xlim([-5, 5]) ax.set_ylim([-3, 4]). Inoltre, per impostazione predefinita, imshowmantiene le proporzioni identiche al rapporto degli assi (quindi nel mio esempio un rapporto di 10: 7), ma se si desidera che corrisponda alla finestra del diagramma, aggiungere il parametro aspect='auto'a imshow.
Jurgy,

31

Invece di usare np.hist2d, che in generale produce istogrammi abbastanza brutti, vorrei riciclare py-sphviewer , un pacchetto python per il rendering di simulazioni di particelle usando un kernel di smoothing adattivo e che può essere facilmente installato da pip (consultare la documentazione della pagina web). Considera il codice seguente, basato sull'esempio:

import numpy as np
import numpy.random
import matplotlib.pyplot as plt
import sphviewer as sph

def myplot(x, y, nb=32, xsize=500, ysize=500):   
    xmin = np.min(x)
    xmax = np.max(x)
    ymin = np.min(y)
    ymax = np.max(y)

    x0 = (xmin+xmax)/2.
    y0 = (ymin+ymax)/2.

    pos = np.zeros([3, len(x)])
    pos[0,:] = x
    pos[1,:] = y
    w = np.ones(len(x))

    P = sph.Particles(pos, w, nb=nb)
    S = sph.Scene(P)
    S.update_camera(r='infinity', x=x0, y=y0, z=0, 
                    xsize=xsize, ysize=ysize)
    R = sph.Render(S)
    R.set_logscale()
    img = R.get_image()
    extent = R.get_extent()
    for i, j in zip(xrange(4), [x0,x0,y0,y0]):
        extent[i] += j
    print extent
    return img, extent

fig = plt.figure(1, figsize=(10,10))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)


# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)

#Plotting a regular scatter plot
ax1.plot(x,y,'k.', markersize=5)
ax1.set_xlim(-3,3)
ax1.set_ylim(-3,3)

heatmap_16, extent_16 = myplot(x,y, nb=16)
heatmap_32, extent_32 = myplot(x,y, nb=32)
heatmap_64, extent_64 = myplot(x,y, nb=64)

ax2.imshow(heatmap_16, extent=extent_16, origin='lower', aspect='auto')
ax2.set_title("Smoothing over 16 neighbors")

ax3.imshow(heatmap_32, extent=extent_32, origin='lower', aspect='auto')
ax3.set_title("Smoothing over 32 neighbors")

#Make the heatmap using a smoothing over 64 neighbors
ax4.imshow(heatmap_64, extent=extent_64, origin='lower', aspect='auto')
ax4.set_title("Smoothing over 64 neighbors")

plt.show()

che produce la seguente immagine:

inserisci qui la descrizione dell'immagine

Come vedi, le immagini sembrano piuttosto belle e siamo in grado di identificare diverse sottostrutture su di essa. Queste immagini sono costruite diffondendo un dato peso per ogni punto all'interno di un certo dominio, definito dalla lunghezza di livellamento, che a sua volta è data dalla distanza dal vicino nb più vicino (ho scelto 16, 32 e 64 per gli esempi). Pertanto, le regioni a densità più elevata sono generalmente distribuite su regioni più piccole rispetto alle regioni a densità inferiore.

La funzione myplot è solo una funzione molto semplice che ho scritto per fornire i dati x, y a py-sphviewer per fare la magia.


2
Un commento per chiunque cerchi di installare py-sphviewer su OSX: ho avuto molte difficoltà, vedi: github.com/alejandrobll/py-sphviewer/issues/3
Sam Finnigan,

Peccato che non funzioni con python3. Si installa, ma si arresta in modo anomalo quando si tenta di utilizzarlo ...
Fábio Dias,

1
@Fabio Dias, L'ultima versione (1.1.x) ora funziona con Python 3.
Alejandro,

29

Se si utilizza 1.2.x

import numpy as np
import matplotlib.pyplot as plt

x = np.random.randn(100000)
y = np.random.randn(100000)
plt.hist2d(x,y,bins=100)
plt.show()

gaussian_2d_heat_map


17

Seaborn ora ha la funzione jointplot che dovrebbe funzionare bene qui:

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)

sns.jointplot(x=x, y=y, kind='hex')
plt.show()

immagine dimostrativa


Semplice, carino e analiticamente utile.
Ryandillon,

@wordsforthewise come si fa a rendere visivamente leggibili i dati di 600k usando questo? (come ridimensionare)
nrmb

Non sono del tutto sicuro di cosa tu voglia dire; forse è meglio porre una domanda separata e collegarla qui. Vuoi dire ridimensionare l'intero fico? Prima fai la figura con fig = plt.figure(figsize=(12, 12)), quindi ottieni l'asse corrente con ax=plt.gca(), quindi aggiungi l'argomento ax=axalla jointplotfunzione.
parole per

@wordsforthewise, la prego di rispondere a questa domanda: stackoverflow.com/questions/50997662/... grazie
ebrahimi

4

e la domanda iniziale era ... come convertire i valori di dispersione in valori di griglia, giusto? histogram2dconta la frequenza per cella, tuttavia, se si dispone di altri dati per cella oltre alla sola frequenza, è necessario un lavoro aggiuntivo da eseguire.

x = data_x # between -10 and 4, log-gamma of an svc
y = data_y # between -4 and 11, log-C of an svc
z = data_z #between 0 and 0.78, f1-values from a difficult dataset

Quindi, ho un set di dati con risultati Z per le coordinate X e Y. Tuttavia, stavo calcolando alcuni punti al di fuori dell'area di interesse (grandi lacune) e cumuli di punti in una piccola area di interesse.

Sì, qui diventa più difficile ma anche più divertente. Alcune librerie (scusate):

from matplotlib import pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.interpolate import griddata

pyplot è il mio motore grafico oggi, cm è una gamma di mappe a colori con qualche scelta iniziale. intontito per i calcoli e griddata per allegare valori a una griglia fissa.

L'ultimo è importante soprattutto perché la frequenza dei punti xy non è equamente distribuita nei miei dati. Innanzitutto, iniziamo con alcuni limiti che si adattano ai miei dati e una dimensione della griglia arbitraria. I dati originali hanno punti dati anche al di fuori dei limiti xey.

#determine grid boundaries
gridsize = 500
x_min = -8
x_max = 2.5
y_min = -2
y_max = 7

Quindi abbiamo definito una griglia con 500 pixel tra i valori minimo e massimo di xe y.

Nei miei dati, ci sono molti più dei 500 valori disponibili nell'area di grande interesse; che nella zona a basso interesse non vi sono nemmeno 200 valori nella griglia totale; tra i confini grafici di x_mine x_maxce ne sono ancora di meno.

Quindi, per ottenere una bella foto, il compito è quello di ottenere una media per gli alti valori di interesse e colmare le lacune altrove.

Definisco la mia griglia ora. Per ogni coppia xx-yy, voglio avere un colore.

xx = np.linspace(x_min, x_max, gridsize) # array of x values
yy = np.linspace(y_min, y_max, gridsize) # array of y values
grid = np.array(np.meshgrid(xx, yy.T))
grid = grid.reshape(2, grid.shape[1]*grid.shape[2]).T

Perché la strana forma? scipy.griddata vuole una forma di (n, D).

Griddata calcola un valore per punto nella griglia, con un metodo predefinito. Scelgo "più vicino": i punti della griglia vuoti verranno riempiti con i valori del vicino più vicino. Sembra che le aree con meno informazioni abbiano celle più grandi (anche se non è così). Si potrebbe scegliere di interpolare "lineare", quindi le aree con meno informazioni sembrano meno nitide. Questione di gusti, davvero.

points = np.array([x, y]).T # because griddata wants it that way
z_grid2 = griddata(points, z, grid, method='nearest')
# you get a 1D vector as result. Reshape to picture format!
z_grid2 = z_grid2.reshape(xx.shape[0], yy.shape[0])

E hop, passiamo a matplotlib per visualizzare la trama

fig = plt.figure(1, figsize=(10, 10))
ax1 = fig.add_subplot(111)
ax1.imshow(z_grid2, extent=[x_min, x_max,y_min, y_max,  ],
            origin='lower', cmap=cm.magma)
ax1.set_title("SVC: empty spots filled by nearest neighbours")
ax1.set_xlabel('log gamma')
ax1.set_ylabel('log C')
plt.show()

Intorno alla parte appuntita della V-Shape, vedi che ho fatto molti calcoli durante la mia ricerca del punto debole, mentre le parti meno interessanti quasi ovunque hanno una risoluzione inferiore.

Heatmap di un SVC in alta risoluzione


Puoi migliorare la tua risposta per avere un codice completo ed eseguibile? Questo è un metodo interessante che hai fornito. Sto cercando di capirlo meglio al momento. Non capisco bene perché ci sia una forma a V. Grazie.
Due

La V-Shape proviene dai miei dati. È il valore f1 per un SVM addestrato: sta andando un po 'nella teoria degli SVM. Se hai una C alta, include tutti i tuoi punti nel calcolo, consentendo di lavorare con un intervallo gamma più ampio. La gamma è la rigidità della curva che separa il bene e il male. Questi due valori devono essere dati all'SVM (X e Y nel mio grafico); allora ottieni un risultato (Z nella mia grafica). Nella zona migliore si spera di raggiungere altezze significative.
Anderas,

secondo tentativo: la V-Shape è nei miei dati. È il valore f1 per un SVM: se hai un C elevato, include tutti i tuoi punti nel calcolo, permettendo a un intervallo gamma più ampio di funzionare, ma rallentando il calcolo. La gamma è la rigidità della curva che separa il bene e il male. Questi due valori devono essere dati all'SVM (X e Y nel mio grafico); allora ottieni un risultato (Z nella mia grafica). Nell'area ottimizzata si ottengono valori elevati, altrove valori bassi. Quello che ho mostrato qui è utilizzabile se hai valori Z per alcuni (X, Y) e molti vuoti altrove. Se hai punti dati (X, Y, Z), puoi usare il mio codice.
Anderas,

4

Ecco il grande approccio del vicino più prossimo di Jurgy Jurgy ma implementato usando scipy.cKDTree . Nei miei test è circa 100 volte più veloce.

inserisci qui la descrizione dell'immagine

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.spatial import cKDTree


def data_coord2view_coord(p, resolution, pmin, pmax):
    dp = pmax - pmin
    dv = (p - pmin) / dp * resolution
    return dv


n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)

resolution = 250

extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]
xv = data_coord2view_coord(xs, resolution, extent[0], extent[1])
yv = data_coord2view_coord(ys, resolution, extent[2], extent[3])


def kNN2DDens(xv, yv, resolution, neighbours, dim=2):
    """
    """
    # Create the tree
    tree = cKDTree(np.array([xv, yv]).T)
    # Find the closest nnmax-1 neighbors (first entry is the point itself)
    grid = np.mgrid[0:resolution, 0:resolution].T.reshape(resolution**2, dim)
    dists = tree.query(grid, neighbours)
    # Inverse of the sum of distances to each grid point.
    inv_sum_dists = 1. / dists[0].sum(1)

    # Reshape
    im = inv_sum_dists.reshape(resolution, resolution)
    return im


fig, axes = plt.subplots(2, 2, figsize=(15, 15))
for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 63]):

    if neighbours == 0:
        ax.plot(xs, ys, 'k.', markersize=5)
        ax.set_aspect('equal')
        ax.set_title("Scatter Plot")
    else:

        im = kNN2DDens(xv, yv, resolution, neighbours)

        ax.imshow(im, origin='lower', extent=extent, cmap=cm.Blues)
        ax.set_title("Smoothing over %d neighbours" % neighbours)
        ax.set_xlim(extent[0], extent[1])
        ax.set_ylim(extent[2], extent[3])

plt.savefig('new.png', dpi=150, bbox_inches='tight')

1
Sapevo che la mia implementazione era molto inefficiente, ma non sapevo di cKDTree. Molto bene! Ti farò riferimento nella mia risposta.
Jurgy,

2

Crea una matrice bidimensionale che corrisponde alle celle nell'immagine finale, chiamata dire heatmap_cells e crea un'istanza come tutti gli zero.

Scegli due fattori di ridimensionamento che definiscono la differenza tra ciascun elemento dell'array in unità reali, per ogni dimensione, diciamo x_scaleey_scale . Scegliere questi in modo tale che tutti i punti dati rientrino nei limiti dell'array heatmap.

Per ogni punto dati non elaborato con x_valuee y_value:

heatmap_cells[floor(x_value/x_scale),floor(y_value/y_scale)]+=1


1

inserisci qui la descrizione dell'immagine

Eccone uno che ho fatto su un set di 1 milione di punti con 3 categorie (rosso, verde e blu). Ecco un link al repository se desideri provare la funzione. Github Repo

histplot(
    X,
    Y,
    labels,
    bins=2000,
    range=((-3,3),(-3,3)),
    normalize_each_label=True,
    colors = [
        [1,0,0],
        [0,1,0],
        [0,0,1]],
    gain=50)

0

Molto simile alla risposta di @Piti , ma usando 1 chiamata invece di 2 per generare i punti:

import numpy as np
import matplotlib.pyplot as plt

pts = 1000000
mean = [0.0, 0.0]
cov = [[1.0,0.0],[0.0,1.0]]

x,y = np.random.multivariate_normal(mean, cov, pts).T
plt.hist2d(x, y, bins=50, cmap=plt.cm.jet)
plt.show()

Produzione:

2d_gaussian_heatmap


0

Temo di essere un po 'in ritardo alla festa, ma ho avuto una domanda simile qualche tempo fa. La risposta accettata (da @ptomato) mi ha aiutato, ma vorrei anche pubblicare questo nel caso fosse utile a qualcuno.


''' I wanted to create a heatmap resembling a football pitch which would show the different actions performed '''

import numpy as np
import matplotlib.pyplot as plt
import random

#fixing random state for reproducibility
np.random.seed(1234324)

fig = plt.figure(12)
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

#Ratio of the pitch with respect to UEFA standards 
hmap= np.full((6, 10), 0)
#print(hmap)

xlist = np.random.uniform(low=0.0, high=100.0, size=(20))
ylist = np.random.uniform(low=0.0, high =100.0, size =(20))

#UEFA Pitch Standards are 105m x 68m
xlist = (xlist/100)*10.5
ylist = (ylist/100)*6.5

ax1.scatter(xlist,ylist)

#int of the co-ordinates to populate the array
xlist_int = xlist.astype (int)
ylist_int = ylist.astype (int)

#print(xlist_int, ylist_int)

for i, j in zip(xlist_int, ylist_int):
    #this populates the array according to the x,y co-ordinate values it encounters 
    hmap[j][i]= hmap[j][i] + 1   

#Reversing the rows is necessary 
hmap = hmap[::-1]

#print(hmap)
im = ax2.imshow(hmap)

Ecco il risultato inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.