Overlapping yticklabels: Is it possible to control

2019-01-15 16:36发布

问题:

I have a dataset with around 200 observations which I would like to plot as a heatmap. Each observation has a string associated with it which I would like to display. My problem is that I cannot read these labels since they overlap each other. My question is therefore, whether one can somehow set the cell size of the heatmap to the font size of the yticklabel or whether there is any other workaround for that.

In my example below, I use random data for illustration purposes:

import seaborn as sns
import numpy as np
data = np.random.rand(200, 10)
ax = sns.heatmap(data)
for item in ax.get_yticklabels():
    item.set_rotation(0)

which gives me:

Is there a way to make these yticklabels readable? In the ideal case, I would have an option that allows me to set the cells' height to the fontsize of the yticklabels. Is that possible?

EDIT:

As mentioned in the comments, one possibility would be to increase the figure's size. I tried that as follows:

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

data = np.random.rand(200, 10)

fig, ax = plt.subplots()
fig.set_size_inches(38.5, 10.5)

ax2 = sns.heatmap(data, ax=ax)
for item in ax2.get_yticklabels():
    item.set_rotation(0)

This gives me the same output. Am I using it correctly?

回答1:

The only way to make more room for the labels is to increase the height of the matrix. The only other option would be to decrease the font size, but I guess that's not what you want. So you can compute the ideal figure height based on the number of rows in the matrix and the font size of the labels. When you save the resulting plot you get the expected result. It seems that the height of the GUI window which you see when calling plt.show() is limited to the screen height:

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

# create some random data
data = np.random.rand(150, 10)

# get the tick label font size
fontsize_pt = plt.rcParams['ytick.labelsize']
dpi = 72.27

# comput the matrix height in points and inches
matrix_height_pt = fontsize_pt * data.shape[0]
matrix_height_in = matrix_height_pt / dpi

# compute the required figure height 
top_margin = 0.04  # in percentage of the figure height
bottom_margin = 0.04 # in percentage of the figure height
figure_height = matrix_height_in / (1 - top_margin - bottom_margin)


# build the figure instance with the desired height
fig, ax = plt.subplots(
        figsize=(6,figure_height), 
        gridspec_kw=dict(top=1-top_margin, bottom=bottom_margin))

# let seaborn do it's thing
ax = sns.heatmap(data, ax=ax)

# save the figure
plt.savefig('/tmp/test.png')

Result: