Customize Annotation Text in Seaborn Heatmap

Annotations are the numbers or text in a heatmap.

In this tutorial, you’ll learn how to adjust font properties, align text, set colors, or even create effects like text shadows and multi-line text in Seaborn heatmap.

 

 

Display Annotation

You can set the annot parameter to True to display the annotation.

First, let’s import necessary libraries and prepare some sample data:

import seaborn as sns
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(0)
data = np.random.rand(4, 6)
columns = ['A', 'B', 'C', 'D', 'E', 'F']
df = pd.DataFrame(data, columns=columns)
print(df)

Output:

     A         B         C         D         E         F
0  0.548814  0.715189  0.602763  0.544883  0.423655  0.645894
1  0.437587  0.891773  0.963663  0.383442  0.791725  0.528895
2  0.568045  0.925597  0.071036  0.087129  0.020218  0.832620
3  0.778157  0.870012  0.978618  0.799159  0.461479  0.780529

This output shows the randomly generated data in a 4×6 matrix format, ready for visualization.

Next, let’s create a heatmap with annotations:

sns.heatmap(df, annot=True)
plt.show()

Output:

Display Annotation

 

Adjust Font Size

You can use the annot_kws argument with the fontsize parameter to adjust the font size:

sns.heatmap(df, annot=True, annot_kws={"size": 12})
plt.show()

Output:

Adjust Font Size

 

Set the Color

You can use the color parameter within annot_kws to change the annotation color:

sns.heatmap(df, annot=True, annot_kws={"size": 12, "color": "blue"})
plt.show()

Output:

Set the Color

 

Set Font Weight & Font Family

Seaborn allows you to set these attributes easily. Let’s explore how to change the font weight and font family for the annotations in our heatmap.

sns.heatmap(df, annot=True, annot_kws={"size": 12, "color": "blue", "weight": "bold", "family": "serif"})
plt.show()

Output:

Set Font Weight & Font Family

 

Set Font Style

The font style of annotations in a Seaborn heatmap can be adjusted to ‘normal’, ‘italic’, or ‘oblique’, offering further customization options for your data visualization needs.

sns.heatmap(df, annot=True, annot_kws={"size": 12, "color": "blue", "weight": "bold", "family": "serif", "style": "italic"})
plt.show()

Output:

Set Font Style

Alternatively, you can try ‘normal’ or ‘oblique’ styles depending on your preference or the requirements of your data presentation.

 

Set the Alignment

You can align the text to be ‘center’, ‘left’, or ‘right’, depending on your visualization goals.

sns.heatmap(df, annot=True, annot_kws={"size": 12, "color": "blue", "weight": "bold", "family": "serif", "style": "italic", "ha": "center"})
plt.show()

Output:

Set the Alignment

 

Set Background Color

You can use the bbox attribute within annot_kws to set the background color of annotation text:

sns.heatmap(df, annot=True, annot_kws={"size": 12, "color": "blue", "weight": "bold", "family": "serif", "style": "italic", "ha": "center", "bbox": {"facecolor": "yellow", "edgecolor": "black", "boxstyle": "round,pad=0.5"}})
plt.show()

Output:

Set Background Color

In the above output, the background color of each annotation is set to yellow, with black edge color and rounded corners.

 

Rotate Annotation Text

You can use the va and rotation parameters within annot_kws to rotate the annotation text:

sns.heatmap(df, annot=True, annot_kws={"size": 12, "color": "white", "weight": "bold", "family": "serif", "style": "italic", "ha": "center", "va": "center", "rotation": 45, "bbox": {"boxstyle": "round,pad=0.5", "edgecolor": "green", "facecolor": "gray"}})
plt.show()

Output:

Rotate Annotation Text

In this example, the annotations are rotated 45 degrees, making them easier to read in a more confined space.

 

Apply Text Shadows

Seaborn does not provide a direct way to add text shadows, but we can achieve this effect by overlaying annotations with a slight offset.

You can use matplotlib to apply text shadows to annotation text:

plt.figure(figsize=(8, 6))
ax = sns.heatmap(df, annot=False)  # Base heatmap without annotations

# Adding annotations with 'shadow'
for y in range(df.shape[0]):
    for x in range(df.shape[1]):
        plt.text(x + 0.5, y + 0.5, f'{df.iloc[y, x]:.2f}',
                 horizontalalignment='center',
                 verticalalignment='center',
                 fontsize=12,
                 color='grey',
                 weight='bold',
                 rotation=45)
sns.heatmap(df, annot=True, annot_kws={"size": 12, "weight": "bold", "color": "white", "rotation": 45}, cbar=False, ax=ax)

Output:

Apply Text Shadows

In this output, the ‘shadow’ is created by first placing grey text at each cell’s center and then overlaying the actual white annotation on top of it.

 

Text Wrapping (Multi-line Text)

While Seaborn does not directly support multi-line text in annotations, we can implement a workaround by manually splitting the text into multiple lines.

Here’s a method to wrap text into multiple lines:

def wrap_text(text, line_width):
    """ Function to split text into multiple lines based on specified width """
    words = text.split()
    wrapped_text = ''
    current_line = ''
    for word in words:
        if len(current_line + ' ' + word) <= line_width:
            current_line += ' ' + word
        else:
            wrapped_text += current_line.strip() + '\n'
            current_line = word
    wrapped_text += current_line.strip()
    return wrapped_text

# Creating heatmap with multi-line annotations
plt.figure(figsize=(10, 8))
ax = sns.heatmap(df, annot=False)  # Base heatmap without annotations

# Adding wrapped text annotations
for y in range(df.shape[0]):
    for x in range(df.shape[1]):
        text_to_wrap = f"Value: {df.iloc[y, x]:.2f}"
        wrapped_text = wrap_text(text_to_wrap, 10)
        plt.text(x + 0.5, y + 0.5, wrapped_text,
                 horizontalalignment='center',
                 verticalalignment='center',
                 fontsize=10,
                 color="white",
                 weight="bold",
                 rotation=0)
plt.show()

Output:

Text Wrapping

In this example, the wrap_text function splits the annotation text into multiple lines, ensuring that each line does not exceed a specified width.

Leave a Reply

Your email address will not be published. Required fields are marked *