Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Align line graph to xticks on dual axis plot with heatmap

I'm trying to plot a line graph and a heatmap on a dual axis plot. This is what I'm getting:

enter image description here

As you can see, the line graph isn't aligned to the xticks due to the presence of the heatmap, which centers the xticks. How can I shift the line graph to the right by 0.5 so that the data points on the line graph correctly correspond to the xticks?

Below is my code:

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()
like image 633
Ernest Li Avatar asked Sep 05 '25 09:09

Ernest Li


2 Answers

Below is one way of doing it.

Explanation: The twin axis instance ax2 has only one line plotted using sns.lineplot. You extract that line object first. Then you just update (shift) the x-data of that line to the right by 0.5 as you wanted. The line.get_xdata() returns you an array of x-values and you simply add 0.5 in a vectorized manner followed by applying the changes using line.set_xdata. Add the following lines after your sns.lineplot() command.

line = ax2.lines[0] # get the line
line.set_xdata(line.get_xdata() + 0.5)

enter image description here

like image 162
Sheldore Avatar answered Sep 08 '25 10:09

Sheldore


The problem is not the lineplot, it's the heatmap which shows ticks at the wrong positions[*]. You may directly use a matplotlib imshow plot instead, where everything works correctly.

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()

enter image description here


[*] By "wrong position" I mean that the ticks do not appear at the position on the axes that they seem to label. I.e. the data units of the ticks are not identical to the values shown in the labels.

In case of the heatmap being plotted to ax, printing

print(*ax.get_xticklabels())

results in

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')

Here you can see that the first ticklabel is positionned at x=0.5, but shows '0' as label. I.e. all positions are shifted by 0.5 compared to their labels.

In case of the imshow plot, (after drawing the plot, f.canvas.draw()), the printed labels are

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')

Here labels and positions are consistent.

like image 32
ImportanceOfBeingErnest Avatar answered Sep 08 '25 10:09

ImportanceOfBeingErnest