Составьте две гистограммы на одном графике с помощью matplotlib

234

Я создал график гистограммы, используя данные из файла, и никаких проблем. Теперь я хотел наложить данные из другого файла в той же гистограмме, поэтому я делаю что-то вроде этого

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

но проблема в том, что для каждого интервала отображается только строка с наибольшим значением, а другая скрыта. Интересно, как я мог нарисовать обе гистограммы одновременно разными цветами?

Открой путь
источник

Ответы:

418

Вот вам рабочий пример:

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

введите описание изображения здесь

Хоакин
источник
1
Разве не было бы хорошей идеей установить pyplot.hold(True)перед началом печати, на всякий случай?
JAB
2
Не уверен, что в моем параметре конфигурации matplotlib установлено значение hold (True) или pyplot по умолчанию ведет себя так, но для меня код работает так, как есть. Код извлекается из более крупного приложения, которое пока не доставляет никаких проблем. Во всяком случае, хороший вопрос, который я уже задал себе при написании кода
Хоакин
@joaquin: как я могу указать x, чтобы быть синим и y, чтобы быть красным?
AMC
7
При воспроизведении сюжета с краем цвета полосок Noneпо умолчанию. Если вам нужен такой же дизайн, как показано на графике, вы можете установить edgecolorпараметр в обоих, например, k(черный). Процедура похожа на легенду.
Итак,
2
Еще проще: pyplot.hist([x, y], bins, alpha=0.5, label=['x', 'y']).
Августин
174

Принятые ответы дают код для гистограммы с перекрывающимися столбцами, но если вы хотите, чтобы каждый столбец был рядом (как я сделал), попробуйте вариант ниже:

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

введите описание изображения здесь

Ссылка: http://matplotlib.org/examples/statistics/histogram_demo_multihist.html

РЕДАКТИРОВАТЬ [2018/03/16]: Обновлен, чтобы позволить рисование массивов разных размеров, как предложено @stochastic_zeitgeist

Густаво Безерра
источник
@GustavoBezerra, как использовать plt.histдля создания одного PDF-файла для каждой гистограммы? Я загрузил свои данные с помощью pandas.read_csvи файл имеет 36 столбцов и 100 строк. Поэтому я хотел бы 100 файлов PDF.
Сигур
2
@ Сигур Это совсем не по теме. Пожалуйста, Google или задать новый вопрос. Похоже, это связано с: stackoverflow.com/questions/11328958/…
Густаво Безерра
1
@stochastic_zeitgeist Я согласен с @pasbi. Я использовал ваш комментарий с фреймом данных pandas, потому что мне нужны были разные веса из-за nans. с, x=np.array(df.a)и y=np.array(df.b.dropna())это в основном закончилось тем, чтоplt.hist([x, y], weights=[np.ones_like(x)/len(x), np.ones_like(y)/len(y)])
grinsbaeckchen
1
В случае, если ваши размеры выборки резко отличаются, вы можете построить график, используя двойные оси, чтобы лучше сравнить распределения. Смотри ниже .
Андрей
1
@ AgapeGal'lo Пожалуйста, обратитесь к ответу Андрея.
Густаво Безерра
30

В случае, если у вас разные размеры выборки, может быть трудно сравнить распределения с одной осью 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, очистить ось, а затем заново нанести ее на две отдельные оси (смещая края корзины таким образом, чтобы они не перекрывались):

#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
Это хороший краткий ответ , кроме вас , следует также добавить , как центрировать бары на каждой этикетке клеща
Odisseo
12

В завершение ответа Густаво Безерра :

Если вы хотите, чтобы каждая гистограмма была нормализована ( 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()

введите описание изображения здесь

Для сравнения точно так же xи yвекторы с весами по умолчанию и density=True:

введите описание изображения здесь

Jojo
источник
9

Вы должны использовать binsиз значений, возвращаемых 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)

Две гистограммы matplotlib с одинаковым бинингом

Адриен Рено
источник
7

Вот простой метод построения двух гистограмм с их столбцами рядом на одном графике, когда данные имеют разные размеры:

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()
stochastic_zeitgeist
источник
3

Звучит так, как будто вы хотите просто гистограмму:

Кроме того, вы можете использовать подзаговоры.

деревенщина
источник
Разница заключается в том, что с историей вы получаете график частоты. Может быть, вы должны показать, как это сделать. частота с пандами + гистограмма = исторических ()
VP.
2

На случай, если у вас есть pandas ( 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()
Serv-вкл
источник
Я считаю, что использование панд не сработает, если сравниваемые гистограммы имеют разные размеры выборки. Это также часто контекст, в котором используются нормализованные гистограммы.
Соломон Вимал
2

Есть одно предупреждение, когда вы хотите построить гистограмму из двумерного массива. Вам нужно поменять 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()

введите описание изображения здесь

黄锐铭
источник
0

На этот вопрос уже был дан ответ, но я хотел добавить еще один быстрый / простой способ, который может помочь другим посетителям в этом вопросе.

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

Некоторые полезные примеры здесь для KDE против сравнения гистограмм.

Соломон Вимал
источник
0

Вдохновленный ответом Соломона, но придерживаясь вопроса, который связан с гистограммой, чистое решение:

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

Удостоверьтесь, что сначала вычерчиваете более высокое значение, в противном случае вам потребуется установить plt.ylim (0,0,45), чтобы гистограмма более высокого уровня не была обрезана.

Сара
источник
0

Также вариант, который очень похож на ответ Хоакин:

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

Дает следующий вывод:

введите описание изображения здесь

PV8
источник