I'm trying to plot a line graph and a heatmap on a dual axis plot. This is what I'm getting:
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()
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)
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()
[*] 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With