I am making some data analysis in Python, and I am using Seaborn for visualization. Seaborn works very nice for creating heatmaps.
I am trying to underline the maximum values for each column in my heatmap.
I was able to correctly highlight the text in the maximum cells by making them italic and bold. Still, I found no way to underline it.
This is an example of my code:
data_matrix = < extract my data and put them into a matrix >
max_in_each_column = np.max(data_matrix, axis=0)
sns.heatmap(data_matrix,
mask=data_matrix == max_in_each_column,
linewidth=0.5,
annot=True,
xticklabels=my_x_tick_labels,
yticklabels=my_y_tick_labels,
cmap="coolwarm_r")
sns.heatmap(data_matrix,
mask=data_matrix != max_in_each_column,
annot_kws={"style": "italic", "weight": "bold"},
linewidth=0.5,
annot=True,
xticklabels=my_x_tick_labels,
yticklabels=my_y_tick_labels,
cbar=False,
cmap="coolwarm_r")
Of course I have tried using argumentannot_kws={"style": "underlined"}
, but apparently in Seaborn the "style" key only supports values "normal", "italic" or "oblique".
Is there a workaround to this?
Yes, you can workaround your problem using tex commands within your texts. The basic idea is that you use the annot
key of seaborn.heatmap
to assign an array of strings as text labels. These contain your data values + some tex prefixes/suffixes to allow tex making them bold/emphasized (italic)/underlined or whatsoever.
An example (with random numbers):
# random data
data_matrix = np.round(np.random.rand(10, 10), decimals=2)
max_in_each_column = np.max(data_matrix, axis=0)
# Activating tex in all labels globally
plt.rc('text', usetex=True)
# Adjust font specs as desired (here: closest similarity to seaborn standard)
plt.rc('font', **{'size': 14.0})
plt.rc('text.latex', preamble=r'\usepackage{lmodern}')
# remains unchanged
sns.heatmap(data_matrix,
mask=data_matrix == max_in_each_column,
linewidth=0.5,
annot=True,
cmap="coolwarm_r")
# changes here
sns.heatmap(data_matrix,
mask=data_matrix != max_in_each_column,
linewidth=0.5,
# Use annot key with np.array as value containing strings of data + latex
# prefixes/suffices making the bold/italic/underline formatting
annot=np.array([r'\textbf{\emph{\underline{' + str(data) + '}}}'
for data in data_matrix.ravel()]).reshape(
np.shape(data_matrix)),
# fmt key must be empty, formatting error otherwise
fmt='',
cbar=False,
cmap="coolwarm_r")
plt.show()
Further explanation the annotation array:
# For all matrix_elements in your 2D data array (2D requires the .ravel() and .reshape()
# stuff at the end) construct in sum a 2D data array consisting of strings
# \textbf{\emph{\underline{<matrix_element>}}}. Each string will be represented by tex as
# a bold, italic and underlined representation of the matrix_element
np.array([r'\textbf{\emph{\underline{' + str(data) + '}}}'
for data in data_matrix.ravel()]).reshape(np.shape(data_matrix))
The resulting plot is basically what you wanted: