diff --git a/bin/QC.py b/bin/QC.py
index 0c05a32..5044866 100755
--- a/bin/QC.py
+++ b/bin/QC.py
@@ -6,18 +6,24 @@
from libs.figs import ATGC_graph
from libs.figs import GC_content_plot
from libs.report import make_report
+from libs.reporte_maker import reporter
+import plotly.graph_objects as go
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('-q', '--fastq', action='append', dest='fastq', required=True,
help='FASTQ file (necessary if no sequencing summary file), ' +
'can also be in a tar.gz archive')
+parser.add_argument('-r', "--conf_params", action='append', dest="conf_params", help="config parameters")
+parser.add_argument('-w', "--work_params", action='append', dest="work_params", help="workflow parameters")
+parser.add_argument('-e', "--env", action='append', dest="env", help="packages versions")
+
+parser.add_argument('-s', "--stats", action='store', dest="stats", help="template maker stats")
parser.add_argument('-p', "--positions", action='store', dest="positions", help="Number of base position to show", type=int, default=1000)
parser.add_argument('-t', "--thread", action='store', dest="thread", help="Number of threads", type=int, default=2)
parser.add_argument('-b', "--batch-size", action='store', dest="batch_size", help="Batch size", type=int, default=500)
parser.add_argument('-n', "--project", action='store', dest="project", help="project name", type=str, default="test_project")
args = parser.parse_args()
-
columns = ["pos",
"Q_score",
"GC_content",
@@ -46,6 +52,50 @@ def compQC(fastq, positions, reverse=False):
return df_stats, df_qc, positions, q_scores, q1, q3
+def pie_unknown(df):
+ labels = ['Simulated feature counts','Unknow feature counts']
+ values = [int(df['Simulated UMI counts']),
+ int(df['Unknown transcript counts'])]
+
+ fig = go.Figure(data=[go.Pie(labels=labels, values=values, pull=[0, 0, 0.2, 0])])
+ return fig
+
+
+def create_table(stats_data, table_width=500, table_height=400, margin=10):
+ data=[go.Table(
+ header=dict(
+ values=['', 'Value'],
+ fill_color='#EBEBEB', # Couleur de fond de l'en-tête
+ font=dict(color='black', size=12) # Couleur et taille du texte de l'en-tête
+ ),
+ cells=dict(
+ values=[
+ ['Simulated Cell BC', 'Simulated Filtered-Out', 'Simulated UMI counts', 'Mean UMI per cell'],
+ [
+ stats_data['Simulated Cell BC'],
+ stats_data['Simulated Filtered-Out'],
+ stats_data['Simulated UMI counts'],
+ int(int(stats_data['Simulated UMI counts']) / int(stats_data['Simulated Cell BC']))
+ ]
+ ],
+ fill_color='#f4f4f4', # Couleur de fond des cellules
+ font=dict(color='black', size=11) # Couleur et taille du texte des cellules
+ )
+ )]
+
+ fig = go.Figure(data)
+
+ fig.update_layout(
+ #width=table_width,
+ #height=table_height,
+ margin=dict(l=margin,
+ r=margin,
+ t=20,
+ b=0),
+ )
+ return fig
+
+
def main():
df_stats, df_qc, pos, q_scores, q1, q3 = compQC(args.fastq, args.positions)
df_stats_rev, df_qc_rev, pos_rev, q_scores_rev, q1_rev, q3_rev = compQC(args.fastq, args.positions, reverse=True)
@@ -77,7 +127,21 @@ def main():
gc = GC_content_plot(df_stats['GC_percentage'])
- make_report(Q_over_time, atgc, gc, args.project, args.positions)
+ df_stats = pd.read_csv(args.stats)
+ pie_fig = pie_unknown(df_stats)
+ stats_table = create_table(df_stats)
+
+ #make_report(Q_over_time, atgc, gc, args.project, args.positions)
+ reporter(stats_table,
+ pie_fig,
+ Q_over_time,
+ atgc,
+ gc,
+ args.conf_params,
+ args.work_params,
+ args.project,
+ args.env)
+
if __name__ == "__main__":
main()
diff --git a/bin/libs/css_style.py b/bin/libs/css_style.py
new file mode 100644
index 0000000..b43d707
--- /dev/null
+++ b/bin/libs/css_style.py
@@ -0,0 +1,174 @@
+from dominate.util import raw
+
+def _summary(graphs):
+ """
+ Compose the summary section of the page
+ :param graphs:
+ :return: a string with HTML code for the module list
+ """
+ result = "
\n"
+ return result
+
+
+def div_summary_style(titles):
+ style = """
+
+ """
+ menu = """
+
+
+ {summary_list}
+
+ """.format(summary_list=_summary(titles))
+ html = style+menu
+ return html
+
+
+def head_style():
+ style = raw(f"""
+ body {{ font-family: Arial, sans-serif; }}
+ header {{ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background-color: #EBEBEB;
+ padding: 10px 20px;
+ border-bottom: 1px solid #ddd; }}
+
+ h1.title {{ font-size: 14px; }}
+
+ h1.title2 {{
+ font-size: 16px;
+ max-width: 400px;
+ border-bottom: 2px solid #000000; /* Exemple avec une bordure noire de 2px */
+ padding-bottom: 10px; /* Ajoute un peu d'espace entre le texte et la bordure */
+ }}
+ p.date {{ font-size: 12px;
+ color: #666; }}
+
+ .container {{ display: flex;
+ justify-content: space-between;
+ background-color: #FFFFFF}}
+
+ .content {{ flex: 2;
+ padding: 20px;
+ max-width: 1400px;
+ margin-left: 0;
+ margin-right: auto;
+ }}
+
+ .aside {{ flex: 1; border-right: 1px solid #ddd; padding: 20px; }}
+ .tabs {{ display: flex;
+ margin-top: 20px;
+ margin-bottom: 20px; }}
+
+ .tab-button {{
+ background-color: #f4f4f4;
+ padding: 10px;
+ cursor: pointer;
+ border: none;
+ border-radius: 4px;
+ }}
+
+ .tab-button.active {{
+ background-color: #052F61;
+ color: white;
+ border-radius: 10px;
+ }}
+
+ .tab-content {{ display: none; }}
+ .tab-content.active {{ display: block; }}
+ """)
+ return style
+
+
+def body_style():
+ style = """
+ body {
+ font-family: 'Arial', sans-serif;
+ background-color: #f4f4f4;
+ margin: 0;
+ padding: 0;
+ }
+ .table-container {
+ width: 80%;
+ margin: 50px auto;
+ box-shadow: 0 2px 8px rgba(0,0,0,0.2);
+ }
+ table {
+ width: 100%;
+ font-size: 14px;
+ border-collapse: collapse;
+ background-color: #fff;
+ border-radius: 8px;
+ overflow: hidden;
+ }
+ th, td {
+ padding: 12px 15px;
+ text-align: left;
+ border-bottom: 1px solid #ddd;
+ }
+ th {
+ background-color: #EBEBEB;
+ color: #666;
+
+ }
+ tr:nth-child(even) {
+ background-color: #f2f2f2;
+ }
+ tr:hover {
+ background-color: #e9f1fe;
+ }
+ """
+ return style
\ No newline at end of file
diff --git a/bin/libs/figs.py b/bin/libs/figs.py
index 2af2ef7..a4a61f4 100755
--- a/bin/libs/figs.py
+++ b/bin/libs/figs.py
@@ -249,33 +249,23 @@ def over_time_graph(time_series,
]
)
- # Set minimal value of y axis to 0 if required
y_axis_range_mode = 'tozero' if yaxis_starts_zero else 'normal'
- # Update layout
fig.update_layout(
title=graph_name,
- autosize=False,
- width=1400,
- height=400,
+ autosize=True,
xaxis_title=' Position ',
yaxis_title='' +yaxis_title +'',
hovermode='x unified',
yaxis=dict(rangemode=y_axis_range_mode)
)
- # Set logarithmic scale if required
+
if log:
fig.update_yaxes(type="log")
- # Show the figure
- return fig #.write_html("Qscore_over_positions.html") #fig.show()
+ return fig
- # Dummy return values (modify as needed for your application)
- #table_html = None
- #div = None
- #output_file = None
- #return graph_name, output_file, table_html, div
def ATGC_graph(time_series,
percentage_G,
@@ -292,16 +282,14 @@ def ATGC_graph(time_series,
green_zone_starts_at=None,
green_zone_color=toulligqc_colors['phred_score_over_time']):
- # Apply Gaussian filter to the percentile series
filtered_G = gaussian_filter1d(percentage_G[0], sigma=sigma)
filtered_C = gaussian_filter1d(percentage_C[0], sigma=sigma)
filtered_A = gaussian_filter1d(percentage_A[0], sigma=sigma)
filtered_T = gaussian_filter1d(percentage_T[0], sigma=sigma)
- # Create a Plotly figure
+
fig = go.Figure()
- # Add the 25th percentile trace
fig.add_trace(go.Scatter(
x=time_series[0],
y=filtered_G,
@@ -311,29 +299,24 @@ def ATGC_graph(time_series,
fill=None
))
- # Add the 75th percentile trace
fig.add_trace(go.Scatter(
x=time_series[0],
y=filtered_A,
name="Base A Percentage",
mode='lines',
line=dict(color="green", width=2),
- #fill='tonexty', # Fill the area between this line and the previous line
- #fillcolor='rgba(0, 100, 0, 0.2)' # Semi-transparent fill
))
- # Add the 75th percentile trace
+
fig.add_trace(go.Scatter(
x=time_series[0],
y=filtered_T,
name="Base T Percentage",
mode='lines',
line=dict(color="blue", width=2),
- #fill='tonexty', # Fill the area between this line and the previous line
- #fillcolor='rgba(0, 100, 0, 0.2)' # Semi-transparent fill
+
))
- # Add the 50th percentile (median) trace
fig.add_trace(go.Scatter(
x=time_series[0],
y=filtered_C,
@@ -345,12 +328,11 @@ def ATGC_graph(time_series,
######
### add REVERSE
#####
- # Apply Gaussian filter to the percentile series
filtered_G = gaussian_filter1d(percentage_G[1], sigma=sigma)
filtered_C = gaussian_filter1d(percentage_C[1], sigma=sigma)
filtered_A = gaussian_filter1d(percentage_A[1], sigma=sigma)
filtered_T = gaussian_filter1d(percentage_T[1], sigma=sigma)
- # Add the 25th percentile trace
+
fig.add_trace(go.Scatter(
x=time_series[1].multiply(other = -1),
y=filtered_G,
@@ -361,7 +343,6 @@ def ATGC_graph(time_series,
visible=False
))
- # Add the 75th percentile trace
fig.add_trace(go.Scatter(
x=time_series[1].multiply(other = -1),
y=filtered_A,
@@ -369,11 +350,9 @@ def ATGC_graph(time_series,
mode='lines',
line=dict(color="green", width=2),
visible=False
- #fill='tonexty', # Fill the area between this line and the previous line
- #fillcolor='rgba(0, 100, 0, 0.2)' # Semi-transparent fill
+
))
- # Add the 75th percentile trace
fig.add_trace(go.Scatter(
x=time_series[1].multiply(other = -1),
y=filtered_T,
@@ -381,11 +360,9 @@ def ATGC_graph(time_series,
mode='lines',
line=dict(color="blue", width=2),
visible=False
- #fill='tonexty', # Fill the area between this line and the previous line
- #fillcolor='rgba(0, 100, 0, 0.2)' # Semi-transparent fill
))
- # Add the 50th percentile (median) trace
+
fig.add_trace(go.Scatter(
x=time_series[1].multiply(other = -1),
y=filtered_C,
@@ -407,7 +384,7 @@ def ATGC_graph(time_series,
buttons=list([
dict(
args=[{'visible': [True, True, True, True, False, False, False, False]},
- {**_xaxis('Q score', dict(visible=True)),
+ {**_xaxis('Base percent', dict(visible=True)),
**_yaxis('Position', dict(visible=True)),
'plot_bgcolor': '#e5ecf6'}],
label="Begining ",
@@ -415,7 +392,7 @@ def ATGC_graph(time_series,
),
dict(
args=[{'visible': [False, False, False, False, True, True, True, True]},
- {**_xaxis('Q score', dict(visible=True)),
+ {**_xaxis('Base percent', dict(visible=True)),
**_yaxis('Position', dict(visible=True)),
'plot_bgcolor': '#e5ecf6'}],
label="End",
@@ -431,46 +408,32 @@ def ATGC_graph(time_series,
)
]
)
- # Set minimal value of y axis to 0 if required
+
y_axis_range_mode = 'tozero' if yaxis_starts_zero else 'normal'
- # Update layout
+
fig.update_layout(
title=graph_name,
- autosize=False,
- width=1400,
- height=400,
+ autosize=True,
xaxis_title=' Position ',
yaxis_title= '' + yaxis_title + '',
hovermode='x unified',
yaxis=dict(rangemode=y_axis_range_mode)
)
- # Set logarithmic scale if required
if log:
fig.update_yaxes(type="log")
-
- # Show the figure
- return fig #.write_html("ATGC_graph.html") #fig.show()
-
- # Dummy return values (modify as needed for your application)
- #table_html = None
- #div = None
- #output_file = None
- #return graph_name, output_file, table_html, div
+ return fig
def GC_content_plot(gc_content_percentages):
- # Distribution réelle
- max_gc = 100 # Pourcentage max
+ max_gc = 100
gc_distribution = [0] * (max_gc + 1)
for gc_content in gc_content_percentages:
gc_distribution[int(gc_content)] += 1
- # affichage en ligne
real_distribution_smooth = np.convolve(gc_distribution, np.ones(5)/5, mode='same')
- # Distribution théorique
mean_gc = np.mean(gc_content_percentages)
std_gc = np.std(gc_content_percentages)
theoretical_distribution = [stats.norm.pdf(gc, mean_gc, std_gc) * len(gc_content_percentages) for gc in range(max_gc + 1)]
@@ -480,17 +443,16 @@ def GC_content_plot(gc_content_percentages):
fig.add_trace(go.Scatter(x=list(range(max_gc + 1)), y=real_distribution_smooth, mode='lines', name='Distribution GC réelle'))
fig.add_trace(go.Scatter(x=list(range(max_gc + 1)), y=theoretical_distribution, mode='lines', name='Distribution GC théorique'))
- # Mise en forme
- fig.update_layout(title='Distribution du contenu en GC',
- autosize=False,
- width=1400,
- height=400,
- xaxis_title=' Contenu en GC (%) ',
- yaxis_title=' Compte ',
+ fig.update_layout(title='GC content distribution',
+ autosize=True,
+ #width=1400,
+ #height=400,
+ xaxis_title=' GC content (%) ',
+ yaxis_title=' Count ',
legend_title=' Légende ')
- return fig #fig.write_html("GC_content.html") #.show()
+ return fig
def interpolation_points(series, graph_name):
diff --git a/bin/libs/reporte_maker.py b/bin/libs/reporte_maker.py
new file mode 100644
index 0000000..15f9115
--- /dev/null
+++ b/bin/libs/reporte_maker.py
@@ -0,0 +1,185 @@
+import pandas as pd
+import re
+import dominate
+from dominate.tags import *
+from dominate.util import raw
+from datetime import date, datetime
+from libs.css_style import body_style, head_style, div_summary_style
+
+import plotly.express as px
+df2 = px.data.iris()
+fig = px.scatter(df2, x="sepal_width", y="sepal_length", color='petal_length')
+
+def list_to_dict(params):
+ return {"--"+k: v for k, v in (s.split(":", 1) for s in params) if v != "null"}
+
+
+def string_to_dict(params):
+ params_list = params[0].split(', ')
+ params_list = {k: v for k, v in (s.split(":", 1) for s in params_list) if v != "null"}
+ return params_list
+
+def parse_versions(versions):
+ try:
+ versions_list = {k: v for d, k, v in (re.split(r'(Badread|SPARSim)', s) for s in versions)}
+ except:
+ versions_list = {k:k for k in versions}
+ return versions_list
+
+
+def read_logo(image_path):
+ import base64
+ with open(image_path, "rb") as image_file:
+ encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
+ return encoded_string
+
+def reporter(stats_table, pie_fig, Q_over_time, atgc, gc, conf_params, work_params, project, versions):
+ work_params = string_to_dict(work_params)
+ conf_params = list_to_dict(conf_params)
+
+ versions = parse_versions(versions)
+
+ conf_params.update(work_params)
+
+ conf_params.update(versions)
+
+ df = pd.DataFrame(list(conf_params.items()), columns=['Params', 'Value'])
+
+
+ Basic_inputs_df = df[df['Params'].isin(['--matrix', '--bc_counts', '--transcriptome',
+ '--features', '--gtf', '--sim_celltypes', '--cell_types_annotation',
+ '--error_model', '--fastq_model', '--ref_genome', '--trained_model',
+ '--qscore_model'])]
+
+ simulation_parames_df = df[df['Params'].isin(['--full_length', '--umi_duplication', '--pcr_cycles',
+ '--pcr_error_rate', '--pcr_dup_rate', '--pcr_total_reads',
+ '--badread_identity', '--dT_LENGTH', '--ADPTER_SEQ', '--TSO_SEQ'])]
+
+ run_params_df = df[df['Params'].isin(['container', 'runOptions', 'dsl2', 'startTime', 'threads', 'commandLine'])]
+
+ versions_df = df[df['Params'].isin(['nextflow', 'SPARSim', 'Badread'])]
+
+ doc = dominate.document(title='Styled Table with Tabs')
+ current_date = raw(str(date.today().strftime('%b-%d-%Y'))+'
'+str(datetime.now().strftime('%H:%M:%S')))
+
+ with doc.head:
+ style(head_style())
+
+ with doc.body:
+ style(body_style())
+
+ with doc:
+ with header():
+ with div():
+ h1('AsaruSim v0.1.0', cls='title')
+ p(current_date, cls='date')
+ img_logo = read_logo('asarusim_v2.png')
+ img(src=f'data:image/png;base64,{img_logo}',height='60', alt='Logo', style="float: right;")
+
+ with div(cls='container'):
+ with div():
+ titles = ['Simulation parameters',
+ 'Simulation statistics',
+ 'Qscore over sequence position',
+ 'Base content over position',
+ 'Per base GC content']
+ raw(div_summary_style(titles))
+
+ with div(cls='content'):
+ h1('Simulation parameters', cls='title2')
+ with div(cls='tabs'):
+ button('Basic inputs', cls='tab-button active', onclick="openTab(event, 'tab1')")
+ button('Simulation config', cls='tab-button', onclick="openTab(event, 'tab2')")
+ button('Run parameters', cls='tab-button', onclick="openTab(event, 'tab3')")
+ button('Package versions', cls='tab-button', onclick="openTab(event, 'tab4')")
+
+ with div(style='margin-bottom: 20px; min-height: 300px;'):
+ with div(id='tab1', cls='tab-content active'):
+ with table():
+ with thead():
+ with tr():
+ for col in Basic_inputs_df.columns:
+ th(col)
+ with tbody():
+ for _, row in Basic_inputs_df.iterrows():
+ with tr():
+ for cell in row:
+ td(cell)
+
+ with div(id='tab2', cls='tab-content'):
+ with table():
+ with thead():
+ with tr():
+ for col in simulation_parames_df.columns:
+ th(col)
+ with tbody():
+ for _, row in simulation_parames_df.iterrows():
+ with tr():
+ for cell in row:
+ td(cell)
+
+ with div(id='tab3', cls='tab-content'):
+ with table():
+ with thead():
+ with tr():
+ for col in run_params_df.columns:
+ th(col)
+ with tbody():
+ for _, row in run_params_df.iterrows():
+ with tr():
+ for cell in row:
+ td(cell)
+ with div(id='tab4', cls='tab-content'):
+ with table():
+ with thead():
+ with tr():
+ for col in versions_df.columns:
+ th(col)
+ with tbody():
+ for _, row in versions_df.iterrows():
+ with tr():
+ for cell in row:
+ td(cell)
+
+ h1('Simulation statistics', cls='title2')
+ with div(style='display: flex; justify-content: space-between'):
+ with div(style='max-width: 600px; flex: 2; margin-top: 80px'):
+ raw(stats_table.to_html())
+ with div(style='max-width: 800px; flex: 2'):
+ raw(pie_fig.to_html())
+
+ h1('Read QC', cls='title2')
+ with div(style='margin-bottom: 20px'):
+
+ raw(Q_over_time.to_html())
+ raw(atgc.to_html())
+ raw(gc.to_html())
+
+ with footer():
+ with div(style='font-size: 12px; padding: 10px 20px;;'):
+ app_url="https://alihamraoui.github.io/AsaruSim/introduction/"
+ p(raw(f'Generated by AsaruSim (version 0.1.0)'))
+
+
+ with doc.body:
+ script(raw("""
+ function openTab(evt, tabName) {
+ var i, tabcontent, tablinks;
+ tabcontent = document.getElementsByClassName("tab-content");
+ for (i = 0; i < tabcontent.length; i++) {
+ tabcontent[i].style.display = "none";
+ }
+ tablinks = document.getElementsByClassName("tab-button");
+ for (i = 0; i < tablinks.length; i++) {
+ tablinks[i].className = tablinks[i].className.replace(" active", "");
+ }
+ document.getElementById(tabName).style.display = "block";
+ evt.currentTarget.className += " active";
+ }
+ """))
+ out_name = project+'.html'
+ with open(out_name, 'w') as f:
+ f.write(doc.render())
+
+if __name__ == '__main__':
+ main()
diff --git a/bin/template_maker.py b/bin/template_maker.py
index 85898f3..df72339 100755
--- a/bin/template_maker.py
+++ b/bin/template_maker.py
@@ -39,6 +39,7 @@
parser.add_argument('--adapter', type=str, default="ATGCGTAGTCAGTCATGATC", help="Adapter sequence.")
parser.add_argument('--TSO', type=str, default="ATGCGTAGTCAGTCATGATC", help="TSO sequence.")
parser.add_argument('--len_dT', type=str, default=15, help="Poly-dT sequence.")
+parser.add_argument('--log', type=str, help="Path to the log file CSV.")
class Transcriptome:
@@ -274,6 +275,16 @@ def main():
os.remove(filename)
count_unfiltered_bc = len(unfiltered_bc) if args.unfilteredBC else 0
+
+ if args.log:
+ log_df = {
+ "Simulated Cell BC": len(matrix.columns),
+ "Simulated Filtered-Out": count_unfiltered_bc,
+ "Simulated UMI counts": generator.counter,
+ "Unknown transcript counts": generator.unfound}
+ log_df = pd.DataFrame(log_df, index=[0])
+ log_df.to_csv(args.log, index=False)
+
logging.info("Completed successfully. Have a great day!")
logging.info("Stats : "+
"\nSimulated Cell BC: "+
diff --git a/bin/toolkit.py b/bin/toolkit.py
index e424701..94c489e 100755
--- a/bin/toolkit.py
+++ b/bin/toolkit.py
@@ -103,7 +103,10 @@ def parse_gtf(gtf_file, index_by, protein_coding=False):
transcript_id = attributes['transcript_id']
transcript_type = attributes.get('transcript_biotype', attributes.get('transcript_type', ''))
- index_key = attributes[index_by]
+ if index_by in attributes:
+ index_key = attributes[index_by]
+ else:
+ continue
start = int(columns[3])
end = int(columns[4])
diff --git a/images/asarusim_v2.png b/images/asarusim_v2.png
new file mode 100644
index 0000000..c5c54ea
Binary files /dev/null and b/images/asarusim_v2.png differ
diff --git a/main.nf b/main.nf
index 916965f..015e22f 100755
--- a/main.nf
+++ b/main.nf
@@ -25,6 +25,12 @@ log.info """\
"""
.stripIndent()
+logo_ch = channel.fromPath('./images/asarusim_v2.png')
+config_params_ch = Channel.value(params)
+ .map { p -> p.collect { key, value -> "--conf_params $key:$value" }}
+
+workflow_params_ch = Channel.from(workflow).map { p -> p.collect { value -> "--work_params '$value'" }}
+
include { SUBSAMPLE } from './modules/errorModel.nf'
include { ALIGNMENT } from './modules/errorModel.nf'
include { ERROR_MODLING } from './modules/errorModel.nf'
@@ -83,19 +89,22 @@ workflow {
if (params.sim_celltypes) {
counts_ch = COUNT_SIMULATOR(matrix_ch, cell_types_ch)
- template_ch = TEMPLATE_MAKER(counts_ch, transcriptome_ch, barcodes_ch, gtf_ch, length_dist_ch)
+ TEMPLATE_MAKER(counts_ch, transcriptome_ch, barcodes_ch, gtf_ch, length_dist_ch)
} else {
- template_ch = TEMPLATE_MAKER(matrix_ch, transcriptome_ch, barcodes_ch, gtf_ch, length_dist_ch)
+ TEMPLATE_MAKER(matrix_ch, transcriptome_ch, barcodes_ch, gtf_ch, length_dist_ch)
}
+ template_fa_ch = TEMPLATE_MAKER.out.template
+ template_log_ch = TEMPLATE_MAKER.out.logfile
+
if (params.pcr_cycles > 0) {
- template_ch = PCR_SIMULATOR(template_ch)
+ template_fa_ch = PCR_SIMULATOR(template_fa_ch)
}
- gr_truth_ch = GROUND_TRUTH(template_ch)
- error_ch = ERRORS_SIMULATOR(template_ch, error_model_ch, qscore_model_ch, identity_ch)
- qc_ch = QC(error_ch)
+ gr_truth_ch = GROUND_TRUTH(template_fa_ch)
+ error_ch = ERRORS_SIMULATOR(template_fa_ch, error_model_ch, qscore_model_ch, identity_ch)
+ qc_ch = QC(error_ch, config_params_ch, workflow_params_ch, logo_ch, template_log_ch)
}
workflow.onComplete {
diff --git a/modules/modules.nf b/modules/modules.nf
index 0e00204..1764112 100755
--- a/modules/modules.nf
+++ b/modules/modules.nf
@@ -27,7 +27,8 @@ process TEMPLATE_MAKER {
val length_dist
output:
- path "template.fa"
+ path "template.fa", emit: template
+ path "log.csv", emit: logfile
script:
def gtf = params.features != "transcript_id" ? "--features $params.features --gtf $gtf" : ""
@@ -45,7 +46,8 @@ process TEMPLATE_MAKER {
--len_dT $params.dT_LENGTH \
$full_length \
--length_dist ${length_dist.trim()} \
- -o template.fa
+ -o template.fa \
+ --log log.csv
"""
}
@@ -99,15 +101,28 @@ process GROUND_TRUTH {
process QC {
publishDir params.outdir, mode:'copy'
+ cache false
input:
path fastq
+ val conf_params
+ val work_params
+ path logo
+ path log_csv
output:
path "${params.projetctName}.html"
script:
"""
- python3.11 $projectDir/bin/QC.py -q $fastq -n $params.projetctName
+ bedread_version=\$(echo "-e \$(badread --version | head -n 1)")
+ nextflow_version=\$(echo "-e \$(Rscript -e "ip <- installed.packages()[, c('Package', 'Version')];
+ cat(paste(ip[,1], ip[,2], sep=': '), sep='\n')" | grep SPARSim)")
+
+ python3.11 $projectDir/bin/QC.py -q $fastq --stats $log_csv -n $params.projetctName \
+ ${conf_params.join(' ').replaceAll(/[\(\)\$]/, "")} \
+ ${work_params.join('').replaceAll(/[\(\)\$]/, "")} \
+ "\$bedread_version" \
+ "\$nextflow_version" \
"""
}
\ No newline at end of file