Plot dua histogram pada grafik tunggal dengan matplotlib


234

Saya membuat plot histogram menggunakan data dari file dan tidak ada masalah. Sekarang saya ingin menempatkan data dari file lain dalam histogram yang sama, jadi saya melakukan sesuatu seperti ini

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

tetapi masalahnya adalah untuk setiap interval, hanya bilah dengan nilai tertinggi yang muncul, dan yang lainnya disembunyikan. Saya bertanya-tanya bagaimana saya bisa memetakan kedua histogram secara bersamaan dengan warna yang berbeda.

Jawaban:


418

Di sini Anda memiliki contoh yang berfungsi:

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

masukkan deskripsi gambar di sini


1
Bukankah itu ide yang baik untuk ditetapkan pyplot.hold(True)sebelum merencanakan, untuk berjaga-jaga?
JAB

2
Tidak yakin apakah hold (True) disetel di parplig config matplotlib saya atau pyplot berperilaku seperti ini secara default, tetapi bagi saya kodenya berfungsi apa adanya. Kode ini diekstraksi dari aplikasi yang lebih besar yang sejauh ini tidak memberikan masalah. Ngomong-ngomong, pertanyaan bagus sudah saya buat untuk diri saya sendiri ketika menulis kode
joaquin

@ jooaquin: bagaimana saya bisa menentukan x menjadi biru dan y menjadi merah?
amc

7
Ketika saya mereproduksi plot dengan warna warna bar secara Nonedefault. Jika Anda ingin desain yang sama seperti yang ditunjukkan pada grafik, Anda dapat mengatur edgecolorparameter di keduanya misalnya menjadi k(hitam). Prosedurnya mirip untuk legenda.
Jadi S

2
Bahkan lebih mudah: pyplot.hist([x, y], bins, alpha=0.5, label=['x', 'y']).
Augustin

174

Jawaban yang diterima memberikan kode untuk histogram dengan bilah yang tumpang tindih, tetapi jika Anda ingin setiap bilah saling berdampingan (seperti yang saya lakukan), coba variasi di bawah ini:

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

masukkan deskripsi gambar di sini

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

EDIT [2018/03/16]: Diperbarui untuk memungkinkan plot array dengan ukuran berbeda, seperti yang disarankan oleh @stochastic_zeitgeist


@ GustavoBezerra, bagaimana cara menggunakan plt.histuntuk menghasilkan satu file pdf untuk setiap histogram? Saya memuat data saya menggunakan pandas.read_csvdan file memiliki 36 kolom dan 100 baris. Jadi saya ingin 100 file pdf.
Sigur

2
@ Konfigurasi Itu cukup banyak topik. Silakan Google atau ajukan pertanyaan baru. Ini sepertinya terkait: stackoverflow.com/questions/11328958/…
Gustavo Bezerra

1
@stochastic_zeitgeist Saya setuju dengan @pasbi. Saya menggunakan komentar Anda dengan kerangka data panda karena saya membutuhkan bobot yang berbeda karena nans. dengan x=np.array(df.a)dan y=np.array(df.b.dropna())pada dasarnya berakhir menjadiplt.hist([x, y], weights=[np.ones_like(x)/len(x), np.ones_like(y)/len(y)])
grinsbaeckchen

1
Jika ukuran sampel Anda sangat berbeda, Anda mungkin ingin merencanakan menggunakan sumbu kembar untuk membandingkan distribusi dengan lebih baik. Lihat di bawah .
Andrew

1
@ AgapeGal'lo Silakan merujuk ke jawaban Andrew.
Gustavo Bezerra

30

Jika Anda memiliki ukuran sampel yang berbeda, mungkin sulit untuk membandingkan distribusi dengan sumbu y tunggal. Sebagai contoh:

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

Dalam hal ini, Anda dapat memplot dua set data Anda pada sumbu yang berbeda. Untuk melakukannya, Anda bisa mendapatkan data histogram Anda menggunakan matplotlib, bersihkan porosnya, dan kemudian plot ulang pada dua sumbu terpisah (menggeser tepi nampan sehingga tidak tumpang tindih):

#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
Ini adalah jawaban singkat yang bagus kecuali Anda juga harus menambahkan cara memusatkan bar pada setiap label centang
Odisseo

12

Sebagai pelengkap jawaban Gustavo Bezerra :

Jika Anda ingin setiap histogram dinormalisasi ( normeduntuk mpl <= 2.1 dan densityuntuk mpl> = 3.1 ) Anda tidak bisa hanya menggunakan normed/density=True, Anda perlu mengatur bobot untuk setiap nilai sebagai gantinya:

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

masukkan deskripsi gambar di sini

Sebagai perbandingan, sama persis xdan yvektor dengan bobot default dan density=True:

masukkan deskripsi gambar di sini


9

Anda harus menggunakan binsdari nilai yang dikembalikan oleh 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)

Dua histogram matplotlib dengan binning yang sama


7

Berikut adalah metode sederhana untuk memplot dua histogram, dengan bilah mereka berdampingan, pada plot yang sama ketika data memiliki ukuran yang berbeda:

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

Hanya dalam kasus Anda memiliki panda ( import pandas as pd) atau tidak apa-apa dengan menggunakannya:

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

Saya percaya menggunakan panda tidak akan berfungsi jika histogram yang akan dibandingkan memiliki ukuran sampel yang berbeda. Ini juga sering merupakan konteks di mana histogram normal digunakan.
Solomon Vimal

2

Ada satu peringatan ketika Anda ingin memplot histogram dari array numpy 2-d. Anda perlu menukar 2 sumbu.

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

masukkan deskripsi gambar di sini


0

Pertanyaan ini telah dijawab sebelumnya, tetapi ingin menambahkan solusi cepat / mudah lain yang mungkin membantu pengunjung lain ke pertanyaan ini.

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

Beberapa contoh bermanfaat ada di sini untuk perbandingan kde vs histogram.


0

Terinspirasi oleh jawaban Solomon, tetapi untuk tetap dengan pertanyaan, yang terkait dengan histogram, solusi bersih adalah:

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

Pastikan untuk merencanakan yang lebih tinggi terlebih dahulu, jika tidak, Anda perlu mengatur plt.ylim (0,0.45) agar histogram yang lebih tinggi tidak dipotong.


0

Juga merupakan opsi yang sangat mirip dengan jawaban 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()

Memberikan hasil sebagai berikut:

masukkan deskripsi gambar di sini

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.