Разделить ось x между matplotlib и seaborn - PullRequest
0 голосов
/ 28 августа 2018

У меня есть данные в пандах DataFrame:

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

np.random.seed(786)

df = pd.DataFrame({'a':np.arange(0, 1, 0.05),
                   'b':np.random.rand(20) - .5})

print (df)
       a         b
0   0.00  0.256682
1   0.05 -0.192555
2   0.10  0.393919
3   0.15 -0.113310
4   0.20  0.373855
5   0.25 -0.423764
6   0.30 -0.123428
7   0.35 -0.173446
8   0.40  0.440818
9   0.45 -0.016878
10  0.50  0.055467
11  0.55 -0.165294
12  0.60 -0.216684
13  0.65  0.011099
14  0.70  0.059425
15  0.75  0.145865
16  0.80 -0.019171
17  0.85  0.116984
18  0.90 -0.051583
19  0.95 -0.096527

Я хотел бы построить barplot и добавить вертикальную линию:

plt.figure(figsize=(10,5))
sns.barplot(x = 'a', y = 'b', data = df)
plt.vlines(x = 0.45, ymin = 0, ymax = 0.6, color = 'red', linewidth=5)

Есть проблемы с метками, потому что перекрытие, а также линия должны быть в точке 0.45, установленной около 0 для x axis.

polt

Я пробую много решений от link1 , link2 , link3 , link4 , но по-прежнему не удается правильно установить ось для обоих графиков.

В чем проблема? Возможно ли разделить ось x между графиками?

Ожидаемый результат - правильно выровненная вертикальная линия, а также непересекающиеся отметки по оси x:

pic

Ответы [ 3 ]

0 голосов
/ 28 августа 2018

Ось X на графике является категоричной, поэтому она не имеет значений df.a в реальном масштабе, а только в виде меток. Вы можете изменить, например, df.a[19] = 2 и ничего не изменится, кроме метки последнего такта бара.

Таким образом, категориальная ось означает, что координаты равны 0 для первого бара, 1 для второго и т. Д. ... 19 для последнего.

Тогда мой подход - установить вертикальную линию на xpos * 19 / .95:

plt.vlines(x = .45*19/.95, ymin = 0, ymax = 0.6, color = 'red', linewidth=5)

enter image description here

В общем случае вы можете добавить лямбда-функцию для вычисления преобразования:

f = lambda x: (x-df.a.values[0]) * (df.a.size-1) / (df.a.values[-1] - df.a.values[0])
plt.vlines(x = f(.45), ymin = 0, ymax = 0.6, color = 'red', linewidth=5)

Однако, поскольку df.a.values печатается только в виде меток, он должен идти линейно от начала до конца.

Относительно проблемы с маркировкой по оси X: я просто могу сказать, что она не появляется в моей системе, код для приведенного выше графика идентичен вашему, за исключением вертикальной линии. Возможно, это было введено при выполнении одной попытки vlines за другой.

0 голосов
/ 30 августа 2018

Использование ax.twiny и округление ввода:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
np.random.seed(786)

df = pd.DataFrame({'a':np.round(np.arange(0, 1, 0.05),2),
                   'b':np.round(np.random.rand(20),2) - .5})


plt.figure(figsize=(10,5))
ax = sns.barplot(x = 'a', y = 'b', data = df)
ax.set_xticklabels(ax.get_xticklabels(), rotation=90)
ax2 = ax.twiny()
ax2.vlines(x = 0.45, ymin = 0, ymax = 0.6, color = 'red', linewidth=2)
#ax2.set_visible(False) # this hides the ticks on the top of the plot

enter image description here

0 голосов
/ 28 августа 2018

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

fig = plt.figure()
ax1 = plt.subplot(211)
ax2 = plt.subplot(212, sharex = ax1, sharey = ax1)
...