diff --git a/code dynamic b/code dynamic new file mode 100644 index 0000000000000000000000000000000000000000..d4d287f86918cf62e678b66fc3380a7d95661d90 --- /dev/null +++ b/code dynamic @@ -0,0 +1,204 @@ +from typing import Any + +import gffutils +import pandas as pd +import matplotlib.pyplot as plt +from collections import Counter +from io import StringIO + +#STAT +def avg_lenght(db): + """ + Calcule la longueur moyenne de chaque chaque features + :param db: base de données + :return: la moyenne de chaque chaque features + """ + avg = Counter() + for feature in db.featuretypes(): + longueurs = [feature.end - feature.start + 1 for feature in db.features_of_type(feature)] + avg[feature] = sum(longueurs) / len(longueurs) if longueurs else 0 + return avg + +def count(db): + """ + comptage de chaque features + :param db: base de données + :return: dict avec feature : nombre de ce feature dans le fichier GFF + """ + stats = Counter() + for feature in db.all_features(): #methode gffutils + stats[feature.featuretype] += 1 + return stats + +def fusions_stat(count, avg): + """ + Combinaisons de plusieurs dictionnaires stat dans 1 tableau + :param count: Un dictionnaire avec le nombre de chaque type de feature. + :param avg: Un dictionnaire avec la longueur moyenne de chaque type de feature. + :return: Un tableau + """ + # Transformer les dict en tableau + count_df = pd.DataFrame(count.items(), columns=["Feature Type", "Count"]) + avg_df = pd.DataFrame(avg.items(), columns=["Feature Type", "Average Length"]) + + # Fusion les tableaux sur la colonne "Feature Type" + combined_df = pd.merge(count_df, avg_df, on="Feature Type", how="left") #faut que klé des deux dict soit les memes + + return combined_df + + +#LIEN + +def liens(feature): + """ + LIEN NCBI + :param feature: Un objet représentant une feature du fichier GFF. + :return: lien vers site NCBI du feature + """ + return "NA" + +def graphe(stats, output_plot): + """ + Génère un graph de la distribution des features du GFF. + :param stats: Dictionnaire contenant le nombre de chaque type de feature. + :return: image qu'on utilisera plus tard + """ + fig, ax = plt.subplots() + ax.pie(stats.values(), labels=stats.keys(), autopct='%1.1f%%', startangle=140) + ax.axis('equal') # Cercle parfait + + img_buffer = StringIO() + plt.savefig(img_buffer, format='svg') + plt.savefig(output_plot) + plt.close() + +def extraire_attributs(db): + """ + recup tout les attributes present dans notres GFF + :param db: base de donnees + :return: set d'attribut + """ + attributs = set() + for feature in db.all_features(): + attributs.update(feature.attributes.keys()) + return sorted(attributs) + +def gff_a_html(gff_file, output_html, output_plot="feature_distribution.png"): + """ + Analyse un fichier GFF et génère un tableau HTML avec les informations des gènes extraites + :param gff_file: chemin de ou est enregistré le fichier GFF + :param output_html: chemin de ou on veux que le fichier HTML s'enregistre + :return: enregistre un fichier HTML avec un tableau de donnée la ou on lui a demandé + """ + # base de données temporaire du fichier + db = gffutils.create_db(gff_file, dbfn=":memory:", force=True, keep_order=True, merge_strategy="create_unique", sort_attribute_values=True) + # memory : pour pas stocker sur disque (RAM) + #force = true : recrée base si elle existe déja + #merge_strategy="create_unique" : pour que les valeurs fusionnée reste unique + #sort_attribute_values=True : tri valeurs + data = [] # Liste stock infos + attributs = extraire_attributs(db) + + # création data + for feature in db.all_features(): + entry = {"Feature Type": feature.featuretype, "ID": feature.id, "Start": feature.start, "End": feature.end, + "Strand": feature.strand, "External Link": liens(feature)} + for attr in attributs: + entry[attr] = ", ".join(feature.attributes.get(attr, ["N/A"])) + data.append(entry) + + # DATA + df = pd.DataFrame(data) + df_html = df.to_html(index=False, escape=False) #html + + # STAT + cnt = count(db) + avg = avg_lenght(db) + stats_df = fusions_stat(cnt, avg) + stats_html = stats_df.to_html(index=False) #html + + graphe(avg, output_plot) + + html_template = f""" + <!DOCTYPE html> + <html lang="en"> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>GFF Report</title> + <link rel="stylesheet" href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.min.css"> + <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> + <script src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js"></script> + <style> + body {{ + font-family: Arial, sans-serif; + margin: 20px; + }} + table {{ + width: 100%; + border-collapse: collapse; + margin-bottom: 20px; + }} + th, td {{ + border: 1px solid #ddd; + padding: 8px; + text-align: left; + }} + th {{ + background-color: #f2f2f2; + }} + img {{ + max-width: 100%; + height: auto; + }} + </style> + <script> + $(document).ready(function() {{ + $('table').DataTable({{ + "paging": true, + "searching": true, + "ordering": true + }}); + }}); + </script> + </head> + <body> + <h1>Feature Data</h1> + {df_html} + + <h1>Statistics</h1> + {stats_html} + + <h1>Distribution celon les longueurs</h1> + <img src="{output_plot}" alt="Feature Distribution"> + </body> + </html> + """ + + with open(output_html, "w", encoding="utf-8") as f: + f.write(html_template) + + print(f"HTML report saved as {output_html}") + +# UTF8 permet les encodages spéciaux +# viewport permet de lire le documents sur un format téléphone +# les trucs apres c'est pour charger CSS, jQuery (librairy JS) et DataTables.js (permet tri et recherche) +# mise en page avec police Arial, margin c'est pour mettre des espaces entre les elements +# th, td c'est tous le tableau entete et reste +# th c'est l'entete et j'ai mis un fond gris pour meuilleur visu +# max-width: 100% permet d'adapter la taille de l'image a la taille de la fenetre du moteur de recherche +# dans scrit : permet pagination quand tableau est trop long, rechercher dans les colonnes et trier + + +if __name__ == "__main__": + + #chemin des fichiers de Clara : + #gff_file = "/Users/claramoreno/PycharmProjects/PythonProjectPaster/wormbase_gff2_alt.txt" + gff_file = "/Users/claramoreno/PycharmProjects/PythonProjectPaster/PROKKA_REF_ONTillumina.gff" + output_html = "/Users/claramoreno/PycharmProjects/PythonProjectPaster/output.html" + + #chemin des fichiers : + #gff_file = + #output_html = + + print(gff_a_html(gff_file,output_html)) \ No newline at end of file