mwaskom / seaborn

Statistical data visualization in Python
https://seaborn.pydata.org
BSD 3-Clause "New" or "Revised" License
12.4k stars 1.91k forks source link

How to set label of clustermap to top or left #2658

Closed sebastianwindeck closed 3 years ago

sebastianwindeck commented 3 years ago

I tried to override the default label positions of the heatmap. Without results

sns_plot = sns.clustermap(df_sorted, row_linkage=linkage, col_linkage=linkage, cmap='viridis', linewidths=0.5, figsize=(13, 13), dendrogram_ratio=0.2, cbar_kws={"ticks":range(0,22,2), 'label': label_text}, cbar_pos=(0.15, 0.8, 0.02, 0.18), annot=True)

sns_plot.ax_heatmap.xaxis.set_label_position('top') sns_plot.ax_heatmap.yaxis.set_label_position('left')

Can the clustermap API address label position changes?

mwaskom commented 3 years ago

Can you please share a reproducible example? Thanks!

sebastianwindeck commented 3 years ago

Sure, thank you for the fast answer

import matplotlib.pyplot as plt
import pandas as pd

sns.set_theme()

# Load the brain networks example dataset
df = sns.load_dataset("brain_networks", header=[0, 1, 2], index_col=0)

# Select a subset of the networks
used_networks = [1, 5, 6, 7, 8, 12, 13, 17]
used_columns = (df.columns.get_level_values("network")
                          .astype(int)
                          .isin(used_networks))
df = df.loc[:, used_columns]

# Create a categorical palette to identify the networks
network_pal = sns.husl_palette(8, s=.45)
network_lut = dict(zip(map(str, used_networks), network_pal))

# Convert the palette to vectors that will be drawn on the side of the matrix
networks = df.columns.get_level_values("network")
network_colors = pd.Series(networks, index=df.columns).map(network_lut)

# Draw the full plot
g = sns.clustermap(df.corr(), center=0, cmap="vlag",
                   row_colors=network_colors, col_colors=network_colors,
                   dendrogram_ratio=(.1, .2),
                   cbar_pos=(.02, .32, .03, .2),
                   linewidths=.75, figsize=(12, 13))
g.ax_row_dendrogram.set_visible(False)
### HERE IS THE ISSUE
g.ax_heatmap.xaxis.set_label_position('top')
g.ax_heatmap.yaxis.set_label_position('left')
###
g.fig.suptitle("Test the label on top", y=1.03,x=0.55)
plt.plot()
mwaskom commented 3 years ago

I'm curious about what you're expecting to happen here. I see:

image

The axis labels are set to the top and left of the heatmap axes, just as you asked for. There's other stuff there already, so it looks bad. But the other stuff being there is (presumably) why you're using clustermap.

Can the clustermap API address label position changes?

So this doesn't seem like an API issue, really?

sebastianwindeck commented 3 years ago

I expected that the labels on the ticks are between the heat map and the dendrogram for easy comprehension

mwaskom commented 3 years ago

Thanks for clarifying. It's always good to be clear about your expectations when reporting an issue, especially if you didn't get an explicit error. Otherwise it's really difficult for a maintainer to provide useful help.

To accomplish what you want, you could fiddle with the heatmap axes bounds, e.g.

bbox = g.ax_heatmap.get_position()
space = .02
g.ax_heatmap.set_position([bbox.x0 + space, bbox.y0, bbox.width - space, bbox.height - space])

image

It's not really obvious to me why this makes the comprehension "easier" than when the labels are off to the side that's not occupied by other objects. And I think that adding a lot of whitespace in between the dendrogram and heatmap is both ugly and makes it harder to link the dendrogram branches to the columns/rows of the heatmap. So I don't think that supporting this is something that needs to be added to the clustermap function signature.

sebastianwindeck commented 3 years ago

I'm sorry for the miscommunication, I would like to have the labels 1-1-lh, 1-1-rh, ..., 17-3-rh on the top of the heat map in between the heatmap and the dendrogram, because some people only want to see the dendrogram without focussing on the clustermap, you are right this would be only nice for styling purpose.

mwaskom commented 3 years ago

Hm, if you just want the dendrograms, you can do that with scipy: https://docs.scipy.org/doc/scipy/reference/generated/scipy.cluster.hierarchy.dendrogram.html.

I think this is outside the scope of clustermap so i'm going to close ... but you may want to ask on stackoverflow with an example that's more closely related to what you're actually trying to achieve.

sebastianwindeck commented 3 years ago

Thank you for the recommendation!

YichaoOU commented 1 year ago

here is the solution:

ax.ax_heatmap.yaxis.tick_left()

Nagidrop commented 1 month ago

Also if you want to plot other ticks

# Have all 4 tick positions
ax.ax_heatmap.tick_params(left=True, bottom=True, right=True, top=True,
                          labelleft=True, labelbottom=True, labelright=True, labeltop=True)