Вертикальная линия в конце гистограммы CDF с использованием matplotlib

Я пытаюсь создать CDF, но в конце графика есть вертикальная линия, показанная ниже:

сюжет

Я читал, что это потому, что matplotlib использует конец ячеек для рисования вертикальных линий, что имеет смысл, поэтому я добавил в свой код как:

bins = sorted(X) + [np.inf]

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

plt.hist(X, bins = bins, cumulative = True, histtype = 'step', color = 'b')

Это удаляет линию в конце и дает желаемый эффект, однако, когда я нормализую этот график, теперь возникает ошибка:

ymin = max(ymin*0.9, minimum) if not input_empty else minimum

UnboundLocalError: local variable 'ymin' referenced before assignment

Есть ли способ нормализовать данные с помощью

bins = sorted(X) + [np.inf]

в моем коде или есть другой способ убрать линию на графике?


person Sam Billington    schedule 27.09.2016    source источник
comment
Не уверен, почему за это проголосовали. Это артефакт того, как работает hist + step. Возможно, вам будет лучше вычислить кумулятивную гистограмму, а затем использовать ax.step.   -  person tacaswell    schedule 27.09.2016
comment
Вы хотите CDF или гистограмму? Если это CDF, то какой?   -  person Stop harming Monica    schedule 27.09.2016


Ответы (3)


Альтернативный способ построения CDF может быть следующим (в моем примере X — это набор выборок, взятых из единичной нормали):

import numpy as np
import matplotlib.pyplot as plt

X = np.random.randn(10000)
n = np.arange(1,len(X)+1) / np.float(len(X))
Xs = np.sort(X)
fig, ax = plt.subplots()
ax.step(Xs,n) 

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

person Angus Williams    schedule 27.09.2016
comment
Это блестящая и красивая альтернатива! - person merlin2011; 18.01.2017
comment
Проблема заключается в том, что график будет линейно интерполирован между точками, но настоящая кумулятивная функция должна иметь эти скачки. - person RomaValcer; 05.03.2017
comment
Да, это, вероятно, справедливое замечание, хотя для больших выборок данных это не будет иметь большого значения. Тем не менее, я обновил свой ответ, чтобы вместо него использовать plt.step. Спасибо! - person Angus Williams; 13.03.2017

Мне нужно было решение, в котором мне не нужно было бы изменять остальную часть моего кода (используя plt.hist(...) или, с пандами, dataframe.plot.hist(...)) и которое я мог бы легко повторно использовать много раз в одном блокноте jupyter.

Теперь я использую эту маленькую вспомогательную функцию для этого:

def fix_hist_step_vertical_line_at_end(ax):
    axpolygons = [poly for poly in ax.get_children() if isinstance(poly, mpl.patches.Polygon)]
    for poly in axpolygons:
        poly.set_xy(poly.get_xy()[:-1])

Что можно использовать так (без панд):

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

X = np.sort(np.random.randn(1000))

fig, ax = plt.subplots()
plt.hist(X, bins=100, cumulative=True, density=True, histtype='step')

fix_hist_step_vertical_line_at_end(ax)

Или вот так (с пандами):

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt

df = pd.DataFrame(np.random.randn(1000))

fig, ax = plt.subplots()
ax = df.plot.hist(ax=ax, bins=100, cumulative=True, density=True, histtype='step', legend=False)

fix_hist_step_vertical_line_at_end(ax)

результат

Это хорошо работает, даже если у вас есть несколько гистограмм кумулятивной плотности на одних и тех же осях.

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

person Zertrin    schedule 22.10.2018
comment
Спасибо! Это сработало для меня. У меня есть дополнительный CDF, поэтому мне просто нужно изменить poly.set_xy(poly.get_xy()[:-1]) на poly.set_xy(poly.get_xy()[1:]) - person Jonathan Ellithorpe; 30.08.2019

Предполагая, что ваши намерения чисто эстетические, добавьте вертикальную линию того же цвета, что и фон вашего графика:

ax.axvline(x = value, color = 'white', linewidth = 2)

Где значение обозначает правую крайность самой правой корзины.

person rllb    schedule 12.04.2020