Skip to main content
 首页 » 编程设计

python之seaborn clustermap : subplots_adjust cancels colour bar relocation

2024年10月01日39artech

我正在尝试使用 seaborn 制作侧面带有颜色条的热图。但是,在我的实际应用案例中,我有很长的列名需要轮换。这需要使用 plt.subplots_adjust,否则标签不适合图像:

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

使用以下最小示例,我发现最后一条命令正在取消颜色条重定位:

#!/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") 

这会产生以下图像:

没有plt.subplots_adjust:

使用 plt.subplots_adjust:

为什么会这样?

这是一个错误吗?

我该怎么做才能让颜色条出现在我想要的位置,并且仍然确保我的旋转颜色标签不会被剪切?

请您参考如下方法:

基于 @ImportanceOfBeingErnest 的建议,我尝试在移动颜色条之前进行调整。这导致了下图:

由于我其实不需要树状图,只需要聚类,所以我可以通过使用树状图框来放置颜色条来获得更令人满意的结果:

#!/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") 

这会生成以下图像:


编辑:plt.tight_layout 也会出现同样的问题。

为了进一步开发我的热图,我想添加带有图例的行颜色(使用 this answer 中提出的方法)。在我的实际应用案例中,图例占用了足够的水平空间,可以从图像中切出。

我想使用 plt.tight_layout 来调整图像。这再次干扰了颜色条的重定位(甚至没有解决剪切图例问题...),如以下示例所示。

#!/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") 

结果如下:

没有plt.tight_layout,最右边的标签被切掉(物种应该是“virginica”):

重新定位颜色条后调用plt.tight_layout:

在重新定位颜色条之前调用plt.tight_layout: