web-dev-qa-db-fra.com

Tracer deux histogrammes en même temps avec matplotlib

J'ai créé un tracé d'histogramme en utilisant les données d'un fichier et aucun problème. Maintenant, je voulais superposer les données d'un autre fichier dans le même histogramme, alors je fais quelque chose comme

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

mais le problème est que pour chaque intervalle, seule la barre avec la valeur la plus élevée apparaît et l'autre est masquée. Je me demande comment pourrais-je tracer les deux histogrammes en même temps avec des couleurs différentes.

189
Open the way

Ici vous avez un exemple de travail:

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

enter image description here

353
joaquin

Les réponses acceptées donnent le code d'un histogramme avec des barres qui se chevauchent, mais si vous voulez que chaque barre soit côte à côte (comme je l'ai fait), essayez la variante ci-dessous:

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

enter image description here

Référence: http://matplotlib.org/examples/statistics/histogram_demo_multihist.html

EDIT [2018/03/16]: Mise à jour pour permettre le traçage de tableaux de tailles différentes, comme suggéré par @stochastic_zeitgeist

131
Gustavo Bezerra

Si la taille des échantillons est différente, il peut être difficile de comparer les distributions avec un seul axe des ordonnées. Par exemple:

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

Dans ce cas, vous pouvez tracer vos deux ensembles de données sur des axes différents. Pour ce faire, vous pouvez obtenir les données de votre histogramme à l'aide de matplotlib, effacer l'axe, puis le représenter à nouveau sur deux axes distincts (en décalant les bords des casiers afin qu'ils ne se chevauchent pas):

#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

24
Andrew

Voici une méthode simple pour tracer deux histogrammes, avec leurs barres côte à côte, sur le même tracé lorsque les données ont des tailles différentes:

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

En complément de réponse de Gustavo Bezerra :

Si vous voulez normaliser chaque histogramme (normed pour mpl <= 2.1 et density pour mpl> = 3.1 ), vous ne pouvez pas simplement utiliser normed/density=True, vous devez définir les poids pour chaque valeur:

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

enter image description here

À titre de comparaison, les mêmes vecteurs x et y avec les pondérations par défaut et density=True:

enter image description here

7
jojo

Il semble que vous souhaitiez simplement un graphique à barres:

Alternativement, vous pouvez utiliser des intrigues secondaires.

3
carl

Vous devez utiliser bins à partir des valeurs renvoyées par 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)

Two matplotlib histograms with same binning

3
Adrien Renaud

Juste au cas où vous avez pandas (import pandas as pd) ou êtes prêt à l’utiliser:

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()
2
serv-inc

On a déjà répondu à cette question, mais je voulais ajouter une autre solution de contournement rapide/facile qui pourrait aider d'autres visiteurs à cette question.

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

Quelques exemples utiles sont ici pour la comparaison kde vs histogramme.

0
Solomon Vimal

Inspirée par la réponse de Solomon, mais pour en rester à la question, qui est liée à l'histogramme, une solution propre est la suivante:

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

Assurez-vous de tracer le plus grand en premier, sinon vous devrez définir plt.ylim (0,0,45) pour que l'histogramme le plus grand ne soit pas coupé.

0
Sarah