Seaborn: Heatmaps can have too long numeric labels

Created on 6 Sep 2016  路  4Comments  路  Source: mwaskom/seaborn

Often times, I have heatmaps like this:

screen shot 2016-09-05 at 9 07 19 pm

I'd like for the numeric labels to be shorter. I eventually found a solution through this SO answer after looking at the source for keywords to google. This solution is nowhere as clean as I'd like.

d = [{'p1': p1, 'p2': p2, 'error': np.random.rand()}
     for p1 in np.logspace(0, 1, num=5)
     for p2 in np.logspace(0, 3, num=5)]

df = pd.DataFrame(d)
df = df.pivot(values='error', index='p1', columns='p2')

ax = sns.heatmap(df)

# format text labels
fmt = '{:0.2f}'
xticklabels = []
for item in ax.get_xticklabels():
    item.set_text(fmt.format(float(item.get_text())))
    xticklabels += [item]
yticklabels = []
for item in ax.get_yticklabels():
    item.set_text(fmt.format(float(item.get_text())))
    yticklabels += [item]

ax.set_xticklabels(xticklabels)
ax.set_yticklabels(yticklabels)

plt.show()

...which produces this plot:

screen shot 2016-09-05 at 9 50 01 pm

Most helpful comment

@stsievert to really make this work with seaborn I had to overwrite the current FixedFormatter like

from matplotlib.ticker import FixedFormatter

ax = sns.heatmap(heat_data)
x_format = ax.xaxis.get_major_formatter()
x_format.seq = ["{:0.0f}".format(float(s)) for s in x_format.seq]
y_format = ax.yaxis.get_major_formatter()
y_format.seq = ["{:0.0f}".format(float(s)) for s in y_format.seq]
ax.xaxis.set_major_formatter(x_format)
ax.yaxis.set_major_formatter(y_format)

and then it worked.

All 4 comments

There's a number of ways to control this sort of thing. The matplotlib solution would be to use a tick formatter. Or you could do

ax = sns.heatmap(df,
                 xticklabels=df.columns.values.round(2),
                 yticklabels=df.index.values.round(2))

ax = sns.heatmap(df, xticklabels=df.columns.values.round(2), yticklabels=df.index.values.round(2))

What if I wanted to use this solution and label every other tick? If I say xticklabels=df.columns.values[::2].round(3), it only labels the first half of dataframe.

I wouldn't mind the ticklabels having some format parameter (that way we're not changing the labels). That was my first thought, and I started working on a PR for it. I'd be okay with saying only apply the tick label if the type of all the labels is numeric.

For reference, below is the mpl solution:

from matplotlib.ticker import FormatStrFormatter

ax = sns.heatmap(df, xticklabels=2)
majorFormatter = FormatStrFormatter('%0.2f')
ax.xaxis.set_major_formatter(majorFormatter)
ax.yaxis.set_major_formatter(majorFormatter)

Yep that solution with the matplotlib formatter is your best bet if you want to also label every other column.

@stsievert to really make this work with seaborn I had to overwrite the current FixedFormatter like

from matplotlib.ticker import FixedFormatter

ax = sns.heatmap(heat_data)
x_format = ax.xaxis.get_major_formatter()
x_format.seq = ["{:0.0f}".format(float(s)) for s in x_format.seq]
y_format = ax.yaxis.get_major_formatter()
y_format.seq = ["{:0.0f}".format(float(s)) for s in y_format.seq]
ax.xaxis.set_major_formatter(x_format)
ax.yaxis.set_major_formatter(y_format)

and then it worked.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

queryous picture queryous  路  4Comments

songololo picture songololo  路  4Comments

ConstantinoSchillebeeckx picture ConstantinoSchillebeeckx  路  4Comments

alexpetralia picture alexpetralia  路  3Comments

rrbarbosa picture rrbarbosa  路  3Comments