DingWB / PyComplexHeatmap

PyComplexHeatmap: A Python package to plot complex heatmap (clustermap)
https://dingwb.github.io/PyComplexHeatmap/
MIT License
295 stars 32 forks source link

Add ylim to anno_scatterplot #33

Open Laolga opened 1 year ago

Laolga commented 1 year ago

Hi! Could you please advice how to add ylim to anno_scatterplot?

DingWB commented 1 year ago

As for now, you can get the annotation for anno_scatterplot and set the ylim, for example:

ann=col_ha.annotations[0]:
ann.ax.set_ylim([0,1])
Laolga commented 1 year ago

Thanks!

zcfu21 commented 1 year ago

Hi! A similar question in 'anno_barplot': how to set 'yticks' to anno_barplot? I've tried 'row_ha.annotations[0].ax.set_yticks()', but it raises an error ('anno_barplot' object has no attribute 'ax').

DingWB commented 1 year ago

What is your row_ha, row_ha.annotations[0] means the first element of row_ha.annotations, if the barplot is not the first element, please change 0 to the corresponding int number. Why don't you paste all of your code so I can look at and debug it for you?

DingWB commented 1 year ago

According to the source code:

  if axis == 1:
      ax.set_xticks(ticks=np.arange(0.5, self.nrows, 1))
      ax.bar(
          x=np.arange(0.5, self.nrows, 1),
          height=self.plot_data[col].values,
          bottom=base_coordinates,
          color=color,
          **plot_kws
      )
  else:
      ax.set_yticks(ticks=np.arange(0.5, self.nrows, 1))
      ax.barh(
          y=np.arange(0.5, self.nrows, 1),
          width=self.plot_data[col].values,
          left=base_coordinates,
          color=color,
          **plot_kws
      )

You can set custom yticks for column annotations and xticks for row annotations. Why do you want to set_yticks for row annotations? yticks for row annotations should be shared by all annotations and should be a range from 0 to nrows, no need to set yticks for row annotation. @zichufu

Maybe you wanted to set_xticks for row annotations?

zcfu21 commented 1 year ago

Sorry for my unclear descriptions. I want to change the yticks/grids in the column annotation barplot from [0,2.5] to [0,1,2,3] (see the following figure). Is there any way to do this? Thanks you so much.

image
DingWB commented 1 year ago

I would suggest you try: (1). set_ylim and set_yticks (2). ax=col_ha.annotations[0].ax ax.yaxis.set_major_locator(MultipleLocator(1))

Please let me know whether it works or not.

zcfu21 commented 1 year ago

Here are my codes:

with plt.rc_context({'font.sans-serif': ['Arial']}):
    plt.figure(figsize=(15, 15))
    col_ha = HeatmapAnnotation(GeneNums=anno_barplot(df_bar,
                                           height=10,colors='orangered'),legend=True,legend_gap=5,hgap=0.5)
    ax=col_ha.annotations[0].ax
    ax.yaxis.set_major_locator(MultipleLocator(1))
    row_ha = HeatmapAnnotation(
                            selected=anno_label(label_rows,colors=colors_dict,relpos=(0,0.4)),
                            axis=0,verbose=0,orientation='right'
                            )
    cm = ClusterMapPlotter(data=distance_df,top_annotation=col_ha,right_annotation=row_ha,
                           col_split=6, row_split=6, col_split_gap=1,
                           row_cluster_metric='euclidean',
                           col_cluster_metric='euclidean',
                           row_cluster_method='ward',
                           col_cluster_method='ward',
                           row_split_gap=1,label='distance',
                           row_dendrogram=True,col_dendrogram=False,show_rownames=False,show_colnames=True,
                           tree_kws={'row_cmap': 'Dark2'},cmap='Spectral_r',
                           legend_gap=5,legend_hpad=2,legend_vpad=5)
    plt.show()

The error is

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_20932\4202014503.py in <module>
      4                                            height=10,colors='orangered'),legend=True,legend_gap=5,hgap=0.5)
      5     #col_ha.ax.set_yticks([0,1,2,3])
----> 6     ax=col_ha.annotations[0].ax
      7     ax.yaxis.set_major_locator(MultipleLocator(1))
      8 

AttributeError: 'anno_barplot' object has no attribute 'ax'
DingWB commented 1 year ago

please try to put

ax=col_ha.annotations[0].ax
ax.yaxis.set_major_locator(MultipleLocator(1))

after ClusterMapPlotter. Because the axes will be created only after you plot the heatmap.

zcfu21 commented 1 year ago

Ohhh it works. Thank you so much!

DingWB commented 1 year ago

That's great. Your heatmap looks beautiful. Could you please paste your code and heatmap here so that other users will know how to make it work if they have the same question? @zichufu

zcfu21 commented 1 year ago

Sure.

with plt.rc_context({'font.sans-serif': ['Arial']}):
    plt.figure(figsize=(15, 15))
    col_ha = HeatmapAnnotation(GeneNums=anno_barplot(df_bar,
                                           height=10,colors='orangered'),legend=True,legend_gap=5,hgap=0.5)
    row_ha = HeatmapAnnotation(
                            selected=anno_label(label_rows,colors=colors_dict,relpos=(0,0.4)),
                            axis=0,verbose=0,orientation='right'
                            )
    cm = ClusterMapPlotter(data=distance_df,top_annotation=col_ha,right_annotation=row_ha,
                           col_split=6, row_split=6, col_split_gap=1,
                           row_cluster_metric='euclidean',
                           col_cluster_metric='euclidean',
                           row_cluster_method='ward',
                           col_cluster_method='ward',
                           row_split_gap=1,label='distance',
                           row_dendrogram=True,col_dendrogram=False,show_rownames=False,show_colnames=False,
                           tree_kws={'row_cmap': 'Dark2'},cmap='Spectral_r',
                           legend_gap=5,legend_hpad=2,legend_vpad=5)
    ax=col_ha.annotations[0].ax
    ax.yaxis.set_major_locator(MultipleLocator(1)) # set yaxis ticks
    plt.show()

image

DingWB commented 1 year ago

Looks great. A minor suggestion: (1). You can add a parameter extend=True to anno_label, cause I saw the labels in the right annotation overlapped with each other. Please see here for more details.

(2). You can also choose to set relpos=(0,0.5) to set the endpoint of the curve to the center of the text.

(3). To make it more beautiful, you can also choose to plot the custom box around the cluster:

# plot custom spines
for i in range(cm.heatmap_axes.shape[0]):
    for j in range(cm.heatmap_axes.shape[1]):
        if i != j:
            continue
        ax = cm.heatmap_axes[i][j]
        for side in ["top", "right", "left", "bottom"]:
            ax.spines[side].set_visible(True)
            ax.spines[side].set_color('red')
            ax.spines[side].set_linewidth(2)

See here for example. (4). I would like to suggest you decrease the figsize, cause the legend is too small and the heatmap looks very big.

zcfu21 commented 1 year ago

Thanks for your suggestions! It looks better now.