Seaborn barplot добавляет горизонтальную линию на разной высоте

#python #pandas #seaborn

Вопрос:

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

То, что я пробовал до сих пор, это:

 import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame([[1, 2, 1], [2, 4, 3], [3, 6, 1], [4, 8, 3]], columns=["X", "Value", "Hor"])
fig, ax = plt.subplots()
sns.barplot(x="X", y="Value", data=df, color='green', ax=ax)
sns.barplot(x="X", y="Hor", data=df, color='green', linewidth=2.5, edgecolor='black', ax=ax)
 

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

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

Мой вопрос двоякий:

  1. Это способ сделать это? Укладывая два гистограммы друг на друга?
  2. Если это так, как я могу настроить все края так, чтобы они соответствовали тому, что мне нужно?

Ответ №1:

Вы можете перебирать исправления в своем barplot, извлекать ширину и положение и отображать свои значения с помощью plt.plot. Обратите внимание, что это приведет к разрыву, если фрейм данных не отсортирован.

 import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame([[1, 2, 1], [2, 4, 3], [3, 6, 1], [4, 8, 3]], columns=["X", "Value", "Hor"])
fig, ax = plt.subplots()
sns.barplot(x="X", y="Value", data=df, color='green', ax=ax)

for ix, a in enumerate(ax.patches):
    
    x_start = a.get_x()
    width = a.get_width()
    
    ax.plot([x_start, x_start width], 2*[df.loc[ix, 'Hor']], '--', c='k')
 

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

Комментарии:

1. Это выглядит великолепно! По какой-то непонятной (для меня :)) причине в моих фактических данных я получаю ошибку, потому что ix переходит к значению, которое на единицу больше, чем строки фрейма данных. Я знаю, что на это, вероятно, сложно ответить, но у меня будет даже малейший намек на то, почему это может быть?

2. да, трудно сказать на расстоянии. Вы должны сгенерировать такое же количество столбцов, как и строк в вашем фрейме данных. Это число, в свою очередь, определяет, насколько высоко ix оно будет.

3. Ну что ж, я думаю, это останется для меня загадкой. Я добавил разрыв (к моему стыду!). Спасибо!

Ответ №2:

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

 import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame([[1, 2, 1], [2, 4, 3], [3, 6, 1], [4, 8, 3]], columns=["X", "Value", "Hor"])

fig, ax = plt.subplots()
sns.barplot(x="X", y="Value", data=df, color='green', ax=ax)

# iterate over range of number of rows
for i in range(len(df)):
    ax.hlines(y = df.Hor[i], xmin = i-0.5, xmax = i 0.5,
              color = 'black')
 

Когда вы строите гистограммы, координаты x начинаются с нуля для первого столбца с шагом в единицу. Эта информация может быть использована для назначения xmin и xmax для ax.hlines , здесь в форме i , которая идет от нуля до количества строк вашего фрейма данных минус один. Вы можете настроить 0.5 в соответствии с вашими потребностями, в зависимости от «ширины» желаемой линии.

Результирующий график