From 04c18c001f574419c7dc0f2219dc4e35cedbf90d Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Sep 2023 18:04:27 +0800 Subject: [PATCH 1/9] Add export functionality to text mining table --- callbacks/text_mining/callbacks.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/callbacks/text_mining/callbacks.py b/callbacks/text_mining/callbacks.py index 80dae07f..78b5ab0b 100644 --- a/callbacks/text_mining/callbacks.py +++ b/callbacks/text_mining/callbacks.py @@ -1,4 +1,4 @@ -from dash import Input, Output, State, ctx, ALL, html, no_update +from dash import Input, Output, State, ctx, ALL, html, no_update, dcc from dash.exceptions import PreventUpdate from .util import * @@ -144,3 +144,15 @@ def display_text_mining_results(text_mining_is_submitted, homepage_submitted, te ) def reset_table_filters(*_): return '' + + @app.callback( + Output('text-mining-download-df-to-csv', 'data'), + Input('text-mining-export-table', 'n_clicks'), + State('text-mining-result-table', 'data'), + ) + def download_text_mining_table_to_csv(download_n_clicks, text_mining_df, ): + if download_n_clicks >= 1: + df = pd.DataFrame(text_mining_df) + return dcc.send_data_frame(df.to_csv, f'Text Mining Analysis Table.csv', index=False) + + raise PreventUpdate \ No newline at end of file From 625e70e047094f185fceb34aed83eb6a5d4431e3 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Sep 2023 18:12:58 +0800 Subject: [PATCH 2/9] Rename disabling of button function name --- callbacks/text_mining/callbacks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/callbacks/text_mining/callbacks.py b/callbacks/text_mining/callbacks.py index 78b5ab0b..f47a237a 100644 --- a/callbacks/text_mining/callbacks.py +++ b/callbacks/text_mining/callbacks.py @@ -92,7 +92,7 @@ def display_coexpression_output(text_mining_is_submitted): State('text-mining-query', 'value'), Input('text-mining-result-table', 'data'), ) - def trigger(n_clicks, text_mining_query, *_): + def disable_text_mining_button_upon_run(n_clicks, text_mining_query, *_): is_there_error, _ = is_error(text_mining_query) if is_there_error: From 9a8a862091ae0e126da5eea93ccd127f08ec2125 Mon Sep 17 00:00:00 2001 From: memgonzales Date: Mon, 4 Sep 2023 19:43:00 +0800 Subject: [PATCH 3/9] Add more error checking for genomic interval --- callbacks/lift_over/util.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/callbacks/lift_over/util.py b/callbacks/lift_over/util.py index d003be2e..21dcc0d6 100644 --- a/callbacks/lift_over/util.py +++ b/callbacks/lift_over/util.py @@ -8,6 +8,8 @@ from ..general_util import * from ..links_util import * +import regex as re + Genomic_interval = namedtuple('Genomic_interval', ['chrom', 'start', 'stop']) @@ -122,6 +124,12 @@ def to_genomic_interval(genomic_interval_str): if is_one_digit_chromosome(chrom): chrom = pad_one_digit_chromosome(chrom) + # Change 'chr' to 'Chr' + chrom = re.sub(r'chr', 'Chr', chrom, flags=re.IGNORECASE) + + if not chrom.startswith('Chr') or not chrom[3].isdigit(): + return errors['NO_CHROM_INTERVAL_SEP'].code, genomic_interval_str + except ValueError: return errors['NO_CHROM_INTERVAL_SEP'].code, genomic_interval_str From 849e09c80ca74e8bf9c5ddd7bf5c7717c9dc8e79 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Sep 2023 19:44:40 +0800 Subject: [PATCH 4/9] Disable button upon computation in lift over --- callbacks/lift_over/callbacks.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/callbacks/lift_over/callbacks.py b/callbacks/lift_over/callbacks.py index 52d9c74c..99c29b33 100644 --- a/callbacks/lift_over/callbacks.py +++ b/callbacks/lift_over/callbacks.py @@ -1,4 +1,4 @@ -from dash import Input, Output, State, dcc, html +from dash import Input, Output, State, dcc, html, ctx from dash.exceptions import PreventUpdate from .util import * @@ -53,6 +53,16 @@ def display_lift_over_output(lift_over_is_submitted): else: return {'display': 'none'} + @app.callback( + Output('lift-over-submit', 'disabled'), + + Input('lift-over-submit', 'n_clicks'), + Input('lift-over-results-table', 'data'), + Input('lift-over-results-statistics', 'children') + ) + def disable_text_mining_button_upon_run(n_clicks, *_): + return ctx.triggered_id == 'lift-over-submit' and n_clicks > 0 + @app.callback( Output('lift-over-results-intro', 'children'), Output('lift-over-results-tabs', 'children'), From 5a7e8f6d6fd70e98fc9e5ec4eae1e4f3ae743435 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Sep 2023 20:00:06 +0800 Subject: [PATCH 5/9] Rename callback function for disabling button in lift ove --- callbacks/lift_over/callbacks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/callbacks/lift_over/callbacks.py b/callbacks/lift_over/callbacks.py index 99c29b33..c63645f3 100644 --- a/callbacks/lift_over/callbacks.py +++ b/callbacks/lift_over/callbacks.py @@ -60,7 +60,7 @@ def display_lift_over_output(lift_over_is_submitted): Input('lift-over-results-table', 'data'), Input('lift-over-results-statistics', 'children') ) - def disable_text_mining_button_upon_run(n_clicks, *_): + def disable_lift_over_button_upon_run(n_clicks, *_): return ctx.triggered_id == 'lift-over-submit' and n_clicks > 0 @app.callback( From 25bac1affed90d553fd889c856c9e95198ddad57 Mon Sep 17 00:00:00 2001 From: memgonzales Date: Mon, 4 Sep 2023 20:07:40 +0800 Subject: [PATCH 6/9] Fix formatting of genomci interval tooltip --- pages/homepage.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pages/homepage.py b/pages/homepage.py index d70ef634..e0e6674d 100644 --- a/pages/homepage.py +++ b/pages/homepage.py @@ -20,16 +20,14 @@ html.Span('Enter genomic intervals like so: '), html.Span( 'Chr01:100000-200000', className='text-muted'), html.Br(), - html.Span( - 'Multiple intervals should be separated by a semicolon like so: '), - html.Span('Chr01:100000-200000;Chr02:300000-400000', - className='text-muted'), - html.Br(), - html.Span( + html.P([ + html.Span( + 'Multiple intervals should be separated by a semicolon like so: '), + html.Span('Chr01:100000-200000;Chr02:300000-400000', + className='text-muted') + ]), + html.P( 'These intervals are obtained from LD-based clumping of significant GWAS SNPs or from QTL mapping studies.'), - html.Br(), - html.Br(), - html.P( 'We also provide some sample genomic intervals, taken from the following GWAS/QTL analyses:'), html.Ul([ @@ -65,7 +63,8 @@ ])], id='genomic-interval-modal', is_open=False, - size='xl' + size='xl', + scrollable=True ) # ====== From ccc9c052fa94255675061faed0d21fdf810329e2 Mon Sep 17 00:00:00 2001 From: memgonzales Date: Mon, 4 Sep 2023 21:14:43 +0800 Subject: [PATCH 7/9] Finish description of algorithms --- pages/analysis/co_expr.py | 142 +++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 64 deletions(-) diff --git a/pages/analysis/co_expr.py b/pages/analysis/co_expr.py index 9d9c1a95..2e08f766 100644 --- a/pages/analysis/co_expr.py +++ b/pages/analysis/co_expr.py @@ -5,72 +5,85 @@ from callbacks.coexpression.util import * -coach = html.Li( - [html.B('COACH'), - html.Span( +coach = html.Li([ + html.B('COACH'), + html.Span( ' Detects highly connected gene subnetworks (referred to as "cores") and expands them by including closely associated genes', className='algo-desc'), - html.Div([ - html.Span( + html.Div([ + html.Span( 'Wu, M., Li, X., Kwoh, C. K., & Ng, S. K. (2009). A core-attachment based method to detect protein complexes in PPI networks. '), - html.I('BMC Bioinformatics, 10'), - html.Span('(169). '), - html.A('https://doi.org/10.1186/1471-2105-10-169', - href='https://doi.org/10.1186/1471-2105-10-169', - target='_blank')], - className='reference' - )] -) + html.I('BMC Bioinformatics, 10'), + html.Span('(169). '), + html.A( + 'https://doi.org/10.1186/1471-2105-10-169', + href='https://doi.org/10.1186/1471-2105-10-169', + target='_blank') + ], className='reference') +]) -demon = html.Li( - [html.B('DEMON'), - html.Span( +demon = html.Li([ + html.B('DEMON'), + html.Span( ' Adopts a bottom-up approach where genes "vote" to determine the subnetwork to which connected genes belong', className='algo-desc'), - html.Div([ - html.Span( + html.Div([ + html.Span( 'Coscia, M., Rossetti, G., Giannotti, F., & Pedreschi, D. (2012). DEMON: A local-first discovery method for overlapping communities. In '), - html.I('KDD\'12: Proceedings of the 18th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining '), - html.Span('(pp. 615–623). Association for Computing Machinery. '), - html.A('https://doi.org/10.1145/2339530.2339630', - href='https://doi.org/10.1145/2339530.2339630', - target='_blank')], - className='reference' - )] -) + html.I('KDD\'12: Proceedings of the 18th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining '), + html.Span('(pp. 615–623). Association for Computing Machinery. '), + html.A( + 'https://doi.org/10.1145/2339530.2339630', + href='https://doi.org/10.1145/2339530.2339630', + target='_blank') + ], className='reference') +]) -clusterone = html.Li( - [html.B('ClusterONE'), - html.Span( +clusterone = html.Li([ + html.B('ClusterONE'), + html.Span( ' Forms cohesive gene subnetworks from an initial set of seed genes. ', className='algo-desc'), - html.Div([ - html.Span( + html.Div([ + html.Span( 'Nepusz, T., Yu, H., & Paccanaro, A. (2012). Detecting overlapping protein complexes in protein-protein interaction networks. '), - html.I('Nature Methods, 9, '), - html.Span('471–472. '), - html.A('https://doi.org/10.1038/nmeth.1938', - href='https://doi.org/10.1038/nmeth.1938', - target='_blank')], - className='reference' - )], -) + html.I('Nature Methods, 9, '), + html.Span('471–472. '), + html.A( + 'https://doi.org/10.1038/nmeth.1938', + href='https://doi.org/10.1038/nmeth.1938', + target='_blank') + ], className='reference') +]) -fox = html.Li([html.B('FOX'), - html.Span( - ' Determines the membership of a gene to a subnetwork by counting the number of triangles formed by the gene with other genes in the subnetwork', - className='algo-desc'), +fox = html.Li([ + html.B('FOX'), + html.Span( + ' Determines the membership of a gene to a subnetwork by counting the number of triangles formed by the gene with other genes in the subnetwork', + className='algo-desc'), html.Div([ html.Span( - 'Lyu, T., Bing, L., Zhang, Z., & Zhang, Y. (2020). FOX: Fast overlapping community detection algorithm in big weighted networks. '), + 'Lyu, T., Bing, L., Zhang, Z., & Zhang, Y. (2020). FOX: Fast overlapping community detection algorithm in big weighted networks. '), html.I('ACM Transactions on Social Computing, 3'), html.Span('(3), 1–23. '), - html.A('https://doi.org/10.1145/3404970', - href='https://doi.org/10.1145/3404970', - target='_blank')], - className='reference mb-3', - ), - html.Span('RicePilaf uses LazyFox for a parallelized implementation of FOX') + html.A( + 'https://doi.org/10.1145/3404970', + href='https://doi.org/10.1145/3404970', + target='_blank') + ], className='reference mb-3'), + html.Span( + 'RicePilaf uses LazyFox for a parallelized implementation of FOX.', + className='algo-desc'), + html.Div([ + html.Span( + 'Garrels, T., Khodabakhsh, A., Renard, B. Y., & Baum, K. (2023). LazyFox: Fast and parallelized overlapping community detection in large graphs. '), + html.I('PeerJ Computer Science, 9, '), + html.Span('e1291. '), + html.A( + 'https://doi.org/10.7717/peerj-cs.1291', + href='https://doi.org/10.7717/peerj-cs.1291', + target='_blank') + ], className='reference mb-3') ]) module_detection_algo_modal = dbc.Modal([ @@ -86,7 +99,8 @@ ])], id='coexpression-clustering-algo-modal', is_open=False, - size='xl' + size='xl', + scrollable=True ) @@ -123,19 +137,19 @@ html.Div([ html.P( [ - 'In this page, you can search for modules (a.k.a. communities, clusters) in rice co-expression networks, ' - 'which are significantly enriched in the genes implicated by your GWAS. ' - 'Likely functions of the modules are inferred by enrichment analysis against several ontologies and pathway databases. Click ', - dcc.Link( - ['here ', html.I( - id='demo-link', - className='fa-solid fa-up-right-from-square fa-2xs' - )], - href='https://github.com/bioinfodlsu/rice-pilaf/wiki/2.3-Co%E2%80%90expression-Network-Analysis', - target='_blank', - className='top-navbar-item' - ), - ' for user guide.' + 'In this page, you can search for modules (a.k.a. communities, clusters) in rice co-expression networks, ' + 'which are significantly enriched in the genes implicated by your GWAS. ' + 'Likely functions of the modules are inferred by enrichment analysis against several ontologies and pathway databases. Click ', + dcc.Link( + ['here ', html.I( + id='demo-link', + className='fa-solid fa-up-right-from-square fa-2xs' + )], + href='https://github.com/bioinfodlsu/rice-pilaf/wiki/2.3-Co%E2%80%90expression-Network-Analysis', + target='_blank', + className='top-navbar-item' + ), + ' for user guide.' ] ) From bc860d15decb2430732a9ad394da943d971229f4 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Sep 2023 21:17:21 +0800 Subject: [PATCH 8/9] Disable button upon computation in coexpression --- callbacks/coexpression/callbacks.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/callbacks/coexpression/callbacks.py b/callbacks/coexpression/callbacks.py index d4e84740..de51a9eb 100644 --- a/callbacks/coexpression/callbacks.py +++ b/callbacks/coexpression/callbacks.py @@ -1,4 +1,4 @@ -from dash import Input, Output, State, html, dcc +from dash import Input, Output, State, html, dcc, ctx from dash.exceptions import PreventUpdate from collections import namedtuple @@ -90,6 +90,17 @@ def display_coexpression_output(coexpression_is_submitted): else: return {'display': 'none'} + + @app.callback( + Output('coexpression-submit', 'disabled'), + + Input('coexpression-submit', 'n_clicks'), + Input('coexpression-module-graph', 'elements'), + Input('coexpression-pathways', 'data'), + Input('coexpression-module-stats', 'children') + ) + def disable_coexpression_button_upon_run(n_clicks, *_): + return ctx.triggered_id == 'coexpression-submit' and n_clicks > 0 @app.callback( Output('coexpression-parameter-slider', 'marks'), From 072b86b6105ccc2f86b0109bfba1e6187d1e5dc6 Mon Sep 17 00:00:00 2001 From: memgonzales Date: Mon, 4 Sep 2023 21:21:45 +0800 Subject: [PATCH 9/9] Add information on thread count and queue size for running LazyFox --- pages/analysis/co_expr.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pages/analysis/co_expr.py b/pages/analysis/co_expr.py index 2e08f766..4a2a7148 100644 --- a/pages/analysis/co_expr.py +++ b/pages/analysis/co_expr.py @@ -4,6 +4,10 @@ from callbacks.constants import Constants from callbacks.coexpression.util import * +# ============================ +# Module Detection Algorithms +# ============================ + coach = html.Li([ html.B('COACH'), @@ -72,7 +76,7 @@ target='_blank') ], className='reference mb-3'), html.Span( - 'RicePilaf uses LazyFox for a parallelized implementation of FOX.', + 'RicePilaf uses LazyFox for a parallelized implementation of FOX. LazyFox is run with the queue size and thread count set to 20.', className='algo-desc'), html.Div([ html.Span( @@ -103,10 +107,14 @@ scrollable=True ) +# ====================== +# Coexpression Networks +# ====================== + coexpression_network_modal = dbc.Modal([ dbc.ModalHeader( - dbc.ModalTitle('Module Detection Algorithms') + dbc.ModalTitle('Coexpression Networks') ), dbc.ModalBody([ html.P(