簡體   English   中英

使用 matplotlib 在單個圖表上繪制兩個直方圖

[英]Plot two histograms on single chart with matplotlib

我使用文件中的數據創建了一個直方圖,沒有問題。 現在我想在同一個直方圖中疊加來自另一個文件的數據,所以我做這樣的事情

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

但問題是,對於每個區間,只有最高值的條出現,而其他的則隱藏。 我想知道如何用不同的顏色同時繪制兩個直方圖。

這里有一個工作示例:

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

在此處輸入圖片說明

接受的答案給出了帶有重疊條的直方圖的代碼,但如果您希望每個條並排(就像我所做的那樣),請嘗試以下變體:

import numpy as np
import matplotlib.pyplot as plt

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

直方圖

參考: http : //matplotlib.org/examples/statistics/histogram_demo_multihist.html

編輯 [2018/03/16]:更新為允許繪制不同大小的數組,如@stochastic_zeitgeist 所建議的

如果您有不同的樣本量,可能很難將分布與單個 y 軸進行比較。 例如:

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

在這種情況下,您可以在不同的軸上繪制兩個數據集。 為此,您可以使用 matplotlib 獲取直方圖數據,清除軸,然后在兩個單獨的軸上重新繪制它(移動 bin 邊緣,使它們不重疊):

#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

作為Gustavo Bezerra 回答的補充

如果你想每個直方圖進行歸一化normed為MPL <= 2.1和density為MPL> = 3.1),你不能只用normed/density=True ,你需要為每個代替值的權重:

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

在此處輸入圖片說明

作為比較,具有默認權重和density=True的完全相同的xy向量:

在此處輸入圖片說明

您應該使用hist返回的值中的bins

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)

兩個具有相同分箱的 matplotlib 直方圖

這是一個簡單的方法,當數據具有不同的大小時,在同一個圖上繪制兩個直方圖,它們的條並排:

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

還有一個與 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()

給出以下輸出:

在此處輸入圖片說明

繪制兩個重疊的直方圖(或更多)會導致繪圖相當混亂。 我發現使用階梯直方圖(又名空心直方圖)可以大大提高可讀性。 唯一的缺點是在 matplotlib 中,步驟直方圖的默認圖例格式不正確,因此可以像以下示例中那樣對其進行編輯:

import numpy as np                   # v 1.19.2
import matplotlib.pyplot as plt      # v 3.3.2
from matplotlib.lines import Line2D

rng = np.random.default_rng(seed=123)

# Create two normally distributed random variables of different sizes
# and with different shapes
data1 = rng.normal(loc=30, scale=10, size=500)
data2 = rng.normal(loc=50, scale=10, size=1000)

# Create figure with 'step' type of histogram to improve plot readability
fig, ax = plt.subplots(figsize=(9,5))
ax.hist([data1, data2], bins=15, histtype='step', linewidth=2,
        alpha=0.7, label=['data1','data2'])

# Edit legend to get lines as legend keys instead of the default polygons
# and sort the legend entries in alphanumeric order
handles, labels = ax.get_legend_handles_labels()
leg_entries = {}
for h, label in zip(handles, labels):
    leg_entries[label] = Line2D([0], [0], color=h.get_facecolor()[:-1],
                                alpha=h.get_alpha(), lw=h.get_linewidth())
labels_sorted, lines = zip(*sorted(leg_entries.items()))
ax.legend(lines, labels_sorted, frameon=False)

# Remove spines
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

# Add annotations
plt.ylabel('Frequency', labelpad=15)
plt.title('Matplotlib step histogram', fontsize=14, pad=20)
plt.show()

step_hist

如您所見,結果看起來很干凈。 當重疊兩個以上的直方圖時,這尤其有用。 根據變量的分布方式,這最多可用於大約 5 個重疊分布。 不僅如此,還需要使用另一種類型的繪圖,例如 此處介紹的一種。

以防萬一您有熊貓( import pandas as pd )或者可以使用它:

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

當您想從二維 numpy 數組繪制直方圖時,有一個警告。 您需要交換 2 個軸。

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

在此處輸入圖片說明

這個問題之前已經回答過,但想添加另一個快速/簡單的解決方法,可能會幫助其他訪問者解決這個問題。

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

這里有一些有用的例子,用於 kde 與直方圖的比較。

受到所羅門回答的啟發,但要堅持與直方圖相關的問題,一個干凈的解決方案是:

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

確保首先繪制較高的直方圖,否則您需要設置 plt.ylim(0,0.45) 以便不會切斷較高的直方圖。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM