seaborn clustermap: subplots_adjust cancels colour bar relocation

假装没事ソ 提交于 2021-02-07 20:37:21

问题


I'm trying to make a heatmap with the colour bar on the side using seaborn. However, in my real application case, I have long column names that I rotate. This requires the use of plt.subplots_adjust, otherwise the labels do not fit in the image:

plt.setp(g.ax_heatmap.get_xticklabels(), rotation=90)
plt.subplots_adjust(bottom=0.5)

Using the following minimal example, I found out that this last command was cancelling the colour bar relocation:

#!/usr/bin/env python3

import seaborn as sns
import matplotlib.pyplot as plt

iris = sns.load_dataset("iris")
species = iris.pop("species")
# Make long column names
iris.columns = ["________".join(label.split("_")) for label in iris.columns]


g = sns.clustermap(iris, col_cluster=False, yticklabels=False)
# Relocate colour bar on the side
g.cax.set_position([.15, .2, .03, .45])
plt.setp(g.ax_heatmap.get_xticklabels(), rotation=90)
plt.savefig("/tmp/unadjusted.png")

plt.cla()

g = sns.clustermap(iris, col_cluster=False, yticklabels=False)
g.cax.set_position([.15, .2, .03, .45])
plt.setp(g.ax_heatmap.get_xticklabels(), rotation=90)
# Adjust to have the column labels not cut out
plt.subplots_adjust(bottom=0.5)
plt.savefig("/tmp/adjusted.png")

This results in the following images:

Without plt.subplots_adjust:

With plt.subplots_adjust:

Why does this happen?

Is this a bug?

What can I do to have the colour bar where I want and still be sure that my rotated colour labels will not be cut?


回答1:


Based on a suggestion by @ImportanceOfBeingErnest, I tried to adjust before moving the colour bar. This resulted in the following image:

Since I actually don't want the dendrogram, but just the clustering, I can obtain a more pleasing result by using the dendrogram box to put the colour bar:

#!/usr/bin/env python3

import seaborn as sns
import matplotlib.pyplot as plt

iris = sns.load_dataset("iris")
species = iris.pop("species")
# Make long column names
iris.columns = ["________".join(label.split("_")) for label in iris.columns]

g = sns.clustermap(iris, col_cluster=False, yticklabels=False)
plt.setp(g.ax_heatmap.get_xticklabels(), rotation=90)
# Adjust to have the column labels not cut out
plt.subplots_adjust(bottom=0.5)
g.cax.set_position([.15, .2, .03, .45])
plt.savefig("/tmp/adjusted_before.png")

plt.cla()

g = sns.clustermap(iris, col_cluster=False, yticklabels=False)
plt.setp(g.ax_heatmap.get_xticklabels(), rotation=90)
# Adjust to have the column labels not cut out
plt.subplots_adjust(bottom=0.5)
# Remove the dendrogram (https://stackoverflow.com/a/42418968/1878788)
g.ax_row_dendrogram.set_visible(False)
# Use the dendrogram box to reposition the colour bar
dendro_box = g.ax_row_dendrogram.get_position()
dendro_box.x0 = (dendro_box.x0 + 2 * dendro_box.x1) / 3
g.cax.set_position(dendro_box)
# Move the ticks to the left (https://stackoverflow.com/a/36939552/1878788)
g.cax.yaxis.set_ticks_position("left")
# If we add a label to the colour bar
# (cbar_kws={"label" : "the_label"} in clustermap arguments)
# we also need to move the label
# g.cax.yaxis.set_label_position("left")
plt.savefig("/tmp/adjusted_before_using_row_dendrogram_box.png")

This generates the following image:


Edit: The same issue occurs with plt.tight_layout.

Further developing my heatmap, I wanted to add row colours with legends (using an approach proposed in this answer). In my real application case, the legend takes enough horizontal space to be cut out of the image.

I wanted to use plt.tight_layout to adjust the image. This again interferes with the colour bar relocation (and doesn't even solve the cut legend issue...), as illustrated with the following examples.

#!/usr/bin/env python3

import seaborn as sns
import matplotlib.pyplot as plt

iris = sns.load_dataset("iris")
species = iris.pop("species")
# Make long column names
iris.columns = ["________".join(label.split("_")) for label in iris.columns]


# Associating colours with species
species_list = species.unique()
label_colours = dict(zip(species_list, sns.color_palette("colorblind", len(species_list))))
row_colours = species.map(label_colours)

g = sns.clustermap(iris, col_cluster=False, yticklabels=False, row_colors=row_colours, cbar_kws={"label" : "measure"})
# Adding row colour legend
# https://stackoverflow.com/a/27992943/1878788
for (label, colour) in label_colours.items():
    # Make long label
    g.ax_col_dendrogram.bar(0, 0, color=colour, label="Iris___________________{}".format(label))
g.ax_col_dendrogram.legend(loc="center", ncol=3)
# Rotating column labels
plt.setp(g.ax_heatmap.get_xticklabels(), rotation=90)
# Adjust to have the column labels not cut out
plt.subplots_adjust(bottom=0.5)
# Remove the dendrogram (https://stackoverflow.com/a/42418968/1878788)
g.ax_row_dendrogram.set_visible(False)
# Use the dendrogram box to reposition the colour bar
dendro_box = g.ax_row_dendrogram.get_position()
dendro_box.x0 = (dendro_box.x0 + 2 * dendro_box.x1) / 3
g.cax.set_position(dendro_box)
# Move the ticks and labels to the left (https://stackoverflow.com/a/36939552/1878788)
g.cax.yaxis.set_ticks_position("left")
g.cax.yaxis.set_label_position("left")
plt.savefig("/tmp/with_row_colour_lengend.png")

plt.cla()

g = sns.clustermap(iris, col_cluster=False, yticklabels=False, row_colors=row_colours, cbar_kws={"label" : "measure"})
# Adding row colour legend
# https://stackoverflow.com/a/27992943/1878788
for (label, colour) in label_colours.items():
    # Make long label
    g.ax_col_dendrogram.bar(0, 0, color=colour, label="Iris___________________{}".format(label))
g.ax_col_dendrogram.legend(loc="center", ncol=3)
# Rotating column labels
plt.setp(g.ax_heatmap.get_xticklabels(), rotation=90)
# Adjust to have the column labels not cut out
plt.subplots_adjust(bottom=0.5)
# Remove the dendrogram (https://stackoverflow.com/a/42418968/1878788)
g.ax_row_dendrogram.set_visible(False)
# Use the dendrogram box to reposition the colour bar
dendro_box = g.ax_row_dendrogram.get_position()
dendro_box.x0 = (dendro_box.x0 + 2 * dendro_box.x1) / 3
g.cax.set_position(dendro_box)
# Move the ticks and labels to the left (https://stackoverflow.com/a/36939552/1878788)
g.cax.yaxis.set_ticks_position("left")
g.cax.yaxis.set_label_position("left")
plt.tight_layout()
plt.savefig("/tmp/tight_after.png")

plt.cla()

g = sns.clustermap(iris, col_cluster=False, yticklabels=False, row_colors=row_colours, cbar_kws={"label" : "measure"})
# Adding row colour legend
# https://stackoverflow.com/a/27992943/1878788
for (label, colour) in label_colours.items():
    # Make long label
    g.ax_col_dendrogram.bar(0, 0, color=colour, label="Iris___________________{}".format(label))
g.ax_col_dendrogram.legend(loc="center", ncol=3)
plt.tight_layout()
# Rotating column labels
plt.setp(g.ax_heatmap.get_xticklabels(), rotation=90)
# Adjust to have the column labels not cut out
plt.subplots_adjust(bottom=0.5)
# Remove the dendrogram (https://stackoverflow.com/a/42418968/1878788)
g.ax_row_dendrogram.set_visible(False)
# Use the dendrogram box to reposition the colour bar
dendro_box = g.ax_row_dendrogram.get_position()
dendro_box.x0 = (dendro_box.x0 + 2 * dendro_box.x1) / 3
g.cax.set_position(dendro_box)
# Move the ticks and labels to the left (https://stackoverflow.com/a/36939552/1878788)
g.cax.yaxis.set_ticks_position("left")
g.cax.yaxis.set_label_position("left")
plt.savefig("/tmp/tight_before.png")

This results in the following figures:

Without plt.tight_layout, the right-most label is cut (the species should be "virginica"):

Calling plt.tight_layout after relocating the colour bar:

Calling plt.tight_layout before relocating the colour bar:



来源:https://stackoverflow.com/questions/47350879/seaborn-clustermap-subplots-adjust-cancels-colour-bar-relocation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!