From 9b74ef911dea8cf56f6d05f7c20a35792155e11d Mon Sep 17 00:00:00 2001 From: mpecchi Date: Sun, 5 May 2024 00:03:08 -0400 Subject: [PATCH] updated similarity --- src/gcms_data_analysis/gcms.py | 60 +++++++++++-- tests/data_minimal_case/S_1.txt | 3 +- tests/data_minimal_case/S_2.txt | 3 +- tests/data_minimal_case/cal_minimal.xlsx | Bin 30023 -> 30110 bytes .../compounds_properties.xlsx | Bin 5496 -> 5956 bytes tests/test_project_class.py | 80 ++++++++++++++++-- 6 files changed, 129 insertions(+), 17 deletions(-) diff --git a/src/gcms_data_analysis/gcms.py b/src/gcms_data_analysis/gcms.py index ce32dfa..ec7a781 100644 --- a/src/gcms_data_analysis/gcms.py +++ b/src/gcms_data_analysis/gcms.py @@ -103,6 +103,7 @@ def __init__( self.list_of_all_compounds: list[str] | None = None self.compounds_properties: pd.DataFrame | None = None + self.dict_names_to_iupacs: dict[str, str] | None = None self.deriv_list_of_all_compounds: list[str] | None = None self.deriv_files_present: bool = False @@ -306,11 +307,9 @@ def create_list_of_all_compounds(self): self.load_all_files() if not self.calibrations: self.load_calibrations() - all_dfs_with_comps = [] - for file in self.files.values(): - all_dfs_with_comps.append(file) - for calib in self.calibrations.values(): - all_dfs_with_comps.append(calib) + all_dfs_with_comps = [f for f in self.files.values()] + [ + f for f in self.calibrations.values() + ] # non-derivatized compounds all_compounds: pd.DataFrame = pd.concat(all_dfs_with_comps) @@ -336,7 +335,7 @@ def create_compounds_properties( if self.dict_classes_to_codes is None: self.load_class_code_frac() - if not self.list_of_all_compounds is None: + if self.list_of_all_compounds is None: self.create_list_of_all_compounds() # cpdf = pd.DataFrame(index=pd.Index(self.list_of_all_compounds)) # @@ -373,6 +372,55 @@ def load_compounds_properties(self) -> pd.DataFrame: cpdf = self.create_compounds_properties() return self.compounds_properties + def create_dict_names_to_iupacs(self) -> dict[str, str]: + if self.compounds_properties is None: + self.load_compounds_properties() + self.dict_names_to_iupacs = self.compounds_properties["iupac_name"].to_dict() + return self.dict_names_to_iupacs + + def add_iupac_to_files_and_calibrations(self): + """Adds the IUPAC name to each compound in the loaded files, + distinguishing between underivatized and derivatized compounds, + and updates the corresponding file dataframes.""" + if not self.files: + self.load_all_files() + if self.compounds_properties is None: + self.load_compounds_properties() + for file in self.files.values(): + file["iupac_name"] = file.index.map(self.dict_names_to_iupacs) + for file in self.calibrations.values(): + file["iupac_name"] = file.index.map(self.dict_names_to_iupacs) + return self.files, self.calibrations + + # def apply_calibration_to_files(self): + # """Applies the appropriate calibration curve to each compound + # in the loaded files, adjusting concentrations based on calibration + # data, and updates the 'files' attribute with calibrated data.""" + # print("Info: apply_calibration_to_files: loop started") + # if not self.files: + # self.load_all_files() + # if not self.calibrations: + # self.load_calibrations() + # if not self.iupac_to_files_added: + # _, _ = self.add_iupac_to_files() + + # for filename, _ in self.files.items(): + # calibration_name = self.files_info.loc[filename, "calibration_file"] + # calibration = self.calibrations[calibration_name] + # if not self.is_files_deriv[filename]: + # df_comps = self.compounds_properties + # else: + # df_comps = self.deriv_compounds_properties + # file = self._apply_calib_to_file(filename, calibration, df_comps) + # if Project.auto_save_to_excel: + # self.save_file(file, filename) + # self.calibration_to_files_applied = True + # return self.files, self.is_files_deriv + + +def create_tanimoto_matrix(smiles_list: list[str]): + pass + def get_compound_from_pubchempy(comp_name: str) -> pcp.Compound: if not isinstance(comp_name, str) or comp_name.isspace(): diff --git a/tests/data_minimal_case/S_1.txt b/tests/data_minimal_case/S_1.txt index 746b4d1..6c3b7f8 100644 --- a/tests/data_minimal_case/S_1.txt +++ b/tests/data_minimal_case/S_1.txt @@ -7,6 +7,7 @@ Output Time 11:00:20 AM # of Peaks 3 Mass TIC Peak# Ret.Time Proc.From Proc.To Mass Area Height A/H Conc. Mark Name Ret. Index Area% Height% SI CAS # -1 13.703 13.580 13.900 TIC 20 20 1 0 V Phenol 2.59 3.01 97 108-95-2 +1 13.703 13.580 13.900 TIC 20 20 1 0 V Capric Acid 2.59 3.01 97 108-95-2 2 20.942 20.767 21.020 TIC 200 200 1 0 V Naphthalene 8.11 9.20 98 91-20-3 3 21.426 21.373 21.500 TIC 2000 2000 1 0 V Dodecane 0.36 0.57 96 112-40-3 +4 22.426 22.373 22.500 TIC 1000 1000 1 0 V NotValidComp 0.36 0.57 96 112-40-3 diff --git a/tests/data_minimal_case/S_2.txt b/tests/data_minimal_case/S_2.txt index 35f4bb5..b179c4a 100644 --- a/tests/data_minimal_case/S_2.txt +++ b/tests/data_minimal_case/S_2.txt @@ -7,6 +7,7 @@ Output Time 11:00:20 AM # of Peaks 3 Mass TIC Peak# Ret.Time Proc.From Proc.To Mass Area Height A/H Conc. Mark Name Ret. Index Area% Height% SI CAS # -1 13.703 13.580 13.900 TIC 40 40 1 0 V Phenol 2.59 3.01 97 108-95-2 +1 13.703 13.580 13.900 TIC 40 40 1 0 V Capric Acid 2.59 3.01 97 108-95-2 2 20.942 20.767 21.020 TIC 400 400 1 0 V Naphthalene 8.11 9.20 98 91-20-3 3 21.426 21.373 21.500 TIC 4000 4000 1 0 V Dodecane 0.36 0.57 96 112-40-3 +4 24.426 26.373 21.500 TIC 1000 1000 1 0 V Almost Oleic Acid 0.36 0.57 96 112-40-3 diff --git a/tests/data_minimal_case/cal_minimal.xlsx b/tests/data_minimal_case/cal_minimal.xlsx index 52acd5cbefcfc2a4c234e0a177ee0c91b08596b4..d205d097f64c07fbaa902916d96d0574c40c581e 100644 GIT binary patch delta 14910 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 delta 14857 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%0A2o6VUhfK$C z4g$b1d2KYo7LKNbMoH3+4eU+N5(^=r04!O$On7r2`UyL&-uHv#@ww}fLa5w%`-p1_ z4ti^S&Sw{!mQTf7TEj7}RbCo&zj&yrm@SpVWY@$5BEo;s)L`;LFa%*ERI9;~(42+= z?v3!_4d`R;L#}=vD>m(lPD~J;_f*+d!IRNfH~2uZ`4sLaYgvW2j6$&V=upXLdENy4Zkb-L;syfMAQ!Y{CIGT zS!y3u7$Jc!14E1Pia1(1w%X2;gMaL&uEj_yznTt8V%DZ9tXInsIk?c=Z~{rj1^EY$ zo+g^gx|3}$el%(Bkc&EqSiQERqqSu1uZtxj_#!fSGW1}8n&z?ui{(%l#cPt;8ZL^_ z0ZJ`#Y$*hUlF0f#YpS0(g;x67P}Iy&*I=%vvZ;Z;N3Q9A!iyLfd#%X_8@uYd-E;1Xw+QEiGFC%1KmBqw^i1)Sj4@<6O!)O zvC?vN0{s?)5cG0;=w_*XA)zljn{hjSn6vtWkjz)++4UEA0~W($VBvBy+)-jsR0WsT z{KmazyOjXbQ{yG~8^qI=b*#aj?`dsH+_?gj-uvIU0Y76@>lZ}y=?|33YP z2myfxKBMuU3lAP->+lJDT8IFO5*b9{z(Dk$^Fn`jIREz*j|v)aq$B#jTcH12U~`WkDM*JYW_+-Br!BLI zk*$fSrID3Ah}DG&YD)oRk} qBxpqfk^$2voErfQnJxGSaT^jGMHyJQzgh{vFC_4$U~2on-~JzxowG^+ diff --git a/tests/data_minimal_case/compounds_properties.xlsx b/tests/data_minimal_case/compounds_properties.xlsx index 201f8ed66c6b8c07f7ed635a2a6afe5e98d13def..ecf35d4d485e338e08bb648497b59258b75010ee 100644 GIT binary patch delta 2012 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 dict[str, list[float]]: + + mols_comp = Chem.MolFromSmiles(comp_smiles) + mols_cal = [ + Chem.MolFromSmiles(smi) for smi in calib_smiless if isinstance(smi, str) + ] + + # Generate fingerprints from molecule objects, skipping None entries created from invalid SMILES + fps_comp = GetMorganFingerprintAsBitVect(mols_comp, 2, nBits=1024) + + fps_cal = [ + GetMorganFingerprintAsBitVect(mol, 2, nBits=1024) + for mol in mols_cal + if mol is not None + ] + + # perform Tanimoto similarity betwenn the first and all other compounds + similarity = DataStructs.BulkTanimotoSimilarity(fps_comp, fps_cal) + # create a df with results + return similarity + + +calib_comp_iupacs = proj.calibrations["cal_minimal"].index.tolist() +calib_smiless = proj.compounds_properties.loc[ + calib_comp_iupacs, "canonical_smiles" +].tolist() +tanimoto_similarity_df: pd.DataFrame = pd.DataFrame( + index=proj.compounds_properties["iupac_name"], + columns=calib_comp_iupacs, +) +for iupac, smiles in zip( + proj.compounds_properties["iupac_name"], + proj.compounds_properties["canonical_smiles"], +): + if isinstance(smiles, str): + sim = create_tanimoto_similarity_dict(smiles, calib_smiless) + tanimoto_similarity_df.loc[iupac, :] = sim +# %% +compounds_properties = proj.compounds_properties +calib_comp_iupacs = proj.calibrations["cal_minimal"]["iupac_name"].tolist() +tanimoto_similarity_df: pd.DataFrame = pd.DataFrame( + index=compounds_properties.iupac_name.tolist(), + columns=proj.calibrations["cal_minimal"]["iupac_name"].tolist(), +) +for comp in compounds_properties.iupac_name.tolist(): + print(comp) + s = create_tanimoto_similarity_dict(comp, calib_comp_iupacs) + tanimoto_similarity_df.loc[comp, :] = s +# %% + +# %%