Traccia due istogrammi su un singolo diagramma con matplotlib


234

Ho creato un diagramma dell'istogramma utilizzando i dati di un file e nessun problema. Ora volevo sovrapporre i dati di un altro file nello stesso istogramma, quindi faccio qualcosa del genere

n,bins,patchs = ax.hist(mydata1,100)
n,bins,patchs = ax.hist(mydata2,100)

ma il problema è che per ogni intervallo appare solo la barra con il valore più alto e l'altra è nascosta. Mi chiedo come potrei tracciare entrambi gli istogrammi contemporaneamente con colori diversi.

Risposte:


418

Ecco un esempio funzionante:

import random
import numpy
from matplotlib import pyplot

x = [random.gauss(3,1) for _ in range(400)]
y = [random.gauss(4,2) for _ in range(400)]

bins = numpy.linspace(-10, 10, 100)

pyplot.hist(x, bins, alpha=0.5, label='x')
pyplot.hist(y, bins, alpha=0.5, label='y')
pyplot.legend(loc='upper right')
pyplot.show()

inserisci qui la descrizione dell'immagine


1
Non sarebbe una buona idea impostare pyplot.hold(True)prima della stampa, per ogni evenienza?
JAB,

2
Non sono sicuro che hold (True) sia impostato nel mio parametro di configurazione matplotlib o pyplot si comporti in questo modo per impostazione predefinita, ma per me il codice funziona così com'è. Il codice viene estratto da un'applicazione più grande che finora non ha dato alcun problema. Comunque, buona domanda che ho già fatto a me stesso quando scrivo il codice
joaquin,

@joaquin: come posso specificare x come blu e y come rosso?
AMC

7
Quando ho riprodotto la trama con l'edgecolor delle barre è Nonedi default. Se si desidera lo stesso design mostrato nel grafico, è possibile impostare il edgecolorparametro in entrambi, ad esempio su k(nero). La procedura è simile per la legenda.
Quindi il

2
Ancora più facile: pyplot.hist([x, y], bins, alpha=0.5, label=['x', 'y']).
Augustin,

174

Le risposte accettate forniscono il codice per un istogramma con barre sovrapposte, ma nel caso in cui si desideri che ciascuna barra sia fianco a fianco (come ho fatto io), provare la variazione di seguito:

import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-deep')

x = np.random.normal(1, 2, 5000)
y = np.random.normal(-1, 3, 2000)
bins = np.linspace(-10, 10, 30)

plt.hist([x, y], bins, label=['x', 'y'])
plt.legend(loc='upper right')
plt.show()

inserisci qui la descrizione dell'immagine

Riferimento: http://matplotlib.org/examples/statistics/histogram_demo_multihist.html

EDIT [2018/03/16]: aggiornato per consentire la stampa di matrici di dimensioni diverse, come suggerito da @stochastic_zeitgeist


@GustavoBezerra, come utilizzare plt.histper produrre un file pdf per ogni istogramma? Ho caricato i miei dati usando pandas.read_csve il file ha 36 colonne e 100 linee. Quindi vorrei 100 file pdf.
Sigur,

2
@Sigur Questo è abbastanza fuori tema. Per favore, Google o fai una nuova domanda. Questo sembra essere correlato: stackoverflow.com/questions/11328958/…
Gustavo Bezerra,

1
@stochastic_zeitgeist Sono d'accordo con @pasbi. Ho usato il tuo commento con un frame di dati Panda perché avevo bisogno di pesi diversi a causa di Nans. con x=np.array(df.a)e y=np.array(df.b.dropna())sostanzialmente finì per essereplt.hist([x, y], weights=[np.ones_like(x)/len(x), np.ones_like(y)/len(y)])
grinsbaeckchen

1
Nel caso in cui le dimensioni del campione siano drasticamente diverse, è possibile che si desideri tracciare una trama utilizzando due assi per confrontare meglio le distribuzioni. Vedi sotto .
Andrew,

1
@ AgapeGal'lo Ti preghiamo di fare riferimento alla risposta di Andrew.
Gustavo Bezerra,

30

Nel caso di campioni di dimensioni diverse, potrebbe essere difficile confrontare le distribuzioni con un singolo asse y. Per esempio:

import numpy as np
import matplotlib.pyplot as plt

#makes the data
y1 = np.random.normal(-2, 2, 1000)
y2 = np.random.normal(2, 2, 5000)
colors = ['b','g']

#plots the histogram
fig, ax1 = plt.subplots()
ax1.hist([y1,y2],color=colors)
ax1.set_xlim(-10,10)
ax1.set_ylabel("Count")
plt.tight_layout()
plt.show()

hist_single_ax

In questo caso, puoi tracciare i tuoi due set di dati su assi diversi. Per fare ciò, è possibile ottenere i dati dell'istogramma utilizzando matplotlib, cancellare l'asse e quindi ri-tracciarlo su due assi separati (spostando i bordi del cestino in modo che non si sovrappongano):

#sets up the axis and gets histogram data
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.hist([y1, y2], color=colors)
n, bins, patches = ax1.hist([y1,y2])
ax1.cla() #clear the axis

#plots the histogram data
width = (bins[1] - bins[0]) * 0.4
bins_shifted = bins + width
ax1.bar(bins[:-1], n[0], width, align='edge', color=colors[0])
ax2.bar(bins_shifted[:-1], n[1], width, align='edge', color=colors[1])

#finishes the plot
ax1.set_ylabel("Count", color=colors[0])
ax2.set_ylabel("Count", color=colors[1])
ax1.tick_params('y', colors=colors[0])
ax2.tick_params('y', colors=colors[1])
plt.tight_layout()
plt.show()

hist_twin_ax


1
Questa è una bella risposta breve tranne che dovresti anche aggiungere come centrare le barre su ogni etichetta di spunta
Odisseo

12

A completamento della risposta di Gustavo Bezerra :

Se vuoi che ogni istogramma sia normalizzato ( normedper mpl <= 2.1 e densityper mpl> = 3.1 ) non puoi semplicemente usare normed/density=True, devi invece impostare i pesi per ciascun valore:

import numpy as np
import matplotlib.pyplot as plt

x = np.random.normal(1, 2, 5000)
y = np.random.normal(-1, 3, 2000)
x_w = np.empty(x.shape)
x_w.fill(1/x.shape[0])
y_w = np.empty(y.shape)
y_w.fill(1/y.shape[0])
bins = np.linspace(-10, 10, 30)

plt.hist([x, y], bins, weights=[x_w, y_w], label=['x', 'y'])
plt.legend(loc='upper right')
plt.show()

inserisci qui la descrizione dell'immagine

A titolo di confronto, lo stesso identico xe i yvettori con pesi predefiniti e density=True:

inserisci qui la descrizione dell'immagine


9

È necessario utilizzare binsdai valori restituiti da hist:

import numpy as np
import matplotlib.pyplot as plt

foo = np.random.normal(loc=1, size=100) # a normal distribution
bar = np.random.normal(loc=-1, size=10000) # a normal distribution

_, bins, _ = plt.hist(foo, bins=50, range=[-6, 6], normed=True)
_ = plt.hist(bar, bins=bins, alpha=0.5, normed=True)

Due istogrammi matplotlib con lo stesso binning


7

Ecco un semplice metodo per tracciare due istogrammi, con le loro barre affiancate, sullo stesso grafico quando i dati hanno dimensioni diverse:

def plotHistogram(p, o):
    """
    p and o are iterables with the values you want to 
    plot the histogram of
    """
    plt.hist([p, o], color=['g','r'], alpha=0.8, bins=50)
    plt.show()


2

Nel caso abbiate dei panda ( import pandas as pd) o non abbiate ragione di usarlo:

test = pd.DataFrame([[random.gauss(3,1) for _ in range(400)], 
                     [random.gauss(4,2) for _ in range(400)]])
plt.hist(test.values.T)
plt.show()

Credo che l'uso dei panda non funzionerà se gli istogrammi da confrontare hanno dimensioni del campione diverse. Questo è spesso anche il contesto in cui vengono utilizzati gli istogrammi normalizzati.
Solomon Vimal,

2

C'è un avvertimento quando si desidera tracciare l'istogramma da una matrice numpy 2-d. Devi scambiare i 2 assi.

import numpy as np
import matplotlib.pyplot as plt

data = np.random.normal(size=(2, 300))
# swapped_data.shape == (300, 2)
swapped_data = np.swapaxes(x, axis1=0, axis2=1)
plt.hist(swapped_data, bins=30, label=['x', 'y'])
plt.legend()
plt.show()

inserisci qui la descrizione dell'immagine


0

Questa domanda ha già ricevuto una risposta, ma ha voluto aggiungere un'altra soluzione rapida / semplice che potrebbe aiutare gli altri visitatori a questa domanda.

import seasborn as sns 
sns.kdeplot(mydata1)
sns.kdeplot(mydata2)

Alcuni esempi utili sono qui per il confronto tra kde e istogramma.


0

Ispirato dalla risposta di Salomone, ma per attenersi alla domanda relativa all'istogramma, una soluzione pulita è:

sns.distplot(bar)
sns.distplot(foo)
plt.show()

Assicurati di tracciare prima quello più alto, altrimenti dovrai impostare plt.ylim (0,0.45) in modo che l'istogramma più alto non venga tagliato.


0

Anche un'opzione che è abbastanza simile alla risposta di Joaquin:

import random
from matplotlib import pyplot

#random data
x = [random.gauss(3,1) for _ in range(400)]
y = [random.gauss(4,2) for _ in range(400)]

#plot both histograms(range from -10 to 10), bins set to 100
pyplot.hist([x,y], bins= 100, range=[-10,10], alpha=0.5, label=['x', 'y'])
#plot legend
pyplot.legend(loc='upper right')
#show it
pyplot.show()

Fornisce il seguente output:

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.