Гистограмма matplotlib неуместна и отсутствуют столбцы - PullRequest
0 голосов
/ 26 мая 2020

У меня есть большие файлы данных, поэтому я использую гистограмму numpy (такую ​​же, как в matplotlib), чтобы вручную генерировать гистограммы и обновлять их. Однако при построении графика я чувствую, что график сдвигается.

Это код, который я использую для ручного создания и обновления гистограмм партиями. Обратите внимание, что все гистограммы используют одни и те же ячейки.

temp = np.histogram(batch, bins=np.linspace(0, 40, 41))
hist += temp[0]

Приведенный выше код повторяется при анализе файлов данных. Например, небольшой набор данных будет иметь следующие данные окончательной гистограммы:

[8190, 666, 278, 145, 113, 83, 52, 48, 45, 44, 45, 29, 28, 45, 29, 15, 16, 10, 17, 7, 15, 6, 10, 7, 3, 5, 7, 4, 2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 29]

Ниже приведен код построения.

import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt
import numpy as np
plt.xticks(np.linspace(0, 1, 11))
plt.hist([i/40 for i in range(40)], bins=np.linspace(0, 1, 41), weights=scores, rwidth=0.7)
plt.yscale('log', nonposy='clip')

Результирующий рисунок довольно странно. Он не показывает полосу на [0,475, 0,5), и я ожидаю, что интервал 0,975, который находится в диапазоне [0,975, 1,0], будет включать последние 29 значений. Однако вместо этого я вижу этот бар в позиции [0,950, 0,975). Я думал, что это может быть связано с использованием бункеров и линейного пространства, но размер массива-приманки и веса одинаковы.

enter image description here

Я никогда не видел такого поведения. Я тоже думал, что это будет так, как диапазоны [x, x + width), но у меня не было проблем с этим.

Примечание об использовании linspace. Он определяет края, поэтому 40 ячеек определяется 41 ребром.

In [2]: np.linspace(0,1,41)                                                     
Out[2]: 
array([0.   , 0.025, 0.05 , 0.075, 0.1  , 0.125, 0.15 , 0.175, 0.2  ,
       0.225, 0.25 , 0.275, 0.3  , 0.325, 0.35 , 0.375, 0.4  , 0.425,
       0.45 , 0.475, 0.5  , 0.525, 0.55 , 0.575, 0.6  , 0.625, 0.65 ,
       0.675, 0.7  , 0.725, 0.75 , 0.775, 0.8  , 0.825, 0.85 , 0.875,
       0.9  , 0.925, 0.95 , 0.975, 1.   ])

In [3]: len(np.linspace(0,1,41))                                                
Out[3]: 41

1 Ответ

1 голос
/ 26 мая 2020

Кажется, вы используете plt.hist с идеей поместить одно значение в каждую ячейку, чтобы имитировать гистограмму. Поскольку значения x попадают точно в границы интервала, из-за округления они могут оказаться в соседнем интервале. Это можно смягчить, переместив значения x на половину ширины ячейки. Самый простой - это рисование столбцов напрямую.

Следующий код создает гистограмму с заданными данными, причем каждая полоса находится в центре области, которую она представляет. В качестве проверки, полоски снова измеряются в конце и отображается их высота.

from  matplotlib.ticker import MultipleLocator
import matplotlib.pyplot as plt
import numpy as np

scores =[8190,666,278,145,113,83,52,48,45,44,45,29,28,45,29,15,16,10,17,7,15,6,10,7,3,5,7,4,2,3,0,1,0,0,0,0,0,0,0,29]
binbounds = np.linspace(0, 1, 41)
rwidth = 0.7
width = binbounds[1] - binbounds[0]
bars = plt.bar(binbounds[:-1] + width / 2, height=scores, width=width * rwidth, align='center')
plt.gca().xaxis.set_major_locator(MultipleLocator(0.1))
plt.gca().xaxis.set_minor_locator(MultipleLocator(0.05))
plt.yscale('log', nonposy='clip')
for rect in bars:
    x, y = rect.get_xy()
    w = rect.get_width()
    h = rect.get_height()
    plt.text(x + w / 2, h, f'{h}\n', ha='center', va='center')
plt.show()

resulting plot

PS: Чтобы увидеть, что происходит с оригиналом гистограмма, просто сделайте тестовый график без весов:

plt.hist([i/40 for i in range(40)], bins=np.linspace(0, 1, 41), rwidth=1, ec='k')
plt.plot([i/40 for i in range(40)], [0.5] * 40, 'ro')
plt.xticks(np.linspace(0, 1, 11))

Красная точка показывает, где находятся значения x. Некоторые попадают в правильный ящик, некоторые - в соседний, который внезапно получает 2 значения. histogram without weights

Чтобы создать гистограмму со значениями x в центре каждой ячейки:

plt.hist([i/40 + 1/80 for i in range(40)], bins=np.linspace(0, 1, 41), rwidth=1, ec='k')
plt.plot([i/40 + 1/80 for i in range(40)], [0.5] * 40, 'ro')
plt.xticks(np.linspace(0, 1, 11))
plt.yticks([0, 1])

x-values in center of bin

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...