Skip to content

Commit

Permalink
Merge pull request #93 from bioinfodlsu/input
Browse files Browse the repository at this point in the history
Fix display and session of genomic interval and text mining input + Revise code for clearing dcc Store data
  • Loading branch information
memgonzales authored Aug 31, 2023
2 parents 445c74a + 21c05d2 commit 7e33f10
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 76 deletions.
22 changes: 11 additions & 11 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,6 @@

dash.page_container,

# Do NOT place inside session-container.
# Otherwise, the input field for genomic interval will be cleared when submitted.
dcc.Store(
id='homepage-genomic-intervals-saved-input',
storage_type='session'
),

# Session storage
html.Div(
id='session-container',
Expand All @@ -85,6 +78,11 @@
storage_type='session'
),

dcc.Store(
id='homepage-genomic-intervals-saved-input',
storage_type='session'
),

dcc.Store(
id='homepage-genomic-intervals-submitted-input',
storage_type='session'
Expand All @@ -95,6 +93,8 @@
storage_type='session'
),



# ==========
# Lift-over
# ==========
Expand Down Expand Up @@ -208,16 +208,16 @@
id='coexpression-is-submitted',
storage_type='session'
),

# ==============================
# Regulatory Feature Enrichment
# ==============================

dcc.Store(
id='tfbs-saved-input',
storage_type='session'
),

# ==============================
# Regulatory Feature Enrichment
# ==============================

dcc.Store(
id='tfbs-submitted-input',
storage_type='session'
Expand Down
6 changes: 2 additions & 4 deletions callbacks/coexpression/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@

import pandas as pd
import networkx as nx
from scipy.stats import fisher_exact
import statsmodels.stats.multitest as sm
from scipy.stats import fisher_exact, false_discovery_control

from collections import namedtuple

Expand Down Expand Up @@ -219,8 +218,7 @@ def do_module_enrichment_analysis(implicated_gene_ids, genomic_intervals, addl_g
# Add 1 since user-facing module number is one-based
p_values_indices.append(idx + 1)

_, adj_p_values, _, _ = sm.multipletests(
p_values, method='fdr_bh')
adj_p_values = false_discovery_control(p_values, method='bh')
significant_adj_p_values = [(p_values_indices[idx], adj_p_value) for idx, adj_p_value in enumerate(
adj_p_values) if adj_p_value < const.P_VALUE_CUTOFF]
significant_adj_p_values.sort(key=lambda x: x[1])
Expand Down
38 changes: 19 additions & 19 deletions callbacks/homepage/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,24 +58,25 @@ def display_specific_analysis_page(nav_className, analysis_nav_id, analysis_layo
State('homepage-genomic-intervals', 'value'),
Input('homepage-submit', 'n_clicks'),
Input('homepage-genomic-intervals', 'n_submit'),
State('session-container', 'children'),
Input('homepage-reset', 'n_clicks'),
Input('homepage-clear-cache', 'n_clicks'),
prevent_initial_call=True
)
def parse_input(nb_intervals_str, n_clicks, dccStore_children, *_):
def parse_input(nb_intervals_str, n_clicks, n_submit, dccStore_children, *_):
if 'homepage-clear-cache' == ctx.triggered_id:
clear_cache_folder()

if 'homepage-reset' == ctx.triggered_id:
# clear data for items in dcc.Store found in session-container
dccStore_children = get_cleared_dccStore_data(dccStore_children)
dccStore_children = get_cleared_dccStore_data_excluding_some_data(dccStore_children)

return dccStore_children, None, {'display': 'none'}, False, ''

if 'homepage-submit' == ctx.triggered_id and n_clicks >= 1:
if n_submit >= 1 or ('homepage-submit' == ctx.triggered_id and n_clicks >= 1):
if nb_intervals_str:
intervals = lift_over_util.get_genomic_intervals_from_input(
nb_intervals_str)
Expand All @@ -85,8 +86,8 @@ def parse_input(nb_intervals_str, n_clicks, dccStore_children, *_):
{'display': 'block'}, False, nb_intervals_str
else:
# clear data for items in dcc.Store found in session-container
dccStore_children = get_cleared_dccStore_data(
dccStore_children)
dccStore_children = get_cleared_dccStore_data_excluding_some_data(
dccStore_children, 'homepage-genomic-intervals-saved-input')

browse_loci_util.write_igv_tracks_to_file(nb_intervals_str)

Expand Down Expand Up @@ -120,27 +121,26 @@ def get_nipponbare_gene_ids(nb_intervals_str, homepage_is_submitted):
@app.callback(
Output('homepage-genomic-intervals-saved-input',
'data', allow_duplicate=True),
State('homepage-genomic-intervals', 'value'),
Input({'type': 'example-genomic-interval',
'description': ALL}, 'n_clicks'),
Input('homepage-reset', 'n_clicks'),
prevent_initial_call=True
)
def set_input_fields(genomic_intervals, example_genomic_interval_n_clicks, *_):
if all(val == 0 for val in example_genomic_interval_n_clicks):
return ''

if ctx.triggered_id:
if 'homepage-reset' == ctx.triggered_id:
return None

if 'homepage-genomic-intervals' == ctx.triggered_id:
return genomic_intervals

def set_input_fields_with_preset_input(example_genomic_interval_n_clicks):
if ctx.triggered_id and not all(val == 0 for val in example_genomic_interval_n_clicks):
return get_example_genomic_interval(ctx.triggered_id['description'])

raise PreventUpdate


@app.callback(
Output('homepage-genomic-intervals-saved-input',
'data', allow_duplicate=True),
Input('homepage-genomic-intervals', 'value'),
prevent_initial_call=True
)
def set_input_fields(genomic_intervals):
return genomic_intervals


@app.callback(
Output('homepage-results-container', 'style'),
Expand Down
8 changes: 6 additions & 2 deletions callbacks/homepage/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ def clear_cache_folder():
if os.path.exists(const.TEMP):
shutil.rmtree(const.TEMP, ignore_errors=True)

def get_cleared_dccStore_data(dccStore_children):
def get_cleared_dccStore_data_excluding_some_data(dccStore_children, *arg):
for i in range(len(dccStore_children)):
dccStore_children[i]['props']['data'] = ''
dccStore_ID = dccStore_children[i]['props']['id']

if not dccStore_ID in arg:
dccStore_children[i]['props']['data'] = ''

return dccStore_children

def get_example_genomic_interval(description):
Expand Down
24 changes: 17 additions & 7 deletions callbacks/lift_over/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ def display_gene_tables(nb_intervals_str, active_tab, filter_rice_variants, othe
if active_tab == get_tab_id('All Genes'):
all_genes_raw = get_all_genes(other_refs, nb_intervals)

all_genes_raw['OGI'] = get_rgi_orthogroup_link(
mask = (all_genes_raw['OGI'] != NULL_PLACEHOLDER)
all_genes_raw.loc[mask, 'OGI'] = get_rgi_orthogroup_link(
all_genes_raw, 'OGI')
if 'Nipponbare' in all_genes_raw.columns:
mask = (all_genes_raw['Nipponbare'] != NULL_PLACEHOLDER)
Expand Down Expand Up @@ -336,13 +337,16 @@ def display_gene_tables(nb_intervals_str, active_tab, filter_rice_variants, othe
mask = (common_genes_raw['OGI'] != NULL_PLACEHOLDER)
common_genes_raw.loc[mask, 'OGI'] = get_rgi_orthogroup_link(
common_genes_raw, 'OGI')

if 'Nipponbare' in common_genes_raw.columns:
common_genes_raw['Nipponbare'] = get_rgi_genecard_link(
mask = (common_genes_raw['Nipponbare'] != NULL_PLACEHOLDER)
common_genes_raw.loc[mask, 'Nipponbare'] = get_rgi_genecard_link(
common_genes_raw, 'Nipponbare')

for cultivar in other_ref_genomes:
if cultivar in common_genes_raw.columns:
common_genes_raw[cultivar] = get_rgi_genecard_link(
mask = (common_genes_raw[cultivar] != NULL_PLACEHOLDER)
common_genes_raw.loc[mask, cultivar] = get_rgi_genecard_link(
common_genes_raw, cultivar)

common_genes = common_genes_raw.to_dict('records')
Expand All @@ -357,9 +361,12 @@ def display_gene_tables(nb_intervals_str, active_tab, filter_rice_variants, othe
nb_intervals)[0].drop(
['Chromosome', 'Start', 'End', 'Strand'], axis=1)

genes_from_Nb_raw['OGI'] = get_rgi_orthogroup_link(
mask = (genes_from_Nb_raw['OGI'] != NULL_PLACEHOLDER)
genes_from_Nb_raw.loc[mask, 'OGI'] = get_rgi_orthogroup_link(
genes_from_Nb_raw, 'OGI')
genes_from_Nb_raw['Name'] = get_rgi_genecard_link(

mask = (genes_from_Nb_raw['Name'] != NULL_PLACEHOLDER)
genes_from_Nb_raw.loc[mask, 'Name'] = get_rgi_genecard_link(
genes_from_Nb_raw, 'Name')

genes_from_Nb = genes_from_Nb_raw.to_dict('records')
Expand All @@ -376,9 +383,12 @@ def display_gene_tables(nb_intervals_str, active_tab, filter_rice_variants, othe
genes_from_other_ref_raw = get_unique_genes_in_other_ref(
other_ref, nb_intervals)

genes_from_other_ref_raw['OGI'] = get_rgi_orthogroup_link(
mask = (genes_from_other_ref_raw['OGI'] != NULL_PLACEHOLDER)
genes_from_other_ref_raw.loc[mask, 'OGI'] = get_rgi_orthogroup_link(
genes_from_other_ref_raw, 'OGI')
genes_from_other_ref_raw['Name'] = get_rgi_genecard_link(

mask = (genes_from_other_ref_raw['Name'] != NULL_PLACEHOLDER)
genes_from_other_ref_raw.loc[mask, 'Name'] = get_rgi_genecard_link(
genes_from_other_ref_raw, 'Name')

genes_from_other_ref = genes_from_other_ref_raw.to_dict(
Expand Down
60 changes: 31 additions & 29 deletions callbacks/text_mining/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@
from .util import *
from ..lift_over import util as lift_over_util


Text_mining_input = namedtuple(
'Text_mining_input', ['text_mining_query'])


def init_callback(app):

# to display user input interval in the top nav
Expand All @@ -30,19 +25,25 @@ def display_input(nb_intervals_str, homepage_is_submitted, *_):

@app.callback(
Output('text-mining-query-saved-input', 'data', allow_duplicate=True),
State('text-mining-query', 'value'),
Input({'type': 'example-text-mining',
'description': ALL}, 'n_clicks'),
prevent_initial_call=True
)
def set_input_fields(query_string, *_):
if ctx.triggered_id:
if 'text-mining-query' == ctx.triggered_id:
return query_string

def set_input_fields_with_preset_input(example_text_mining_n_clicks):
if ctx.triggered_id and not all(val == 0 for val in example_text_mining_n_clicks):
return ctx.triggered_id['description']

raise PreventUpdate


@app.callback(
Output('text-mining-query-saved-input', 'data', allow_duplicate=True),
Input('text-mining-query', 'value'),
prevent_initial_call=True
)
def set_input_fields(query_string):
return query_string


@app.callback(
Output('text-mining-query', 'value'),
Expand All @@ -52,40 +53,41 @@ def get_input_homepage_session_state(query):
return query

@app.callback(
Output('text-mining-input-error', 'style'),
Output('text-mining-input-error', 'children'),
Output('text-mining-is-submitted', 'data', allow_duplicate=True),
Output('text-mining-query-submitted-input',
'data', allow_duplicate=True),
Input('text-mining-submit', 'n_clicks'),
Input('text-mining-query', 'n_submit'),
State('homepage-is-submitted', 'data'),
State('text-mining-query', 'value'),
prevent_initial_call=True
)
def submit_text_mining_input(text_mining_submitted_n_clicks, homepage_is_submitted, text_mining_query):
if homepage_is_submitted and text_mining_submitted_n_clicks >= 1:
submitted_input = Text_mining_input(
text_mining_query)._asdict()

return True, submitted_input
def submit_text_mining_input(text_mining_submitted_n_clicks, text_mining_query_n_submit, homepage_is_submitted, text_mining_query):
if homepage_is_submitted and (text_mining_submitted_n_clicks >= 1 or text_mining_query_n_submit >= 1):
is_there_error, message = is_error(text_mining_query)

if not is_there_error:
return {'display': 'none'}, message, True, text_mining_query
else:
return {'display': 'block'}, message, False, None

raise PreventUpdate


@app.callback(
Output('text-mining-results-container', 'style'),
Output('text-mining-input-error', 'style'),
Output('text-mining-input-error', 'children'),
State('text-mining-query', 'value'),
Input('text-mining-is-submitted', 'data')
)
def display_text_mining_output(text_mining_query, text_mining_is_submitted):
is_there_error, message = is_error(text_mining_query)
def display_coexpression_output(text_mining_is_submitted):
if text_mining_is_submitted:
if not is_there_error:
return {'display': 'block'}, {'display': 'none'}, message
else:
return {'display': 'none'}, {'display': 'block'}, message
return {'display': 'block'}

else:
return {'display': 'none'}

return {'display': 'none'}, {'display': 'none'}, message

@app.callback(
Output('text-mining-result-table', 'data'),
Expand All @@ -98,7 +100,7 @@ def display_text_mining_output(text_mining_query, text_mining_is_submitted):
)
def display_text_mining_results(text_mining_is_submitted, homepage_submitted, text_mining_query_submitted_input):
if homepage_submitted and text_mining_is_submitted:
query_string = text_mining_query_submitted_input['text_mining_query']
query_string = text_mining_query_submitted_input

is_there_error, _ = is_error(query_string)
if not is_there_error:
Expand Down
10 changes: 7 additions & 3 deletions pages/analysis/text_mining.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,23 @@
dbc.Input(
id='text-mining-query',
type='text',
value=''
value='',
debounce=True,
n_submit=0
),

html.Div([html.Span('Examples:', className='pe-3'),
html.Span('pre-harvest sprouting',
id={'type': 'example-text-mining',
'description': 'pre-harvest sprouting'},
className='sample-genomic-interval'),
className='sample-genomic-interval',
n_clicks=0),
html.Span(',', className='sample-genomic-interval'),
html.Span('anaerobic germination',
id={'type': 'example-text-mining',
'description': 'anaerobic germination'},
className='sample-genomic-interval ms-3')],
className='sample-genomic-interval ms-3',
n_clicks=0)],
className='pt-3'),
html.Br(),

Expand Down
4 changes: 3 additions & 1 deletion pages/homepage.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@
dbc.Input(
id='homepage-genomic-intervals',
type='text',
value=''
value='',
debounce=True,
n_submit=0
),

html.Div([
Expand Down

0 comments on commit 7e33f10

Please sign in to comment.