1

I would like to plot several heatmaps side by side, with annotations.

For this, I use subplots and I can plot each heatmap in its axes using the ax kwarg.

The issue is when I use xlim : it's applied to the heatmap, but not the annotation :

shifted annotation when using xlim

Here is the code :

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

values = np.random.random((7,24)) # create (7,24) shape array 

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(30,10)) # create 2 columns for subplots

ax1 = sns.heatmap(values, annot=True, ax=ax1) # heatmap with annotation

ax1.set(xlim=(12,22)) # works fine with this line commented
# ax1.set_xlim(12,22)

# ax2 = sns.heatmap(values, annot=True, ax=ax2) # second heatmap

plt.show()

And it gets worse with a second heatmap, because the annotation from the second heatmap are ploted on the first heatmap.

How can I limit x axis to (12,22) while using annotation ?

  • matplotlib 2.2.2
  • seaborn 0.9.0
  • python 3.6.5
CoMartel
  • 3,521
  • 4
  • 25
  • 48
  • 1
    Why don't you mask the part of the heatmap you don't want to include instead of setting xlim? See here for the general approach: https://stackoverflow.com/a/64801510/8881141 – Mr. T Nov 16 '20 at 11:56
  • Adding a mask is indeed a working solution, but feels like a workaround and needs an extra-step, since you need to create the mask AND set xlim sor it to work. I would prefer a less 'hacky' solution :) – CoMartel Nov 16 '20 at 12:24
  • Have you issued a bug ticket? https://github.com/mwaskom/seaborn – Mr. T Nov 17 '20 at 12:53
  • No, but seaborn is in 0.11 now, so that may already have been fixed. I'll have to check that before submitting a ticket. In the meantime, I'll accept your answer – CoMartel Nov 17 '20 at 13:05
  • I have seaborn 0.11.0, and the same bug is visible in my output. – Mr. T Nov 17 '20 at 13:19
  • 1
    Thanks, I issued a bug ticket (https://github.com/mwaskom/seaborn/issues/2358) – CoMartel Nov 18 '20 at 12:55
  • That doesn't seem fair to you : would you had this to your answer ? – CoMartel Nov 18 '20 at 14:05

2 Answers2

1

Why not providing the slice of interest in the first place and relabel the x-axis?

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

np.random.seed(1234)
values = np.random.random((7,24)) # create (7,24) shape array # create (7,24) shape array ) # create (7,24) shape array 

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(21,7)) # create 2 columns for subplots

#full heatmap
sns.heatmap(values, annot=True, ax=ax1) 

#slice of interest
start=12
stop=22
sns.heatmap(values[:, start:stop+1], annot=True, ax=ax2, xticklabels = np.arange(start, stop+1)) # second heatmap

plt.show()

Sample output enter image description here

Mr. T
  • 11,960
  • 10
  • 32
  • 54
1

After posting this issue on seaborn github, here is the official answer :

matplotlib text objects are not automatically clipped when they are placed outside of the axes limits; you can turn that on by passing annot_kws=dict(clip_on=True) to heatmap, though.

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

values = np.random.random((7,24)) # create (7,24) shape array 

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(30,10)) # create 2 columns for subplots

ax1 = sns.heatmap(values, annot=True, ax=ax1, annot_kws=dict(clip_on=True)) # heatmap with annotation

ax1.set(xlim=(12,22)) # works fine with this line commented
# ax1.set_xlim(12,22)

ax2 = sns.heatmap(values, annot=True, ax=ax2, annot_kws=dict(clip_on=True)) # second heatmap
ax2.set(xlim=(12,22))

plt.show()

clip_on=True will remove everithing that is outside the axe

CoMartel
  • 3,521
  • 4
  • 25
  • 48
  • 1
    Very interesting. For future readers, it might be more instructive if one of the subplots were set to `clip_on=False` to emphasize the difference. Embarrassingly, I should have known the solution based on a [previous answer](https://stackoverflow.com/a/51284756/8881141) I got. – Mr. T Nov 18 '20 at 14:45