pertpy 0.6.0__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. pertpy/__init__.py +3 -2
  2. pertpy/data/__init__.py +5 -1
  3. pertpy/data/_dataloader.py +2 -4
  4. pertpy/data/_datasets.py +203 -92
  5. pertpy/metadata/__init__.py +4 -0
  6. pertpy/metadata/_cell_line.py +826 -0
  7. pertpy/metadata/_compound.py +129 -0
  8. pertpy/metadata/_drug.py +242 -0
  9. pertpy/metadata/_look_up.py +582 -0
  10. pertpy/metadata/_metadata.py +73 -0
  11. pertpy/metadata/_moa.py +129 -0
  12. pertpy/plot/__init__.py +1 -9
  13. pertpy/plot/_augur.py +53 -116
  14. pertpy/plot/_coda.py +277 -677
  15. pertpy/plot/_guide_rna.py +17 -35
  16. pertpy/plot/_milopy.py +59 -134
  17. pertpy/plot/_mixscape.py +152 -391
  18. pertpy/preprocessing/_guide_rna.py +88 -4
  19. pertpy/tools/__init__.py +8 -13
  20. pertpy/tools/_augur.py +315 -17
  21. pertpy/tools/_cinemaot.py +143 -4
  22. pertpy/tools/_coda/_base_coda.py +1210 -65
  23. pertpy/tools/_coda/_sccoda.py +50 -21
  24. pertpy/tools/_coda/_tasccoda.py +27 -19
  25. pertpy/tools/_dialogue.py +164 -56
  26. pertpy/tools/_differential_gene_expression.py +240 -14
  27. pertpy/tools/_distances/_distance_tests.py +8 -8
  28. pertpy/tools/_distances/_distances.py +184 -34
  29. pertpy/tools/_enrichment.py +465 -0
  30. pertpy/tools/_milo.py +345 -11
  31. pertpy/tools/_mixscape.py +668 -50
  32. pertpy/tools/_perturbation_space/_clustering.py +5 -1
  33. pertpy/tools/_perturbation_space/_discriminator_classifiers.py +526 -0
  34. pertpy/tools/_perturbation_space/_perturbation_space.py +135 -43
  35. pertpy/tools/_perturbation_space/_simple.py +51 -10
  36. pertpy/tools/_scgen/__init__.py +1 -1
  37. pertpy/tools/_scgen/_scgen.py +701 -0
  38. pertpy/tools/_scgen/_utils.py +1 -3
  39. pertpy/tools/decoupler_LICENSE +674 -0
  40. {pertpy-0.6.0.dist-info → pertpy-0.7.0.dist-info}/METADATA +31 -12
  41. pertpy-0.7.0.dist-info/RECORD +53 -0
  42. {pertpy-0.6.0.dist-info → pertpy-0.7.0.dist-info}/WHEEL +1 -1
  43. pertpy/plot/_cinemaot.py +0 -81
  44. pertpy/plot/_dialogue.py +0 -91
  45. pertpy/plot/_scgen.py +0 -337
  46. pertpy/tools/_metadata/__init__.py +0 -0
  47. pertpy/tools/_metadata/_cell_line.py +0 -613
  48. pertpy/tools/_metadata/_look_up.py +0 -342
  49. pertpy/tools/_perturbation_space/_discriminator_classifier.py +0 -381
  50. pertpy/tools/_scgen/_jax_scgen.py +0 -370
  51. pertpy-0.6.0.dist-info/RECORD +0 -50
  52. /pertpy/tools/_scgen/{_jax_scgenvae.py → _scgenvae.py} +0 -0
  53. {pertpy-0.6.0.dist-info → pertpy-0.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,582 @@
1
+ from __future__ import annotations
2
+
3
+ from collections import namedtuple
4
+ from typing import TYPE_CHECKING, Literal
5
+
6
+ if TYPE_CHECKING:
7
+ from collections.abc import Sequence
8
+
9
+ from rich import print
10
+
11
+ if TYPE_CHECKING:
12
+ import pandas as pd
13
+
14
+ import pubchempy as pcp
15
+
16
+
17
+ class LookUp:
18
+ """Generate LookUp object for different type of metadata."""
19
+
20
+ def __init__(
21
+ self,
22
+ type: Literal["cell_line", "moa", "compound", "drug"] = "cell_line",
23
+ transfer_metadata: Sequence[pd.DataFrame] | None = None,
24
+ ):
25
+ """
26
+ Args:
27
+ type: Metadata type for annotation. One of 'cell_line', 'compound', 'moa' or 'drug. Defaults to cell_line.
28
+ transfer_metadata: DataFrames used to generate Lookup object.
29
+ This is currently set to None for CompoundMetaData which does not require any dataframes for transfer.
30
+ Defaults to 'cell_line'.
31
+ """
32
+ self.type = type
33
+ if type == "cell_line":
34
+ self.cell_line_meta = transfer_metadata[0]
35
+ self.cl_cancer_project_meta = transfer_metadata[1]
36
+ self.gene_annotation = transfer_metadata[2]
37
+ self.bulk_rna_sanger = transfer_metadata[3]
38
+ self.bulk_rna_broad = transfer_metadata[4]
39
+ self.proteomics_data = transfer_metadata[5]
40
+ self.drug_response_gdsc1 = transfer_metadata[6]
41
+ self.drug_response_gdsc2 = transfer_metadata[7]
42
+
43
+ cell_line_annotation = namedtuple(
44
+ "cell_line_annotation",
45
+ "n_cell_line cell_line n_metadata metadata reference_id reference_id_example default_parameter",
46
+ )
47
+ cell_lines = namedtuple("cell_lines", ["depmap", "cancerrxgene"])
48
+
49
+ depmap_data = {
50
+ "n_cell_line": len(self.cell_line_meta.index),
51
+ "n_metadata": len(self.cell_line_meta.columns),
52
+ "cell_line": self.cell_line_meta.ModelID.values,
53
+ "metadata": self.cell_line_meta.columns.values,
54
+ "reference_id": [
55
+ "ModelID",
56
+ "CellLineName",
57
+ "StrippedCellLineName",
58
+ "CCLE_Name",
59
+ ],
60
+ "reference_id_example": "ModelID: ACH-000001 | CellLineName: NIH:OVCAR-3 | StrippedCellLineName: NIHOVCAR3 | CCLEName: NIHOVCAR3_OVARY",
61
+ "default_parameter": {
62
+ "cell_line_source": "DepMap",
63
+ "query_id": "DepMap_ID",
64
+ "reference_id": "ModelID",
65
+ "fetch": "None",
66
+ },
67
+ }
68
+ depmap_record = cell_line_annotation(**depmap_data)
69
+
70
+ cancerrxgene_data = {
71
+ "n_cell_line": len(self.cl_cancer_project_meta.index),
72
+ "n_metadata": len(self.cl_cancer_project_meta.columns),
73
+ "cell_line": self.cl_cancer_project_meta.stripped_cell_line_name.values,
74
+ "metadata": self.cl_cancer_project_meta.columns.values,
75
+ "reference_id": [
76
+ "cell_line_name",
77
+ "stripped_cell_line_name",
78
+ "Model ID",
79
+ "COSMIC ID",
80
+ ],
81
+ "reference_id_example": "cell_line_name: SNU-283 | stripped_cell_line_name: SNU283 | Model ID: SIDM00215 | COSMIC ID: 1659929",
82
+ "default_parameter": {
83
+ "query_id": "stripped_cell_line_name",
84
+ "reference_id": "stripped_cell_line_name",
85
+ "fetch": "None",
86
+ },
87
+ }
88
+ cancerrxgene_record = cell_line_annotation(**cancerrxgene_data)
89
+ self.cell_lines = cell_lines(depmap_record, cancerrxgene_record)
90
+
91
+ bulk_rna_annotation = namedtuple(
92
+ "bulk_rna_annotation",
93
+ "n_cell_line cell_line n_gene gene reference_id reference_id_example default_parameter",
94
+ )
95
+ bulk_rna_expression = namedtuple("bulk_rna_expression", ["broad", "sanger"])
96
+
97
+ broad_data = {
98
+ "n_cell_line": len(self.bulk_rna_broad.index),
99
+ "n_gene": len(self.bulk_rna_broad.columns),
100
+ "cell_line": self.bulk_rna_broad.index.values,
101
+ "gene": self.bulk_rna_broad.columns.values,
102
+ "reference_id": "DepMap_ID",
103
+ "reference_id_example": "DepMap_ID: ACH-001113",
104
+ "default_parameter": {
105
+ "query_id": "DepMap_ID",
106
+ "cell_line_source": "broad",
107
+ },
108
+ }
109
+ broad_record = bulk_rna_annotation(**broad_data)
110
+
111
+ sanger_data = {
112
+ "n_cell_line": len(self.bulk_rna_sanger.index),
113
+ "n_gene": len(self.bulk_rna_sanger.columns),
114
+ "cell_line": self.bulk_rna_sanger.index.values,
115
+ "gene": self.bulk_rna_sanger.columns.values,
116
+ "reference_id": "model_name",
117
+ "reference_id_example": "model_name: MEC-1",
118
+ "default_parameter": {
119
+ "query_id": "cell_line_name",
120
+ "cell_line_source": "sanger",
121
+ },
122
+ }
123
+ sanger_record = bulk_rna_annotation(**sanger_data)
124
+ self.bulk_rna = bulk_rna_expression(broad_record, sanger_record)
125
+
126
+ proteomics = namedtuple(
127
+ "proteomics",
128
+ "n_cell_line cell_line n_protein protein metadata reference_id reference_id_example default_parameter",
129
+ )
130
+ proteomics_data = {
131
+ "n_cell_line": len(self.proteomics_data["model_name"].unique()),
132
+ "n_protein": len(self.proteomics_data.uniprot_id.unique()),
133
+ "cell_line": self.proteomics_data["model_name"].unique(),
134
+ "protein": self.proteomics_data.uniprot_id.unique(),
135
+ "metadata": self.proteomics_data.columns.values,
136
+ "reference_id": ["model_id", "model_name"],
137
+ "reference_id_example": "model_id: SIDM00483 | model_name: SK-GT-4",
138
+ "default_parameter": {
139
+ "query_id": "cell_line_name",
140
+ "reference_id": "model_name",
141
+ "bulk_rna_information": "read_count",
142
+ "protein_information": "protein_intensity",
143
+ "protein_id": "uniprot_id",
144
+ },
145
+ }
146
+ self.proteomics = proteomics(**proteomics_data)
147
+
148
+ drug_response_annotation = namedtuple(
149
+ "drug_response_annotation",
150
+ "n_cell_line cell_line n_drug drug_name metadata reference_id reference_id_example default_parameter",
151
+ )
152
+ drug_response = namedtuple("drug_response", ["gdsc1", "gdsc2"])
153
+
154
+ gdsc1_data = {
155
+ "n_cell_line": len(self.drug_response_gdsc1["cell_line_name"].unique()),
156
+ "n_drug": len(self.drug_response_gdsc1.drug_name.unique()),
157
+ "cell_line": self.drug_response_gdsc1.cell_line_name.unique(),
158
+ "drug_name": self.drug_response_gdsc1.drug_name.unique(),
159
+ "metadata": self.drug_response_gdsc1.columns.values,
160
+ "reference_id": ["cell_line_name", "sanger_model_id", "cosmic_id"],
161
+ "reference_id_example": "cell_line_name: ES5 | sanger_model_id: SIDM00263 | cosmic_id: 684057",
162
+ "default_parameter": {
163
+ "gdsc_dataset": "1",
164
+ "query_id": "cell_line_name",
165
+ "reference_id": "cell_line_name",
166
+ "query_perturbation": "perturbation",
167
+ "reference_perturbation": "drug_name",
168
+ },
169
+ }
170
+ gdsc1_dict = drug_response_annotation(**gdsc1_data)
171
+
172
+ gdsc2_data = {
173
+ "n_cell_line": len(self.drug_response_gdsc2["cell_line_name"].unique()),
174
+ "n_drug": len(self.drug_response_gdsc2.drug_name.unique()),
175
+ "cell_line": self.drug_response_gdsc2.cell_line_name.unique(),
176
+ "drug_name": self.drug_response_gdsc2.drug_name.unique(),
177
+ "metadata": self.drug_response_gdsc2.columns.values,
178
+ "reference_id": ["cell_line_name", "sanger_model_id", "cosmic_id"],
179
+ "reference_id_example": "cell_line_name: PFSK-1 | sanger_model_id: SIDM01132 | cosmic_id: 683667",
180
+ "default_parameter": {
181
+ "gdsc_dataset": "1",
182
+ "query_id": "cell_line_name",
183
+ "reference_id": "cell_line_name",
184
+ "query_perturbation": "perturbation",
185
+ "reference_perturbation": "drug_name",
186
+ },
187
+ }
188
+ gdsc2_dict = drug_response_annotation(**gdsc2_data)
189
+
190
+ self.drug_response = drug_response(gdsc1_dict, gdsc2_dict)
191
+
192
+ elif type == "moa":
193
+ self.moa_meta = transfer_metadata[0]
194
+ moa_annotation = namedtuple(
195
+ "moa_annotation",
196
+ "n_pert n_moa query_id query_id_example target_example default_parameter",
197
+ )
198
+ moa_data = {
199
+ "n_pert": len(self.moa_meta.pert_iname.unique()),
200
+ "n_moa": len(self.moa_meta.moa.unique()),
201
+ "query_id": "pert_iname",
202
+ "query_id_example": [
203
+ "(R)-(-)-apomorphine",
204
+ "9-aminocamptothecin",
205
+ "A-803467",
206
+ ],
207
+ "target_example": [
208
+ "ADRA2A|ADRA2B|ADRA2C|CALY|DRD1|DRD2|DRD3|DRD4|DRD5|HTR1A|HTR1B|HTR1D|HTR2A|HTR2B|HTR2C|HTR5A",
209
+ "SCN10A",
210
+ "TOP1",
211
+ ],
212
+ "default_parameter": {
213
+ "query_id": "pert_iname",
214
+ "target": None,
215
+ },
216
+ }
217
+ self.moa = moa_annotation(**moa_data)
218
+
219
+ elif type == "compound":
220
+ compound_annotation = namedtuple("compound_annotation", "query_id query_id_example default_parameter")
221
+ compound_data = {
222
+ "query_id_type": ["name", "cid"],
223
+ "query_id_example": "name: ACH-000016 | cid: SLR 21",
224
+ "default_parameter": {
225
+ "query_id": "perturbation",
226
+ "query_id_type": "name",
227
+ },
228
+ }
229
+ self.compound = compound_annotation(**compound_data)
230
+
231
+ elif type == "drug":
232
+ self.chembl = transfer_metadata[0]
233
+ self.dgidb = transfer_metadata[1]
234
+ self.pharmgkb = transfer_metadata[2]
235
+
236
+ drug_annotation = namedtuple(
237
+ "drug_annotation",
238
+ "n_compound compound_example n_target target_example n_disease disease_example",
239
+ )
240
+ drugs = namedtuple("drugs", ["chembl", "dgidb", "pharmgkb"])
241
+
242
+ dgidb_data = {
243
+ "n_compound": len(self.dgidb.drug_claim_name.unique()),
244
+ "n_target": len(self.dgidb.gene_claim_name.unique()),
245
+ "compound_example": self.dgidb.drug_claim_name.values[0:5],
246
+ "target_example": self.dgidb.gene_claim_name.unique()[0:5],
247
+ "n_disease": 0,
248
+ "disease_example": "",
249
+ }
250
+ dgidb_record = drug_annotation(**dgidb_data)
251
+
252
+ chembl_targets = list(
253
+ {t for target in self.chembl.targets.tolist() for t in target}
254
+ ) # flatten the target column and remove duplicates
255
+ chembl_data = {
256
+ "n_compound": len(self.chembl.compounds),
257
+ "n_target": len(chembl_targets),
258
+ "compound_example": self.chembl.compounds.values[0:5],
259
+ "target_example": chembl_targets[0:5],
260
+ "n_disease": 0,
261
+ "disease_example": "",
262
+ }
263
+ chembl_record = drug_annotation(**chembl_data)
264
+
265
+ pharmgkb_data = {
266
+ "n_compound": len(self.pharmgkb[self.pharmgkb.Type == "Chemical"]["Compound|Disease"].unique()),
267
+ "n_target": len(self.pharmgkb.Gene.unique()),
268
+ "compound_example": self.pharmgkb[self.pharmgkb.Type == "Chemical"]["Compound|Disease"].unique()[0:5],
269
+ "target_example": self.pharmgkb.Gene.unique()[0:5],
270
+ "n_disease": len(self.pharmgkb[self.pharmgkb.Type == "Disease"]["Compound|Disease"].unique()),
271
+ "disease_example": self.pharmgkb[self.pharmgkb.Type == "Disease"]["Compound|Disease"].unique()[0:5],
272
+ }
273
+ pharmgkb_record = drug_annotation(**pharmgkb_data)
274
+ self.drugs = drugs(chembl_record, dgidb_record, pharmgkb_record)
275
+
276
+ else:
277
+ raise NotImplementedError
278
+
279
+ def available_cell_lines(
280
+ self,
281
+ cell_line_source: Literal["DepMap", "Cancerrxgene"] = "DepMap",
282
+ reference_id: str = "ModelID",
283
+ query_id_list: Sequence[str] | None = None,
284
+ ) -> None:
285
+ """A brief summary of cell line metadata.
286
+
287
+ Args:
288
+ cell_line_source: the source of cell line annotation, DepMap or Cancerrxgene. Defaults to "DepMap".
289
+ reference_id: The type of cell line identifier in the meta data, e.g. ModelID, CellLineName or StrippedCellLineName.
290
+ If fetch cell line metadata from Cancerrxgene, it is recommended to choose
291
+ "stripped_cell_line_name". Defaults to "ModelID".
292
+ query_id_list: Unique cell line identifiers to test the number of matched ids present in the
293
+ metadata. If set to None, the query of metadata identifiers will be disabled. Defaults to None.
294
+ """
295
+ if self.type != "cell_line":
296
+ raise ValueError("This is not a LookUp object specifically for CellLineMetaData!")
297
+
298
+ if query_id_list is not None:
299
+ identifier_num_all = len(query_id_list)
300
+ if cell_line_source == "DepMap":
301
+ if reference_id not in self.cell_line_meta.columns:
302
+ raise ValueError(
303
+ f"The specified `reference_id` {reference_id} is not available in the DepMap cell line annotation data. "
304
+ )
305
+ not_matched_identifiers = list(set(query_id_list) - set(self.cell_line_meta[reference_id]))
306
+ else:
307
+ if reference_id == "ModelID":
308
+ reference_id = "stripped_cell_line_name"
309
+ if reference_id not in self.cl_cancer_project_meta.columns:
310
+ raise ValueError(
311
+ f"The specified `reference_id` {reference_id} is not available "
312
+ f"in the cell line annotation from the project Genomics of Drug Sensitivity in Cancer. "
313
+ )
314
+ not_matched_identifiers = list(set(query_id_list) - set(self.cl_cancer_project_meta[reference_id]))
315
+
316
+ print(f"{len(not_matched_identifiers)} cell lines are not found in the metadata.")
317
+ print(f"{identifier_num_all - len(not_matched_identifiers)} cell lines are found! ")
318
+
319
+ def available_bulk_rna(
320
+ self,
321
+ cell_line_source: Literal["broad", "sanger"] = "sanger",
322
+ query_id_list: Sequence[str] | None = None,
323
+ ) -> None:
324
+ """A brief summary of bulk RNA expression data.
325
+
326
+ Args:
327
+ cell_line_source: the source of RNA-seq data, broad or sanger. Defaults to "sanger".
328
+ query_id_list: Unique cell line identifiers to test the number of matched ids present in the
329
+ metadata. If set to None, the query of metadata identifiers will be disabled. Defaults to None.
330
+ """
331
+ if self.type != "cell_line":
332
+ raise ValueError("This is not a LookUp object specific for CellLineMetaData!")
333
+
334
+ if cell_line_source == "broad":
335
+ bulk_rna = self.bulk_rna_broad
336
+ else:
337
+ bulk_rna = self.bulk_rna_sanger
338
+
339
+ if query_id_list is not None:
340
+ identifier_num_all = len(query_id_list)
341
+ not_matched_identifiers = list(set(query_id_list) - set(bulk_rna.index))
342
+
343
+ print(f"{len(not_matched_identifiers)} cell lines are not found in the metadata.")
344
+ print(f"{identifier_num_all - len(not_matched_identifiers)} cell lines are found! ")
345
+
346
+ def available_protein_expression(
347
+ self,
348
+ reference_id: Literal["model_name", "model_id"] = "model_name",
349
+ query_id_list: Sequence[str] | None = None,
350
+ ) -> None:
351
+ """A brief summary of protein expression data.
352
+
353
+ Args:
354
+ reference_id: The type of cell line identifier in the meta data, model_name or model_id.
355
+ Defaults to "model_name".
356
+ query_id_list: Unique cell line identifiers to test the number of matched ids present in the
357
+ metadata. If set to None, the query of metadata identifiers will be disabled. Defaults to None.
358
+ """
359
+ if self.type != "cell_line":
360
+ raise ValueError("This is not a LookUp object specific for CellLineMetaData!")
361
+
362
+ if query_id_list is not None:
363
+ identifier_num_all = len(query_id_list)
364
+
365
+ if reference_id not in self.proteomics_data.columns:
366
+ raise ValueError(
367
+ f"The specified `reference_id` {reference_id} is not available in the proteomics data. "
368
+ )
369
+ not_matched_identifiers = list(set(query_id_list) - set(self.proteomics_data[reference_id]))
370
+ print(f"[bold blue]{len(not_matched_identifiers)} cell lines are not found in the metadata.")
371
+ print(f"[bold yellow]{identifier_num_all - len(not_matched_identifiers)} cell lines are found! ")
372
+
373
+ def available_drug_response(
374
+ self,
375
+ gdsc_dataset: Literal[1, 2] = 1,
376
+ reference_id: Literal["cell_line_name", "sanger_model_id", "cosmic_id"] = "cell_line_name",
377
+ query_id_list: Sequence[str] | None = None,
378
+ reference_perturbation: Literal["drug_name", "drug_id"] = "drug_name",
379
+ query_perturbation_list: Sequence[str] | None = None,
380
+ ) -> None:
381
+ """A brief summary of drug response data.
382
+
383
+ Args:
384
+ gdsc_dataset: The GDSC dataset, 1 or 2. Defaults to 1.
385
+ The GDSC1 dataset updates previous releases with additional drug screening data from the Wellcome Sanger Institute and Massachusetts General Hospital.
386
+ It covers 970 Cell lines and 403 Compounds with 333292 IC50s.
387
+ GDSC2 is new and has 243,466 IC50 results from the latest screening at the Wellcome Sanger Institute using improved experimental procedures.
388
+ reference_id: The type of cell line identifier in the meta data, cell_line_name, sanger_model_id or cosmic_id.
389
+ Defaults to 'cell_line_name'.
390
+ query_id_list: Unique cell line identifiers to test the number of matched ids present in the metadata.
391
+ If set to None, the query of metadata identifiers will be disabled.
392
+ Defaults to None.
393
+ reference_perturbation: The perturbation information in the meta data, drug_name or drug_id.
394
+ Defaults to 'drug_name'.
395
+ query_perturbation_list: Unique perturbation types to test the number of matched ones present in the metadata.
396
+ If set to None, the query of perturbation types will be disabled.
397
+ Defaults to None.
398
+ """
399
+ if self.type != "cell_line":
400
+ raise ValueError("This is not a LookUp object specific for CellLineMetaData!")
401
+ if gdsc_dataset == 1:
402
+ gdsc_data = self.drug_response_gdsc1
403
+ else:
404
+ gdsc_data = self.drug_response_gdsc2
405
+
406
+ if query_id_list is not None:
407
+ if reference_id not in gdsc_data.columns:
408
+ raise ValueError(
409
+ f"The specified `reference_id` {reference_id} is not available in the GDSC drug response data. "
410
+ )
411
+ identifier_num_all = len(query_id_list)
412
+ not_matched_identifiers = list(set(query_id_list) - set(gdsc_data[reference_id]))
413
+ print(f"{len(not_matched_identifiers)} cell lines are not found in the metadata.")
414
+ print(f"{identifier_num_all - len(not_matched_identifiers)} cell lines are found! ")
415
+
416
+ if query_perturbation_list is not None:
417
+ if reference_perturbation not in gdsc_data.columns:
418
+ raise ValueError(
419
+ f"The specified `reference_perturbation` {reference_perturbation} is not available in the GDSC drug response data. "
420
+ )
421
+ identifier_num_all = len(query_perturbation_list)
422
+ not_matched_identifiers = list(set(query_perturbation_list) - set(gdsc_data[reference_perturbation]))
423
+ print(f"{len(not_matched_identifiers)} perturbation types are not found in the metadata.")
424
+ print(f"{identifier_num_all - len(not_matched_identifiers)} perturbation types are found! ")
425
+
426
+ def available_genes_annotation(
427
+ self,
428
+ reference_id: Literal["gene_id", "ensembl_gene_id", "hgnc_id", "hgnc_symbol"] = "ensembl_gene_id",
429
+ query_id_list: Sequence[str] | None = None,
430
+ ) -> None:
431
+ """A brief summary of gene annotation metadata
432
+
433
+ Args:
434
+ reference_id: The type of gene identifier in the meta data, gene_id, ensembl_gene_id, hgnc_id, hgnc_symbol.
435
+ Defaults to "ensembl_gene_id".
436
+ query_id_list: Unique gene identifiers to test the number of matched ids present in the metadata.
437
+ Defaults to None.
438
+ """
439
+ if self.type != "cell_line":
440
+ raise ValueError("This is not a LookUp object specific for CellLineMetaData!")
441
+
442
+ print("To summarize: in the DepMap_Sanger gene annotation file, you can find: ")
443
+ print(f"{len(self.gene_annotation.index)} driver genes")
444
+ print(
445
+ f"{len(self.gene_annotation.columns)} meta data including: ",
446
+ *list(self.gene_annotation.columns.values),
447
+ sep="\n- ",
448
+ )
449
+ print("Overview of gene annotation: ")
450
+ print(self.gene_annotation.head().to_string())
451
+ """
452
+ #not implemented yet
453
+ print("Default parameters to annotate gene annotation: ")
454
+ default_param = {
455
+ "query_id": "ensembl_gene_id",
456
+ }
457
+ print("\n".join(f"- {k}: {v}" for k, v in default_param.items()))
458
+ if query_id_list is not None:
459
+ identifier_num_all = len(query_id_list)
460
+ not_matched_identifiers = list(set(query_id_list) - set(self.gene_annotation[reference_id]))
461
+ print(f"{len(not_matched_identifiers)} genes are not found in the metadata.")
462
+ print(f"{identifier_num_all - len(not_matched_identifiers)} genes are found! ")
463
+ """
464
+
465
+ def available_moa(
466
+ self,
467
+ query_id_list: Sequence[str] | None = None,
468
+ target_list: Sequence[str] | None = None,
469
+ ) -> None:
470
+ """A brief summary of MoA annotation.
471
+
472
+ Args:
473
+ query_id_list: Unique perturbagens to test the number of matched ones present in the metadata.
474
+ If set to None, the query of metadata perturbagens will be disabled.
475
+ Defaults to None.
476
+ target_list: Unique molecular targets to test the number of matched ones present in the metadata.
477
+ If set to None, the comparison of molecular targets in the query of metadata perturbagens will be disabled.
478
+ Defaults to None.
479
+ """
480
+ if self.type != "moa":
481
+ raise ValueError("This is not a LookUp object specific for MoaMetaData!")
482
+ if query_id_list is not None:
483
+ identifier_num_all = len(query_id_list)
484
+ not_matched_identifiers = list(set(query_id_list) - set(self.moa_meta.pert_iname))
485
+ print(f"{len(not_matched_identifiers)} perturbagens are not found in the metadata.")
486
+ print(f"{identifier_num_all - len(not_matched_identifiers)} perturbagens are found! ")
487
+
488
+ if target_list is not None:
489
+ targets = self.moa_meta.target.astype(str).apply(lambda x: x.split("|"))
490
+ all_targets = [t for tl in targets for t in tl]
491
+ identifier_num_all = len(target_list)
492
+ not_matched_identifiers = list(set(target_list) - set(all_targets))
493
+ print(f"{len(not_matched_identifiers)} molecular targets are not found in the metadata.")
494
+ print(f"{identifier_num_all - len(not_matched_identifiers)} molecular targets are found! ")
495
+
496
+ def available_compounds(
497
+ self,
498
+ query_id_list: Sequence[str] | None = None,
499
+ query_id_type: Literal["name", "cid"] = "name",
500
+ ) -> None:
501
+ """A brief summary of compound annotation.
502
+
503
+ Args:
504
+ query_id_list: Unique compounds to test the number of matched ones present in the metadata.
505
+ If set to None, query of compound identifiers will be disabled.
506
+ Defaults to None.
507
+ query_id_type: The type of compound identifiers, name or cid. Defaults to 'name'.
508
+ """
509
+ if self.type != "compound":
510
+ raise ValueError("This is not a LookUp object specific for CompoundData!")
511
+ if query_id_list is not None:
512
+ identifier_num_all = len(query_id_list)
513
+ not_matched_identifiers = []
514
+
515
+ for compound in query_id_list:
516
+ if query_id_type == "name":
517
+ cids = pcp.get_compounds(compound, "name")
518
+ if len(cids) == 0: # search did not work
519
+ not_matched_identifiers.append(compound)
520
+ else:
521
+ try:
522
+ pcp.Compound.from_cid(compound)
523
+ except pcp.BadRequestError:
524
+ not_matched_identifiers.append(compound)
525
+
526
+ print(f"{len(not_matched_identifiers)} compounds are not found in the metadata.")
527
+ print(f"{identifier_num_all - len(not_matched_identifiers)} compounds are found! ")
528
+
529
+ def available_drug_annotation(
530
+ self,
531
+ drug_annotation_source: Literal["chembl", "dgidb", "pharmgkb"] = "chembl",
532
+ query_id_list: Sequence[str] | None = None,
533
+ query_id_type: Literal["target", "compound", "disease"] = "target",
534
+ ) -> None:
535
+ """A brief summary of drug annotation.
536
+
537
+ Args:
538
+ drug_annotation_source: the source of drug annotation data, chembl, dgidb or pharmgkb. Defaults to "chembl".
539
+ query_id_list: Unique target or compound names to test the number of matched ones present in the metadata.
540
+ If set to None, query of compound identifiers will be disabled.
541
+ Defaults to None.
542
+ query_id_type: The type of identifiers, target, compound and disease(pharmgkb only). Defaults to 'target'.
543
+ """
544
+ if self.type != "drug":
545
+ raise ValueError("This is not a LookUp object specific for DrugMetaData!")
546
+ if query_id_list is not None:
547
+ identifier_num_all = len(query_id_list)
548
+ not_matched_identifiers = []
549
+
550
+ if drug_annotation_source == "chembl":
551
+ if query_id_type == "target":
552
+ chembl_targets = {t for target in self.chembl.targets.tolist() for t in target}
553
+ # flatten the target column and remove duplicates
554
+ not_matched_identifiers = list(set(query_id_list) - chembl_targets)
555
+ elif query_id_type == "compound":
556
+ not_matched_identifiers = list(set(query_id_list) - self.chembl["compounds"])
557
+ else:
558
+ raise ValueError(
559
+ "Gene-disease association is not available in chembl dataset, please try with pharmgkb."
560
+ )
561
+
562
+ elif drug_annotation_source == "dgidb":
563
+ if query_id_type == "target":
564
+ not_matched_identifiers = list(set(query_id_list) - set(self.dgidb["gene_claim_name"]))
565
+ elif query_id_type == "compound":
566
+ not_matched_identifiers = list(set(query_id_list) - set(self.dgidb["drug_claim_name"]))
567
+ else:
568
+ raise ValueError(
569
+ "Gene-disease association is not available in dgidb dataset, please try with pharmgkb."
570
+ )
571
+ else:
572
+ if query_id_type == "target":
573
+ not_matched_identifiers = list(set(query_id_list) - set(self.pharmgkb["Gene"]))
574
+ elif query_id_type == "compound":
575
+ compounds = self.pharmgkb[self.pharmgkb["Type"] == "Chemical"]
576
+ not_matched_identifiers = list(set(query_id_list) - set(compounds["Compound|Disease"]))
577
+ else:
578
+ diseases = self.pharmgkb[self.pharmgkb["Type"] == "Disease"]
579
+ not_matched_identifiers = list(set(query_id_list) - set(diseases["Compound|Disease"]))
580
+
581
+ print(f"{len(not_matched_identifiers)} {query_id_type}s are not found in the metadata.")
582
+ print(f"{identifier_num_all - len(not_matched_identifiers)} {query_id_type}s are found! ")
@@ -0,0 +1,73 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Literal
4
+
5
+ if TYPE_CHECKING:
6
+ from collections.abc import Sequence
7
+
8
+
9
+ class MetaData:
10
+ """Superclass for pertpy's MetaData components."""
11
+
12
+ def _warn_unmatch(
13
+ self,
14
+ total_identifiers: int,
15
+ unmatched_identifiers: Sequence[str],
16
+ query_id: str,
17
+ reference_id: str,
18
+ metadata_type: Literal[
19
+ "cell line",
20
+ "protein expression",
21
+ "bulk RNA",
22
+ "drug response",
23
+ "moa",
24
+ "compound",
25
+ ] = "cell line",
26
+ verbosity: int | str = 5,
27
+ ) -> None:
28
+ """Helper function to print out the unmatched identifiers.
29
+
30
+ Args:
31
+ total_identifiers: The total number of identifiers in the `adata` object.
32
+ unmatched_identifiers: Unmatched identifiers in the `adata` object.
33
+ query_id: The column of `.obs` with cell line information.
34
+ reference_id: The type of cell line identifier in the meta data.
35
+ metadata_type: The type of metadata where some identifiers are not matched during annotation such as
36
+ cell line, protein expression, bulk RNA expression, drug response, moa or compound.
37
+ Defaults to 'cell line'.
38
+ verbosity: The number of unmatched identifiers to print, can be either non-negative values or 'all'.
39
+ Defaults to 5.
40
+ """
41
+ if isinstance(verbosity, str):
42
+ if verbosity != "all":
43
+ raise ValueError("Only a non-negative value or 'all' is accepted.")
44
+ else:
45
+ verbosity = len(unmatched_identifiers)
46
+
47
+ if len(unmatched_identifiers) == total_identifiers:
48
+ hint = ""
49
+ if metadata_type in ["protein expression", "bulk RNA", "drug response"]:
50
+ hint = "Additionally, call the `CellLineMetaData.annotate()` function to acquire more possible query IDs that can be used for cell line annotation purposes."
51
+ raise ValueError(
52
+ f"Attempting to match the query id {query_id} in 'adata.obs' to the reference id {reference_id} in the metadata.\n"
53
+ "However, none of the query IDs could be found in the {metadata_type} annotation data.\n"
54
+ "To resolve this issue, call the `lookup()` function to create a LookUp object.\n"
55
+ "This enables obtaining the count of matched identifiers in the AnnData object for different types of reference and query IDs.\n"
56
+ f"{hint}"
57
+ )
58
+ if len(unmatched_identifiers) == 0:
59
+ return
60
+ if isinstance(verbosity, int) and verbosity >= 0:
61
+ verbosity = min(verbosity, len(unmatched_identifiers))
62
+ if verbosity > 0:
63
+ print(
64
+ f"[bold blue]There are {total_identifiers} identifiers in `adata.obs`."
65
+ f"However, {len(unmatched_identifiers)} identifiers can't be found in the {metadata_type} annotation,"
66
+ "leading to the presence of NA values for their respective metadata.\n",
67
+ "Please check again: ",
68
+ *unmatched_identifiers[:verbosity],
69
+ "...",
70
+ sep="\n- ",
71
+ )
72
+ else:
73
+ raise ValueError("Only 'all' or a non-negative value is accepted.")