MoraxCheng commited on
Commit
9fff9fd
·
1 Parent(s): a0e970b

Enhance scoring matrix visualization with dynamic font and figure sizing based on mutation range

Browse files
Files changed (1) hide show
  1. app.py +54 -13
app.py CHANGED
@@ -145,6 +145,21 @@ def create_scoring_matrix_visual(scores,sequence,image_index=0,mutation_range_st
145
  filtered_scores=filtered_scores[filtered_scores.position.isin(range(mutation_range_start,mutation_range_end+1))]
146
  piv=filtered_scores.pivot(index='position',columns='target_AA',values='avg_score').round(4)
147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  # Save CSV file
149
  csv_path = 'fitness_scoring_substitution_matrix_{}_{}.csv'.format(unique_id, image_index)
150
 
@@ -174,11 +189,22 @@ def create_scoring_matrix_visual(scores,sequence,image_index=0,mutation_range_st
174
  csv_df.to_csv(csv_path, index=False)
175
 
176
  # Continue with visualization
177
- mutation_range_len = mutation_range_end - mutation_range_start + 1
178
- # Limit figure size to prevent memory issues
179
- fig_width = min(50, len(AA_vocab) * 0.8)
180
- fig_height = min(mutation_range_len, 50)
181
- fig, ax = plt.subplots(figsize=(fig_width, fig_height))
 
 
 
 
 
 
 
 
 
 
 
182
  scores_dict = {}
183
  valid_mutant_set=set(filtered_scores.mutant)
184
  ax.tick_params(bottom=True, top=True, left=True, right=True)
@@ -195,27 +221,42 @@ def create_scoring_matrix_visual(scores,sequence,image_index=0,mutation_range_st
195
  scores_dict[mutant] = float(score_value)
196
  else:
197
  scores_dict[mutant]=0.0
198
- labels = (np.asarray(["{} \n {:.4f}".format(symb,value) for symb, value in scores_dict.items() ])).reshape(mutation_range_len,len(AA_vocab))
 
 
 
 
 
 
 
199
  heat = sns.heatmap(piv,annot=labels,fmt="",cmap='RdYlGn',linewidths=0.30,ax=ax,vmin=np.percentile(scores.avg_score,2),vmax=np.percentile(scores.avg_score,98),\
200
  cbar_kws={'label': 'Log likelihood ratio (mutant / starting sequence)'},annot_kws={"size": fontsize})
201
  else:
202
  heat = sns.heatmap(piv,cmap='RdYlGn',linewidths=0.30,ax=ax,vmin=np.percentile(scores.avg_score,2),vmax=np.percentile(scores.avg_score,98),\
203
  cbar_kws={'label': 'Log likelihood ratio (mutant / starting sequence)'},annot_kws={"size": fontsize})
204
- heat.figure.axes[-1].yaxis.label.set_size(fontsize=int(fontsize*1.5))
205
- heat.set_title("Higher predicted scores (green) imply higher protein fitness",fontsize=fontsize*2, pad=40)
206
- heat.set_ylabel("Sequence position", fontsize = fontsize*2)
207
- heat.set_xlabel("Amino Acid mutation", fontsize = fontsize*2)
 
 
 
 
 
208
 
209
  # Set y-axis labels (positions)
 
210
  yticklabels = [str(pos)+' ('+sequence[pos-1]+')' for pos in range(mutation_range_start,mutation_range_end+1)]
211
- heat.set_yticklabels(yticklabels, fontsize=fontsize, rotation=0)
212
 
213
  # Set x-axis labels (amino acids) - ensuring correct number
214
- heat.set_xticklabels(list(AA_vocab), fontsize=fontsize)
215
  try:
216
  plt.tight_layout()
217
  image_path = 'fitness_scoring_substitution_matrix_{}_{}.png'.format(unique_id, image_index)
218
- plt.savefig(image_path,dpi=100)
 
 
219
  return image_path, csv_path
220
  finally:
221
  plt.close('all') # Ensure all figures are closed
 
145
  filtered_scores=filtered_scores[filtered_scores.position.isin(range(mutation_range_start,mutation_range_end+1))]
146
  piv=filtered_scores.pivot(index='position',columns='target_AA',values='avg_score').round(4)
147
 
148
+ # Calculate dynamic font size based on matrix dimensions
149
+ mutation_range_len = mutation_range_end - mutation_range_start + 1
150
+
151
+ # Adjust font size based on number of positions
152
+ if mutation_range_len > 30:
153
+ fontsize = 8
154
+ elif mutation_range_len > 20:
155
+ fontsize = 10
156
+ elif mutation_range_len > 15:
157
+ fontsize = 12
158
+ elif mutation_range_len > 10:
159
+ fontsize = 14
160
+ else:
161
+ fontsize = 16
162
+
163
  # Save CSV file
164
  csv_path = 'fitness_scoring_substitution_matrix_{}_{}.csv'.format(unique_id, image_index)
165
 
 
189
  csv_df.to_csv(csv_path, index=False)
190
 
191
  # Continue with visualization
192
+ # Adjust figure size based on content
193
+ if mutation_range_len <= 10:
194
+ fig_width = max(12, len(AA_vocab) * 0.6)
195
+ fig_height = max(8, mutation_range_len * 0.8)
196
+ elif mutation_range_len <= 20:
197
+ fig_width = max(14, len(AA_vocab) * 0.5)
198
+ fig_height = max(10, mutation_range_len * 0.6)
199
+ else:
200
+ fig_width = max(16, len(AA_vocab) * 0.4)
201
+ fig_height = max(12, mutation_range_len * 0.5)
202
+
203
+ # Limit maximum size
204
+ fig_width = min(fig_width, 30)
205
+ fig_height = min(fig_height, 40)
206
+
207
+ _, ax = plt.subplots(figsize=(fig_width, fig_height))
208
  scores_dict = {}
209
  valid_mutant_set=set(filtered_scores.mutant)
210
  ax.tick_params(bottom=True, top=True, left=True, right=True)
 
221
  scores_dict[mutant] = float(score_value)
222
  else:
223
  scores_dict[mutant]=0.0
224
+ # Format labels based on available space
225
+ if fontsize <= 10:
226
+ # For small fonts, show only score
227
+ labels = (np.asarray(["{:.2f}".format(value) for _, value in scores_dict.items() ])).reshape(mutation_range_len,len(AA_vocab))
228
+ else:
229
+ # For larger fonts, show mutation and score
230
+ labels = (np.asarray(["{} \n{:.3f}".format(symb,value) for symb, value in scores_dict.items() ])).reshape(mutation_range_len,len(AA_vocab))
231
+
232
  heat = sns.heatmap(piv,annot=labels,fmt="",cmap='RdYlGn',linewidths=0.30,ax=ax,vmin=np.percentile(scores.avg_score,2),vmax=np.percentile(scores.avg_score,98),\
233
  cbar_kws={'label': 'Log likelihood ratio (mutant / starting sequence)'},annot_kws={"size": fontsize})
234
  else:
235
  heat = sns.heatmap(piv,cmap='RdYlGn',linewidths=0.30,ax=ax,vmin=np.percentile(scores.avg_score,2),vmax=np.percentile(scores.avg_score,98),\
236
  cbar_kws={'label': 'Log likelihood ratio (mutant / starting sequence)'},annot_kws={"size": fontsize})
237
+ # Adjust label sizes proportionally
238
+ cbar_label_size = max(10, fontsize * 1.2)
239
+ title_size = max(14, fontsize * 1.5)
240
+ axis_label_size = max(12, fontsize * 1.3)
241
+
242
+ heat.figure.axes[-1].yaxis.label.set_size(fontsize=cbar_label_size)
243
+ heat.set_title("Higher predicted scores (green) imply higher protein fitness",fontsize=title_size, pad=20)
244
+ heat.set_ylabel("Sequence position", fontsize = axis_label_size)
245
+ heat.set_xlabel("Amino Acid mutation", fontsize = axis_label_size)
246
 
247
  # Set y-axis labels (positions)
248
+ tick_label_size = max(8, fontsize * 0.8)
249
  yticklabels = [str(pos)+' ('+sequence[pos-1]+')' for pos in range(mutation_range_start,mutation_range_end+1)]
250
+ heat.set_yticklabels(yticklabels, fontsize=tick_label_size, rotation=0)
251
 
252
  # Set x-axis labels (amino acids) - ensuring correct number
253
+ heat.set_xticklabels(list(AA_vocab), fontsize=tick_label_size)
254
  try:
255
  plt.tight_layout()
256
  image_path = 'fitness_scoring_substitution_matrix_{}_{}.png'.format(unique_id, image_index)
257
+ # Increase DPI for better quality when font is small
258
+ dpi = 150 if fontsize <= 10 else 100
259
+ plt.savefig(image_path, dpi=dpi, bbox_inches='tight')
260
  return image_path, csv_path
261
  finally:
262
  plt.close('all') # Ensure all figures are closed