|
13 | 13 | from mpl_toolkits.axes_grid1.inset_locator import inset_axes |
14 | 14 |
|
15 | 15 |
|
16 | | -def rank_regulon_groups_dotplot(grn_adata_filtered, adata_regl, original_cluster_column = 'leiden', new_cluster_column = 'leiden_remap', n_genes=10, key="wilcoxon", cmap='bwr', figsize=(25, 2), values_to_plot="scores", return_fig = True): |
| 16 | +def rank_regulon_groups_dotplot(grn_adata_filtered, adata_regl, original_cluster_column = 'leiden', new_cluster_column = 'leiden_remap', n_genes=10, key="wilcoxon", cmap='bwr', figsize=(25, 2), values_to_plot="scores", return_fig = True, var_group_rotation=0): |
17 | 17 | """_summary_ |
18 | 18 |
|
19 | 19 | Function will throw and error if original cluster column and new cluster are not the same. |
@@ -56,7 +56,8 @@ def rank_regulon_groups_dotplot(grn_adata_filtered, adata_regl, original_cluster |
56 | 56 | fractions.index = [x.replace('_nonzero', '') for x in fractions.index] |
57 | 57 |
|
58 | 58 | # return fig needs to be true: get plot, modify sizes, then plot or return |
59 | | - pp = sc.pl.rank_genes_groups_dotplot(adata_regl, n_genes=n_genes, key=key, groupby=new_cluster_column, cmap=cmap, figsize=figsize, values_to_plot=values_to_plot, return_fig = True) |
| 59 | + pp = sc.pl.rank_genes_groups_dotplot(adata_regl, n_genes=n_genes, key=key, groupby=new_cluster_column, cmap=cmap, figsize=figsize, values_to_plot=values_to_plot, return_fig=True, var_group_rotation =var_group_rotation) |
| 60 | + print(pp) |
60 | 61 | fractions = fractions.reindex(list(pp.dot_size_df.index)) |
61 | 62 |
|
62 | 63 | pp.dot_size_df = fractions.loc[:, pp.dot_color_df.columns] |
@@ -88,42 +89,76 @@ def get_grn_from_regulon(regulon_df, full_name, top_n=20): |
88 | 89 | return nx.from_pandas_edgelist(subset, 'source', 'target', create_using=nx.DiGraph()) |
89 | 90 |
|
90 | 91 | def draw_inset_graph(parent_ax, G, orientation='x'): |
91 | | - """Handles the geometry of the marginal GRN plots.""" |
92 | | - bbox = (0.0, -0.45, 1.0, 0.3) if orientation == 'x' else (-0.45, 0.0, 0.3, 1.0) |
| 92 | + # Pushing the bbox further (to -0.5) to avoid any overlap with the axis frame |
| 93 | + if orientation == 'x': |
| 94 | + bbox = (0.0, -0.52, 1.0, 0.35) |
| 95 | + else: |
| 96 | + bbox = (-0.52, 0.0, 0.35, 1.0) |
| 97 | + |
93 | 98 | ax_ins = inset_axes(parent_ax, width="100%", height="100%", loc='center', |
94 | | - bbox_to_anchor=bbox, bbox_transform=parent_ax.transAxes) |
| 99 | + bbox_to_anchor=bbox, bbox_transform=parent_ax.transAxes, borderpad=0) |
95 | 100 |
|
96 | | - pos = nx.spring_layout(G, k=1.5, seed=42) |
97 | | - nx.draw_networkx(G, pos, ax=ax_ins, node_size=200, node_color='#a8dadc', |
98 | | - edge_color='#457b9d', alpha=0.7, font_size=7, font_weight='bold') |
| 101 | + if len(G) > 0: |
| 102 | + pos = nx.kamada_kawai_layout(G) |
| 103 | + |
| 104 | + # Logic for 2-node graphs to keep edges from looking like infinite lines |
| 105 | + if len(G) <= 3: |
| 106 | + ax_ins.set_xlim(-2.5, 2.5) |
| 107 | + ax_ins.set_ylim(-2.5, 2.5) |
| 108 | + else: |
| 109 | + x_values, y_values = zip(*pos.values()) |
| 110 | + x_r, y_r = max(x_values) - min(x_values), max(y_values) - min(y_values) |
| 111 | + ax_ins.set_xlim(min(x_values) - x_r*0.4, max(x_values) + x_r*0.4) |
| 112 | + ax_ins.set_ylim(min(y_values) - y_r*0.4, max(y_values) + y_r*0.4) |
| 113 | + |
| 114 | + nx.draw_networkx_edges(G, pos, ax=ax_ins, edge_color='#bdc3c7', alpha=0.4, width=0.8) |
| 115 | + nx.draw_networkx_nodes(G, pos, ax=ax_ins, node_size=100, node_color='#f8f9fa', |
| 116 | + edgecolors='#34495e', linewidths=0.5) |
| 117 | + nx.draw_networkx_labels(G, pos, ax=ax_ins, font_size=7, font_weight='bold', clip_on=False) |
| 118 | + |
99 | 119 | ax_ins.axis('off') |
100 | 120 |
|
101 | | -def plot_regulon_comparison(adata, regulon_table, regulons, cluster_key='leiden_remap'): |
102 | | - """ |
103 | | - The 'One-Liner' function. |
104 | | - Pass it the adata, the big regulon table, and the two strings. |
105 | | - """ |
| 121 | +def plot_regulon_comparison(adata, regulon_table, regulons, cluster_key='leiden_remap', palette=None, show_legend=True): |
106 | 122 | # 1. Prepare Scatter Data |
107 | 123 | df = pd.DataFrame(adata[:, regulons].X.copy(), columns=regulons) |
108 | 124 | df['group'] = adata.obs[cluster_key].values |
109 | 125 |
|
110 | | - # 2. Build Graphs automatically from the names |
| 126 | + # 2. Build Graphs |
111 | 127 | G_x = get_grn_from_regulon(regulon_table, regulons[0]) |
112 | 128 | G_y = get_grn_from_regulon(regulon_table, regulons[1]) |
113 | 129 |
|
114 | 130 | # 3. Plotting |
115 | | - fig, ax = plt.subplots(figsize=(9, 9)) |
116 | | - plt.subplots_adjust(left=0.25, bottom=0.25) |
| 131 | + fig, ax = plt.subplots(figsize=(4, 4)) |
| 132 | + |
| 133 | + # Increase margins significantly to accommodate external GRNs and titles |
| 134 | + plt.subplots_adjust(top=0.82, right=0.82, left=0.18, bottom=0.18) |
117 | 135 |
|
118 | | - sns.scatterplot(data=df, x=regulons[0], y=regulons[1], hue='group', ax=ax, s=20, alpha=0.5) |
| 136 | + sns.scatterplot( |
| 137 | + data=df, x=regulons[0], y=regulons[1], hue='group', |
| 138 | + palette=palette, ax=ax, s=20, alpha=0.5, legend=show_legend |
| 139 | + ) |
119 | 140 |
|
| 141 | + # Draw Insets with extra clearance |
120 | 142 | draw_inset_graph(ax, G_x, 'x') |
121 | 143 | draw_inset_graph(ax, G_y, 'y') |
122 | 144 |
|
123 | | - # Clean up aesthetics |
124 | | - sns.despine(ax=ax) |
125 | | - ax.legend(title='Cluster', bbox_to_anchor=(1.05, 1), loc='upper left') |
| 145 | + # 4. Move Labels and Shrink Ticks |
| 146 | + ax.xaxis.set_label_position('top') |
| 147 | + ax.yaxis.set_label_position('right') |
| 148 | + |
| 149 | + # Shrink the numbers on the axes |
| 150 | + ax.tick_params(axis='both', which='major', labelsize=7) |
126 | 151 |
|
| 152 | + # 5. Legend Styling |
| 153 | + if show_legend: |
| 154 | + ax.legend( |
| 155 | + title=cluster_key, bbox_to_anchor=(1.2, 1), loc='upper left', |
| 156 | + fontsize=6, title_fontsize=7, frameon=False |
| 157 | + ) |
| 158 | + elif ax.get_legend(): |
| 159 | + ax.get_legend().remove() |
| 160 | + |
| 161 | + sns.despine(ax=ax) |
127 | 162 | return fig, ax |
128 | 163 |
|
129 | 164 |
|
|
0 commit comments