@@ -22,6 +22,8 @@ def apply_uniform_style(fig: go.Figure) -> go.Figure:
2222 margin = {"t" : 40 , "l" : 30 , "r" : 30 , "b" : 30 },
2323 plot_bgcolor = "rgba(0,0,0,0)" , # Fully transparent background
2424 paper_bgcolor = "rgba(0,0,0,0)" ,
25+ # plot_bgcolor="#fff", # Solid white background for plot area
26+ # paper_bgcolor="#fff", # Solid white background for entire figure
2527 font = {"family" : "Arial, sans-serif" , "size" : 14 , "color" : "#2c3e50" },
2628 title_font = {"size" : 16 , "color" : "#34495e" },
2729 xaxis = {
@@ -110,6 +112,94 @@ def generate_knee_plots(data: pd.DataFrame, valid_bcs: list[str]) -> tuple[go.Fi
110112 return apply_uniform_style (fig_knee_1 ), apply_uniform_style (fig_knee_2 )
111113
112114
115+ def barcode_frequency_plots (data : pd .DataFrame , valid_bcs : list [str ]) -> go .Figure :
116+ """
117+ Generate subplots showing barcode frequency vs UMI counts, barcode frequency vs detected genes, and UMI counts vs detected genes.
118+
119+ Args:
120+ data: DataFrame with barcode and cell metrics.
121+ valid_bcs: List of valid barcode strings.
122+
123+ Returns
124+ -------
125+ A Plotly Figure with three subplots.
126+ """
127+ width = 1200
128+ height = 400
129+ opacity = 0.5
130+ # Map is_retained to human-readable cell_type
131+ data ["cell_type" ] = np .where (data ["barcodes" ].isin (valid_bcs ), "Retained Cell" , "Background" )
132+
133+ # Create subplots: 1 row, 3 columns
134+ fig = make_subplots (
135+ rows = 1 ,
136+ cols = 3 ,
137+ subplot_titles = [
138+ "Barcode Frequency vs UMI Counts (All Cells)" ,
139+ "Barcode Frequency vs Detected Genes (All Cells)" ,
140+ "UMI Counts vs Detected Genes (All Cells)" ,
141+ ],
142+ shared_yaxes = False ,
143+ )
144+
145+ # Plot 1 (legend enabled)
146+ for trace in px .scatter (
147+ data ,
148+ x = "corrected_reads" ,
149+ y = "deduplicated_reads" ,
150+ color = "cell_type" ,
151+ color_discrete_map = {"Retained Cell" : "#636EFA" , "Background" : "lightgrey" },
152+ opacity = opacity ,
153+ ).data :
154+ fig .add_trace (trace , row = 1 , col = 1 )
155+
156+ # Plot 2 (legend disabled)
157+ for trace in px .scatter (
158+ data ,
159+ x = "corrected_reads" ,
160+ y = "num_genes_expressed" ,
161+ color = "cell_type" ,
162+ color_discrete_map = {"Retained Cell" : "#636EFA" , "Background" : "lightgrey" },
163+ opacity = opacity ,
164+ ).data :
165+ trace .showlegend = False # Disable legend for this trace
166+ fig .add_trace (trace , row = 1 , col = 2 )
167+
168+ # Plot 3 (legend disabled)
169+ for trace in px .scatter (
170+ data ,
171+ x = "deduplicated_reads" ,
172+ y = "num_genes_expressed" ,
173+ color = "cell_type" ,
174+ color_discrete_map = {"Retained Cell" : "#636EFA" , "Background" : "lightgrey" },
175+ opacity = opacity ,
176+ ).data :
177+ trace .showlegend = False # Disable legend for this trace
178+ fig .add_trace (trace , row = 1 , col = 3 )
179+
180+ fig .update_layout (
181+ width = width ,
182+ height = height ,
183+ legend = {"orientation" : "h" , "yanchor" : "bottom" , "y" : - 0.3 , "xanchor" : "center" , "x" : 0.5 , "title_text" : "" },
184+ margin = {"t" : 60 , "b" : 80 },
185+ title_x = 0.5 ,
186+ )
187+ fig = apply_uniform_style (fig )
188+ # Explicitly reinforce grid lines for all subplots without overriding other style
189+ fig .update_xaxes (showgrid = True , gridcolor = "lightgrey" , linecolor = "#34495e" )
190+ fig .update_yaxes (showgrid = True , gridcolor = "lightgrey" , linecolor = "#34495e" )
191+ # Add axis labels for all three subplots
192+ fig .update_xaxes (title_text = "Barcode frequency" , row = 1 , col = 1 )
193+ fig .update_yaxes (title_text = "UMI Counts" , row = 1 , col = 1 )
194+
195+ fig .update_xaxes (title_text = "Barcode frequency" , row = 1 , col = 2 )
196+ fig .update_yaxes (title_text = "Detected Genes" , row = 1 , col = 2 )
197+
198+ fig .update_xaxes (title_text = "UMI Counts" , row = 1 , col = 3 )
199+ fig .update_yaxes (title_text = "Detected Genes" , row = 1 , col = 3 )
200+ return fig
201+
202+
113203def generate_gene_histogram (data : pd .DataFrame , is_all_cells : bool ) -> go .Figure :
114204 """
115205 Generate a histogram plot of the number of detected genes per cell.
@@ -262,7 +352,7 @@ def generate_SUA_plots(adata: sc.AnnData, is_all_cells: bool) -> tuple[str, str]
262352
263353 # Customize the layout
264354 fig_S_ratio .update_layout (
265- title = "Histogram of Ratio" + title_suffix ,
355+ title = "Histogram of Splicing Ratio" + title_suffix ,
266356 xaxis = {"title" : "(S+A)/(S+U+A) Ratio" },
267357 yaxis = {"title" : "Counts" },
268358 bargap = 0.1 , # Space between bars
@@ -351,94 +441,6 @@ def umi_dedup(data: pd.DataFrame) -> tuple[go.Figure, float]:
351441 return apply_uniform_style (fig_dedup ), mean_dedup_rate
352442
353443
354- def barcode_frequency_plots (data : pd .DataFrame , valid_bcs : list [str ]) -> go .Figure :
355- """
356- Generate subplots showing barcode frequency vs UMI counts, barcode frequency vs detected genes, and UMI counts vs detected genes.
357-
358- Args:
359- data: DataFrame with barcode and cell metrics.
360- valid_bcs: List of valid barcode strings.
361-
362- Returns
363- -------
364- A Plotly Figure with three subplots.
365- """
366- width = 1200
367- height = 400
368- opacity = 0.5
369- # Map is_retained to human-readable cell_type
370- data ["cell_type" ] = np .where (data ["barcodes" ].isin (valid_bcs ), "Retained Cell" , "Background" )
371-
372- # Create subplots: 1 row, 3 columns
373- fig = make_subplots (
374- rows = 1 ,
375- cols = 3 ,
376- subplot_titles = [
377- "Barcode Frequency vs UMI Counts (All Cells)" ,
378- "Barcode Frequency vs Detected Genes (All Cells)" ,
379- "UMI Counts vs Detected Genes (All Cells)" ,
380- ],
381- shared_yaxes = False ,
382- )
383-
384- # Plot 1 (legend enabled)
385- for trace in px .scatter (
386- data ,
387- x = "corrected_reads" ,
388- y = "deduplicated_reads" ,
389- color = "cell_type" ,
390- color_discrete_map = {"Retained Cell" : "#636EFA" , "Background" : "lightgrey" },
391- opacity = opacity ,
392- ).data :
393- fig .add_trace (trace , row = 1 , col = 1 )
394-
395- # Plot 2 (legend disabled)
396- for trace in px .scatter (
397- data ,
398- x = "corrected_reads" ,
399- y = "num_genes_expressed" ,
400- color = "cell_type" ,
401- color_discrete_map = {"Retained Cell" : "#636EFA" , "Background" : "lightgrey" },
402- opacity = opacity ,
403- ).data :
404- trace .showlegend = False # Disable legend for this trace
405- fig .add_trace (trace , row = 1 , col = 2 )
406-
407- # Plot 3 (legend disabled)
408- for trace in px .scatter (
409- data ,
410- x = "deduplicated_reads" ,
411- y = "num_genes_expressed" ,
412- color = "cell_type" ,
413- color_discrete_map = {"Retained Cell" : "#636EFA" , "Background" : "lightgrey" },
414- opacity = opacity ,
415- ).data :
416- trace .showlegend = False # Disable legend for this trace
417- fig .add_trace (trace , row = 1 , col = 3 )
418-
419- fig .update_layout (
420- width = width ,
421- height = height ,
422- legend = {"orientation" : "h" , "yanchor" : "bottom" , "y" : - 0.3 , "xanchor" : "center" , "x" : 0.5 , "title_text" : "" },
423- margin = {"t" : 60 , "b" : 80 },
424- title_x = 0.5 ,
425- )
426- fig = apply_uniform_style (fig )
427- # Explicitly reinforce grid lines for all subplots without overriding other style
428- fig .update_xaxes (showgrid = True , gridcolor = "lightgrey" , linecolor = "#34495e" )
429- fig .update_yaxes (showgrid = True , gridcolor = "lightgrey" , linecolor = "#34495e" )
430- # Add axis labels for all three subplots
431- fig .update_xaxes (title_text = "Barcode frequency" , row = 1 , col = 1 )
432- fig .update_yaxes (title_text = "UMI Counts" , row = 1 , col = 1 )
433-
434- fig .update_xaxes (title_text = "Barcode frequency" , row = 1 , col = 2 )
435- fig .update_yaxes (title_text = "Detected Genes" , row = 1 , col = 2 )
436-
437- fig .update_xaxes (title_text = "UMI Counts" , row = 1 , col = 3 )
438- fig .update_yaxes (title_text = "Detected Genes" , row = 1 , col = 3 )
439- return fig
440-
441-
442444def mitochondria_plot (adata : sc .AnnData , is_all_cells : bool ) -> go .Figure :
443445 """
444446 Generate a violin plot for mitochondrial content in cells.
@@ -712,7 +714,7 @@ def show_quant_log_table(quant_json_data: dict, permit_list_json_data: dict | No
712714 quant_table_content += f"{ table_row } <td>{ accordion_content } </td></tr>"
713715 else :
714716 # Directly display the content for other cases
715- quant_table_content += f"{ table_row } <td>{ quant_json_data [key_lv1 ]} </td></tr>"
717+ quant_table_content += f"{ table_row } <td>{ str ( quant_json_data [key_lv1 ]) } </td></tr>"
716718
717719 # Create Permit List Table
718720 if permit_list_json_data :
@@ -743,7 +745,6 @@ def generate_summary_table(
743745 median_genes_per_cell: Median number of genes per retained cell.
744746 mapping_rate: Fraction of reads mapped to reference, or None.
745747 seq_saturation_value: Sequencing saturation percentage.
746- export_summary_table: Boolean flag indicating whether to save the summary table as a CSV file.
747748
748749 Returns
749750 -------
0 commit comments