diff --git a/TFinder-v1.py b/TFinder-v1.py index 23670b1d..a8c7642b 100644 --- a/TFinder-v1.py +++ b/TFinder-v1.py @@ -127,9 +127,11 @@ def load_lottiefile(filepath: str): f" - TFinder on [Streamlit](https://streamlit.io/): [https://tfinder-ipmc.streamlit.app/](https://tfinder-ipmc.streamlit.app/)\n" f" - TFinder on [Health Universe](https://www.healthuniverse.com/): [https://apps.healthuniverse.com/nhu-dxv-ktj](https://apps.healthuniverse.com/nhu-dxv-ktj)\n" f" - (BETA) TFinder: [https://tfinder-beta.streamlit.app/](https://tfinder-beta.streamlit.app/)\n") - -if st.secrets['ncbi_error'] == "True": - st.error("⚠ NCBI server maintenance, problems and slowdowns may be observed") +try: + if st.secrets['ncbi_error'] == "True": + st.error("⚠ NCBI server maintenance, problems and slowdowns may be observed") +except Exception as e: + print(e) if chosen_tab == HOME: home_page() @@ -261,8 +263,11 @@ def load_lottiefile(filepath: str): st.markdown( 'TFinder use [NCBI API](https://www.ncbi.nlm.nih.gov/books/NBK25497/#chapter2.Usage_Guidelines_and_Requiremen)' ': More information [NCBI Website and Data Usage Policies and Disclaimers](https://www.ncbi.nlm.nih.gov/home/about/policies/)') - if st.secrets['ncbi_error'] == "True": - st.error("⚠ NCBI server maintenance, problems and slowdowns may be observed") + try: + if st.secrets['ncbi_error'] == "True": + st.error("⚠ NCBI server maintenance, problems and slowdowns may be observed") + except Exception as e: + print(e) st.markdown("TFinder use [JASPAR API](https://doi.org/10.1093/bioinformatics/btx804)") st.markdown('') st.markdown( diff --git a/navigation/aio.py b/navigation/aio.py index c9ca1f72..ff7b5850 100644 --- a/navigation/aio.py +++ b/navigation/aio.py @@ -174,14 +174,14 @@ def aio_page(): with tab1: # Species st.markdown("🔹 :blue[**Step 1.2**] Species of gene names and sliced variants:") - col1, col2, = st.columns(2) - with col1: - species = st.selectbox("🔹 :blue[**Step 1.2**] Select species of gene names:", + col1, col2, col3 = st.columns(3) + species = col1.selectbox("🔹 :blue[**Step 1.2**] Select species of gene names:", ["Human", "Mouse", "Rat", "Drosophila", "Zebrafish"], index=0, label_visibility='collapsed') - with col2: - all_variants = st.toggle('All variant') + all_variants = col2.toggle('All variant') + + gr = col3.selectbox("Genome", ["Current", "Previous"], index=0, help="For human Current is GRCh38 and Previous is GRCh37 for example") # Upstream/Downstream Promoter st.markdown("🔹 :blue[**Step 1.3**] Regulatory region:") @@ -226,7 +226,7 @@ def aio_page(): pbar.progress(i / len(gene_ids), text=f'**:blue[Extract sequence... {gene_id}] ⚠️:red[PLEASE WAIT UNTIL END WITHOUT CHANGING ANYTHING]**') result_promoter_output = NCBIdna(gene_id, prom_term, upstream, downstream, - species, + species, gr, all_slice_forms=True if all_variants else False).find_sequences() if not str(result_promoter_output).startswith('P'): pbar.progress((i + 1) / len(gene_ids), diff --git a/test.py b/test.py new file mode 100644 index 00000000..fd9b9a55 --- /dev/null +++ b/test.py @@ -0,0 +1,168 @@ +import requests +import time + +def get_gene_info(gene_id): + """ + Récupère les informations d'un gène via l'API NCBI Entrez en utilisant l'ID du gène. + """ + url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi" + params = { + "db": "gene", # On cherche dans la base "gene" + "id": gene_id, # ID du gène obtenu via esearch + "retmode": "json" # Retourne le résultat en format JSON + } + + response = requests.get(url, params=params) + + # Vérifier si la requête est réussie + if response.status_code == 200: + print(response.text) + return response.json() + else: + print(f"Erreur : Impossible de récupérer les informations (status code: {response.status_code})") + return None + + +def extract_genomic_info(gene_info): + print(gene_info) + time.sleep(1) + """ + Extrait les NC_, chrstart et chrstop de la réponse JSON. + Ne garde que les accession versions qui partagent la même base avant le point. + """ + accession_dict = {} + + # Extraction depuis la section locationhist + location_hist = gene_info.get('locationhist', []) + if len(location_hist) == 0: + location_hist = gene_info.get('genomicinfo', []) + for loc in location_hist: + nc_accver = loc.get('chraccver') # Extrait le NC_XXXXX.YY + chrstart = loc.get('chrstart') + chrstop = loc.get('chrstop') + print(nc_accver, chrstart, chrstop) + + if nc_accver: + base_accession = nc_accver + if base_accession not in accession_dict: + accession_dict[base_accession] = (chrstart, chrstop) + else: + # Conserver la première occurrence des coordonnées + existing_start, existing_stop = accession_dict[base_accession] + accession_dict[base_accession] = (min(existing_start, chrstart), max(existing_stop, chrstop)) + + print(accession_dict) # Afficher le dictionnaire des NC_ sans les suffixes + return accession_dict + + +def fetch_nc_info(nc_accver): + time.sleep(1) + """ + Récupère les informations détaillées pour un NC_ via l'API NCBI. + """ + url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi" + params = { + "db": "nuccore", + "id": nc_accver, + "retmode": "json" + } + + response = requests.get(url, params=params) + + if response.status_code == 200: + print(response.text) + return response.json() + else: + print(f"Erreur : Impossible de récupérer les informations pour {nc_accver} (status code: {response.status_code})") + return None + + +def main(): + gene_id = input("Entrez l'ID du gène (par ex. 4843 pour NOS2) : ").strip() + + # Étape 1 : Récupérer les informations du gène via son ID + gene_info = get_gene_info(gene_id) + + if gene_info and 'result' in gene_info and gene_id in gene_info['result']: + gene_details = gene_info['result'][gene_id] + print(gene_details) + print(f"Informations pour le gène (ID: {gene_id}):") + + # Étape 2 : Extraire les NC_, chrstart et chrstop + nc_dict = extract_genomic_info(gene_details) + print("\nNC_ Accession, chrstart, chrstop:") + + # Affichage des NC_ et leurs informations de position + for base_accver, (chrstart, chrstop) in nc_dict.items(): + print(f"{base_accver}: chrstart={chrstart}, chrstop={chrstop}") + + # Filtrer pour garder uniquement les entrées qui commencent par "NC_" + nc_dict = {base_accver: (chrstart, chrstop) for base_accver, (chrstart, chrstop) in nc_dict.items() if + base_accver.startswith("NC_")} + + # Si le dictionnaire n'est pas vide, récupérez la base avant le point du premier élément + if nc_dict: + first_base = next(iter(nc_dict)).split('.')[0] # Récupérer la base avant le point de la première clé + + # Filtrer le dictionnaire pour ne garder que les éléments avec la même base + nc_dict = {base_accver: (chrstart, chrstop) for base_accver, (chrstart, chrstop) in nc_dict.items() if + base_accver.split('.')[0] == first_base} + + # Votre code existant pour afficher le dictionnaire filtré + print("\nDictionnaire filtré :") + for base_accver, (chrstart, chrstop) in nc_dict.items(): + print(f"{base_accver}: chrstart={chrstart}, chrstop={chrstop}") + + # Trouver l'entrée avec le chiffre le plus grand et le plus petit après le point + max_version = -1 + max_accver = None + max_coords = None # Pour stocker les coordonnées associées à la version maximale + min_version = float('inf') # Initialiser à l'infini pour trouver la plus petite version + min_accver = None + min_coords = None # Pour stocker les coordonnées associées à la version minimale + + for base_accver in nc_dict.keys(): + version = int(base_accver.split('.')[1]) # Extraire la version après le point + + # Mise à jour pour la version maximale + if version > max_version: + max_version = version + max_accver = base_accver + max_coords = nc_dict[base_accver] # Stocker les coordonnées + + # Mise à jour pour la version minimale + if version < min_version: + min_version = version + min_accver = base_accver + min_coords = nc_dict[base_accver] # Stocker les coordonnées + + # Afficher les résultats + if max_accver: + print(f"\nL'accès avec la version la plus élevée est : {max_accver} avec la version {max_version}.") + print(f"Coordonnées : chrstart={max_coords[0]}, chrstop={max_coords[1]}") + else: + print("\nAucun accès trouvé.") + + if min_accver: + print(f"L'accès avec la version la plus basse est : {min_accver} avec la version {min_version}.") + print(f"Coordonnées : chrstart={min_coords[0]}, chrstop={min_coords[1]}") + else: + print("Aucun accès trouvé.") + + # Étape 3 : Faire une requête sur chaque accession version pour récupérer les infos détaillées + for base_accver in nc_dict.keys(): + nc_info = fetch_nc_info(base_accver) + if nc_info and 'result' in nc_info and base_accver in nc_info['result']: + nc_details = nc_info['result'][base_accver] + print(f"\nDétails pour {base_accver} :") + print(f"Organisme : {nc_details.get('organism', {}).get('scientificname', 'Inconnu')}") + print(f"Description : {nc_details.get('title', 'Inconnu')}") + else: + print(f"Aucune information détaillée trouvée pour {base_accver}.") + + else: + print(f"Aucune information détaillée trouvée pour l'ID {gene_id}.") + + +if __name__ == "__main__": + main() diff --git a/tfinder/__init__.py b/tfinder/__init__.py index 61f64ae1..6700bac8 100644 --- a/tfinder/__init__.py +++ b/tfinder/__init__.py @@ -36,6 +36,8 @@ from sklearn.preprocessing import StandardScaler from tqdm import tqdm +from test import extract_genomic_info + class NCBIdna: def __init__(self, @@ -43,12 +45,13 @@ def __init__(self, prom_term, upstream, downstream, - species=None, all_slice_forms=None): + species=None, gr="Current", all_slice_forms=None): self.gene_id = gene_id self.prom_term = prom_term if prom_term is not None else None self.upstream = upstream if upstream is not None else None self.downstream = downstream if downstream is not None else None self.species = species if species is not None else None + self.gr = gr if gr is not None else "Current" self.all_slice_forms = True if all_slice_forms is True else False @staticmethod @@ -136,7 +139,7 @@ def find_sequences(self): return result_promoter if not self.all_slice_forms: - gene_name, chraccver, chrstart, chrstop, species_API = NCBIdna.get_gene_info(entrez_id) + gene_name, chraccver, chrstart, chrstop, species_API = NCBIdna.get_gene_info(entrez_id, self.gr) if gene_name == 'Bad ID': result_promoter = f'Please verify ID of {self.gene_id}' return result_promoter @@ -210,9 +213,9 @@ def convert_gene_to_entrez_id(gene_name, species): @staticmethod # Get gene information - def get_gene_info(entrez_id): + def get_gene_info(entrez_id, gr): # Request gene information - url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=gene&id={entrez_id}&retmode=json&rettype=xml" + url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=gene&id={entrez_id}&retmode=json" response = requests.get(url) if response.status_code == 200: @@ -221,15 +224,111 @@ def get_gene_info(entrez_id): gene_info = response_data['result'][str(entrez_id)] if 'chraccver' in str(gene_info): gene_name = gene_info['name'] - chraccver = gene_info['genomicinfo'][0]['chraccver'] - chrstart = int(gene_info['genomicinfo'][0]['chrstart']) - chrstop = int(gene_info['genomicinfo'][0]['chrstop']) + if gr != "Current": + chraccver, chrstart, chrstop = NCBIdna.extract_genomic_info(entrez_id, response_data) + else: + chraccver = gene_info['genomicinfo'][0]['chraccver'] + chrstart = int(gene_info['genomicinfo'][0]['chrstart']) + chrstop = int(gene_info['genomicinfo'][0]['chrstop']) species_API = gene_info['organism']['scientificname'] + print(chraccver, chrstart, chrstop) return gene_name, chraccver, chrstart, chrstop, species_API else: gene_name = 'Bad ID' return gene_name, None, None, None, None + @staticmethod + def extract_genomic_info(gene_id, gene_info): + # print(gene_id, gene_info) + + if gene_info and 'result' in gene_info and gene_id in gene_info['result']: + accession_dict = {} + gene_details = gene_info['result'][gene_id] + + time.sleep(1) + + # Extraction depuis la section locationhist + location_hist = gene_details.get('locationhist', []) + if len(location_hist) == 0: + location_hist = gene_details.get('genomicinfo', []) + for loc in location_hist: + nc_accver = loc.get('chraccver') # Extrait le NC_XXXXX.YY + chrstart = loc.get('chrstart') + chrstop = loc.get('chrstop') + + if nc_accver: + base_accession = nc_accver + if base_accession not in accession_dict: + accession_dict[base_accession] = (chrstart, chrstop) + else: + # Conserver la première occurrence des coordonnées + existing_start, existing_stop = accession_dict[base_accession] + accession_dict[base_accession] = (min(existing_start, chrstart), max(existing_stop, chrstop)) + + + nc_dict = accession_dict + + # Affichage des NC_ et leurs informations de position + # for base_accver, (chrstart, chrstop) in nc_dict.items(): + # print(f"{base_accver}: chrstart={chrstart}, chrstop={chrstop}") + + # Filtrer pour garder uniquement les entrées qui commencent par "NC_" + nc_dict = {base_accver: (chrstart, chrstop) for base_accver, (chrstart, chrstop) in nc_dict.items() if + base_accver.startswith("NC_")} + + # Si le dictionnaire n'est pas vide, récupérez la base avant le point du premier élément + if nc_dict: + first_base = next(iter(nc_dict)).split('.')[0] # Récupérer la base avant le point de la première clé + + # Filtrer le dictionnaire pour ne garder que les éléments avec la même base + nc_dict = {base_accver: (chrstart, chrstop) for base_accver, (chrstart, chrstop) in nc_dict.items() if + base_accver.split('.')[0] == first_base} + + # Votre code existant pour afficher le dictionnaire filtré + # print("\nDictionnaire filtré :") + # for base_accver, (chrstart, chrstop) in nc_dict.items(): + # print(f"{base_accver}: chrstart={chrstart}, chrstop={chrstop}") + + # Trouver l'entrée avec le chiffre le plus grand et le plus petit après le point + max_version = -1 + max_accver = None + max_coords = None # Pour stocker les coordonnées associées à la version maximale + min_version = float('inf') # Initialiser à l'infini pour trouver la plus petite version + min_accver = None + min_coords = None # Pour stocker les coordonnées associées à la version minimale + + for base_accver in nc_dict.keys(): + version = int(base_accver.split('.')[1]) # Extraire la version après le point + + # Mise à jour pour la version maximale + if version > max_version: + max_version = version + max_accver = base_accver + max_coords = nc_dict[base_accver] # Stocker les coordonnées + + # Mise à jour pour la version minimale + if version < min_version: + min_version = version + min_accver = base_accver + min_coords = nc_dict[base_accver] # Stocker les coordonnées + + # Afficher les résultats + # if max_accver: + # print(f"\nL'accès avec la version la plus élevée est : {max_accver} avec la version {max_version}.") + # print(f"Coordonnées : chrstart={max_coords[0]}, chrstop={max_coords[1]}") + # else: + # print("\nAucun accès trouvé.") + # + # if min_accver: + # print(f"L'accès avec la version la plus basse est : {min_accver} avec la version {min_version}.") + # print(f"Coordonnées : chrstart={min_coords[0]}, chrstop={min_coords[1]}") + # else: + # print("Aucun accès trouvé.") + + # print("Test", min_accver, min_coords[0], min_coords[1]) + # print("test") + return min_accver, min_coords[0], min_coords[1] + @staticmethod # Get gene information def get_variant_info(entrez_id, variant):