Я пытаюсь построить линейный график и тепловую карту на двухосевом графике. Это то, что я получаю:
Как вы можете видеть, линейный график не привязан к xticks из-за наличия карты нагрева, которая центрирует стрелки. Как перенести линейный график вправо на 0,5, чтобы точки данных на линейном графике правильно соответствовали xticks?
Ниже мой код:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
data1 = np.random.random((10, 10))
data2 = np.random.random((10))
f, ax = plt.subplots(figsize=(11, 9))
plt.tick_params(bottom='on')
ax = sns.heatmap(data1, cmap=sns.color_palette("Greens", 5))
ax2 = plt.twinx()
sns.lineplot(data=data2, linewidth=5, ax=ax2)
ax.axis('tight')
plt.show()
Ниже приведен один из способов сделать это.
Объяснение: экземпляр с двумя осями ax2
имеет только одну строчку, построенную с использованием sns.lineplot
. Сначала вы извлекаете этот объект line
. Затем вы просто обновляете (сдвигаете) x-данные этой строки вправо на 0.5
как вы хотели. line.get_xdata()
возвращает вам массив значений x, и вы просто добавляете 0.5
в векторном виде, а затем применяете изменения, используя line.set_xdata
. Добавьте следующие строки после команды sns.lineplot()
.
line = ax2.lines[0] # get the line
line.set_xdata(line.get_xdata() + 0.5)
Проблема заключается не в линейном графике, а в тепловой карте, показывающей тики в неправильных положениях [*]. Вместо этого вы можете использовать график matplotlib imshow, где все работает правильно.
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
data1 = np.random.random((10, 10))
data2 = np.random.random((10))
f, ax = plt.subplots(figsize=(11, 9))
plt.tick_params(bottom='on')
im = ax.imshow(data1, cmap=plt.get_cmap("Greens",5), aspect="auto")
f.colorbar(im)
ax2 = plt.twinx()
sns.lineplot(data=data2, linewidth=5, ax=ax2)
ax.axis('tight')
plt.show()
[*] Под "неправильной позицией" я имею в виду, что тики не появляются в позиции на осях, которые, по-видимому, маркируются. То есть единицы данных тиков не идентичны значениям, указанным на этикетках.
В случае, если карта нагрева нанесена на ax
, печать
print(*ax.get_xticklabels())
приводит к
Text(0.5, 0, '0') Text(1.5, 0, '1') Text(2.5, 0, '2') Text(3.5, 0, '3') Text(4.5, 0, '4') Text(5.5, 0, '5') Text(6.5, 0, '6') Text(7.5, 0, '7') Text(8.5, 0, '8') Text(9.5, 0, '9')
Здесь вы можете видеть, что первая метка метки позиционируется в x=0.5
, но показывает '0'
качестве метки. Т.е. все позиции сдвинуты на 0,5 по сравнению с их метками.
В случае imshow
(после рисования графика, f.canvas.draw()
), напечатанные ярлыки
Text(-2.0, 0, '-2') Text(0.0, 0, '0') Text(2.0, 0, '2') Text(4.0, 0, '4') Text(6.0, 0, '6') Text(8.0, 0, '8') Text(10.0, 0, '10')
Здесь метки и позиции согласованы.
im = ax.imshow(data1, cmap=plt.get_cmap("Greens",5), aspect="auto")
без рисования линии в вашем коде, отметки по-прежнему отображаются в тех же позициях, что и в график, созданный с использованием sns.heatmap
, т. е. центрированные sns.heatmap