discotoolkit 1.1.2__tar.gz → 1.1.4__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: discotoolkit
3
- Version: 1.1.2
3
+ Version: 1.1.4
4
4
  Summary: DISCOtoolkit is an python package that allows users to access data and use the tools provided by the DISCO database.
5
5
  Home-page: http://www.immunesinglecell.org/
6
6
  Author: Li Mengwei, Rom Uddamvathanak
@@ -8,7 +8,7 @@
8
8
  -->
9
9
  [![Documentation Status](https://readthedocs.org/projects/discotoolkit-py/badge/?version=latest)](https://discotoolkit-py.readthedocs.io/en/latest/?badge=latest) [![Downloads](https://static.pepy.tech/personalized-badge/discotoolkit?period=total&units=international_system&left_color=black&right_color=orange&left_text=Downloads)](https://pepy.tech/project/discotoolkit) [![PyPI version](https://img.shields.io/pypi/v/discotoolkit)](https://pypi.org/project/discotoolkit)
10
10
 
11
- # DISCOtoolkit 1.1.2
11
+ # DISCOtoolkit 1.1.4
12
12
 
13
13
  DISCOtoolkit is an python package that allows users to access data and use the tools provided by the [DISCO database](https://www.immunesinglecell.org/). Read the documentation [DISCOtoolkit](https://discotoolkit-py.readthedocs.io/en/latest/). It provides the following functions:
14
14
 
@@ -9,10 +9,11 @@ import os
9
9
  import hashlib
10
10
  import requests
11
11
  from scipy import stats
12
+
12
13
  # from fast_fisher import fast_fisher_exact, odds_ratio
13
14
  from scipy.stats.contingency import odds_ratio
14
- from joblib import Parallel, delayed # multiprocessing library
15
- from pandarallel import pandarallel # multiprocessing library
15
+ from joblib import Parallel, delayed # multiprocessing library
16
+ from pandarallel import pandarallel # multiprocessing library
16
17
 
17
18
  pd.options.mode.chained_assignment = None
18
19
 
@@ -24,17 +25,45 @@ from .GetMetadata import check_in_list
24
25
  """
25
26
  CELLiD cell type annotation function block.
26
27
  """
27
- # get the total atlas from DISCO website for the user to select which atlas to use
28
- def get_atlas(ref_data = None, ref_path = None):
29
28
 
29
+
30
+ def generate_correlation_map(x, y):
31
+ """Correlate each n with each m.
32
+
33
+ Parameters
34
+ ----------
35
+ x : np.array
36
+ Shape N X T.
37
+
38
+ y : np.array
39
+ Shape M X T.
40
+
41
+ Returns
42
+ -------
43
+ np.array
44
+ N X M array in which each element is a correlation coefficient.
45
+
46
+ """
47
+ mu_x = x.mean(1)
48
+ mu_y = y.mean(1)
49
+ n = x.shape[1]
50
+ if n != y.shape[1]:
51
+ raise ValueError("x and y must " + "have the same number of timepoints.")
52
+ s_x = x.std(1, ddof=n - 1)
53
+ s_y = y.std(1, ddof=n - 1)
54
+ cov = np.dot(x, y.T) - n * np.dot(mu_x[:, np.newaxis], mu_y[np.newaxis, :])
55
+ return cov / np.dot(s_x[:, np.newaxis], s_y[np.newaxis, :])
56
+
57
+
58
+ # get the total atlas from DISCO website for the user to select which atlas to use
59
+ def get_atlas(ref_data=None, ref_path=None):
30
60
  """get the all the atlas string from the DISCO website and return to the user
31
61
 
32
62
  Returns:
33
63
  List: return list of string
34
- """
64
+ """
35
65
  # Download reference data and ref_deg if missing
36
66
  if ref_data is None:
37
-
38
67
  # check for the data path
39
68
  if ref_path is None:
40
69
  ref_path = "DISCOtmp"
@@ -42,19 +71,33 @@ def get_atlas(ref_data = None, ref_path = None):
42
71
  # if the path does not exist, we create a default directory
43
72
  if not os.path.exists(ref_path):
44
73
  os.mkdir(ref_path)
45
-
74
+
46
75
  # download reference data from the server in pickle extension and read as pandas dataframe
47
76
  if ref_data is None:
48
- if not(os.path.exists(ref_path + "/ref_data.pkl")):
77
+ if not (os.path.exists(ref_path + "/ref_data.pkl")):
49
78
  logging.info("Downloading reference dataset...")
50
- response = requests.get(url=prefix_disco_url +"/getRefPkl", timeout=timeout)
79
+ response = requests.get(
80
+ url=prefix_disco_url + "toolkit/getRef?type=pkl", timeout=timeout
81
+ )
51
82
  open(ref_path + "/ref_data.pkl", "wb").write(response.content)
52
- ref_data = pd.read_pickle(ref_path + "/ref_data.pkl", compression = {'method':'gzip','compresslevel':6})
83
+ ref_data = pd.read_pickle(
84
+ ref_path + "/ref_data.pkl",
85
+ compression={"method": "gzip", "compresslevel": 6},
86
+ )
53
87
 
54
88
  all_atlas = [each.split("--")[1] for each in ref_data.columns]
55
89
  return list(set(all_atlas))
56
90
 
57
- def CELLiD_cluster(rna, ref_data : pd.DataFrame = None, ref_deg : pd.DataFrame = None, atlas : str = None, n_predict : int = 1, ref_path : str = None, ncores : int = 10):
91
+
92
+ def CELLiD_cluster(
93
+ rna,
94
+ ref_data: pd.DataFrame = None,
95
+ ref_deg: pd.DataFrame = None,
96
+ atlas: str = None,
97
+ n_predict: int = 1,
98
+ ref_path: str = None,
99
+ ncores: int = 10,
100
+ ):
58
101
  """Cell type annotation using reference data and compute the correlation between the user cell gene expression as compare
59
102
  to the reference data. The celltype with highest correlation will be concluded as the celltype
60
103
 
@@ -73,20 +116,21 @@ def CELLiD_cluster(rna, ref_data : pd.DataFrame = None, ref_deg : pd.DataFrame =
73
116
 
74
117
  # initialize the pandarallel for parallel processing
75
118
  pandarallel.initialize(nb_workers=ncores)
76
-
119
+
77
120
  # check for the input data
78
- if not(isinstance(rna, pd.DataFrame) or isinstance(rna, np.ndarray)):
121
+ if not (isinstance(rna, pd.DataFrame) or isinstance(rna, np.ndarray)):
79
122
  logging.error("the rna must be a pandas DataFrame or Numpy Array")
80
123
 
81
124
  # check for number of prediction of celltypes and set the largest number to 3 only
82
125
  if n_predict is not None:
83
126
  if n_predict > 3:
84
- logging.info("Any value of n_predict that exceeds 3 will be automatically adjusted to 3.")
127
+ logging.info(
128
+ "Any value of n_predict that exceeds 3 will be automatically adjusted to 3."
129
+ )
85
130
  n_predict = 3
86
-
131
+
87
132
  # Download reference data and ref_deg if missing
88
133
  if (ref_data is None) or (ref_deg is None):
89
-
90
134
  # check for the data path
91
135
  if ref_path is None:
92
136
  ref_path = "DISCOtmp"
@@ -94,42 +138,60 @@ def CELLiD_cluster(rna, ref_data : pd.DataFrame = None, ref_deg : pd.DataFrame =
94
138
  # if the path does not exist, we create a default directory
95
139
  if not os.path.exists(ref_path):
96
140
  os.mkdir(ref_path)
97
-
141
+
98
142
  # download reference data from the server in pickle extension and read as pandas dataframe
99
143
  if ref_data is None:
100
- if not(os.path.exists(ref_path + "/ref_data.pkl")):
144
+ if not (os.path.exists(ref_path + "/ref_data.pkl")):
101
145
  logging.info("Downloading reference dataset...")
102
- response = requests.get(url=prefix_disco_url +"/getRefPkl", timeout=timeout)
146
+ response = requests.get(
147
+ url=prefix_disco_url + "toolkit/getRef?type=pkl", timeout=timeout
148
+ )
103
149
  open(ref_path + "/ref_data.pkl", "wb").write(response.content)
104
- ref_data = pd.read_pickle(ref_path + "/ref_data.pkl", compression = {'method':'gzip','compresslevel':6})
150
+ ref_data = pd.read_pickle(
151
+ ref_path + "/ref_data.pkl",
152
+ compression={"method": "gzip", "compresslevel": 6},
153
+ )
105
154
 
106
155
  # similarly do the same for the DEG reference
107
156
  if ref_deg is None:
108
- if not(os.path.exists(ref_path + "/ref_deg.pkl")):
157
+ if not (os.path.exists(ref_path + "/ref_deg.pkl")):
109
158
  logging.info("Downloading deg dataset...")
110
- response = requests.get(url=prefix_disco_url +"/getRefDegPkl", timeout=timeout)
159
+ response = requests.get(
160
+ url=prefix_disco_url + "toolkit/getRefDeg?type=pkl", timeout=timeout
161
+ )
111
162
  open(ref_path + "/ref_deg.pkl", "wb").write(response.content)
112
- ref_deg = pd.read_pickle(ref_path + "/ref_deg.pkl", compression = {'method':'gzip','compresslevel':6})
113
-
163
+ ref_deg = pd.read_pickle(
164
+ ref_path + "/ref_deg.pkl",
165
+ compression={"method": "gzip", "compresslevel": 6},
166
+ )
167
+
114
168
  ####
115
169
  # write list of atlas function
116
170
  # we can write a function to get all the atlas from disco to the users
117
171
  # subsetting to the selected atlas by the user
118
172
  if atlas is not None:
119
- select_ref = [index for index, each in enumerate(ref_data.columns) if each.split("--")[1] in list(atlas)]
173
+ select_ref = [
174
+ index
175
+ for index, each in enumerate(ref_data.columns)
176
+ if each.split("--")[1] in list(atlas)
177
+ ]
120
178
  ref_data = ref_data.iloc[:, select_ref]
121
-
179
+
122
180
  # get the intersection of the gene for the user data and the reference data
123
181
  genes = set.intersection(set(rna.index), set(ref_data.index))
124
182
 
125
183
  # give an error as 2000 genes are very low
126
184
  if len(genes) <= 2000:
127
- logging.error("Less than 2000 genes are shared between the input data and the reference dataset!")
185
+ logging.error(
186
+ "Less than 2000 genes are shared between the input data and the reference dataset!"
187
+ )
128
188
 
129
189
  # give a warning to the user
130
190
  if len(genes) <= 5000:
131
- logging.warning("The input data and reference dataset have a limited number of overlapping genes, which may potentially impact the accuracy of the CELLiD.")
132
-
191
+ logging.warning(
192
+ "The input data and reference dataset have a limited number of overlapping genes, which may potentially impact the accuracy of the CELLiD."
193
+ )
194
+
133
195
  # subsetting the dataframe to the common genes across data and the reference
134
196
  rna = rna.loc[list(genes)]
135
197
  ref_data = ref_data.loc[list(genes)]
@@ -137,7 +199,7 @@ def CELLiD_cluster(rna, ref_data : pd.DataFrame = None, ref_deg : pd.DataFrame =
137
199
  # nested apply function to compute correlation for each cell type between the user and reference database
138
200
  def each_ref_correlation(input, ref_data):
139
201
  input = list(input)
140
- res = ref_data.parallel_apply(basic_correlation, input = input, axis = 0)
202
+ res = ref_data.parallel_apply(basic_correlation, input=input, axis=0)
141
203
  return res
142
204
 
143
205
  # apply the correlation to all the columns in user data
@@ -148,9 +210,14 @@ def CELLiD_cluster(rna, ref_data : pd.DataFrame = None, ref_deg : pd.DataFrame =
148
210
  predicted = pd.Series(list(ref)).corr(pd.Series(list(input)), method="spearman")
149
211
 
150
212
  return predicted
151
-
213
+
152
214
  # get the predicted correlation as in pandas DataFrame
153
- predicted_cell = rna.apply(each_ref_correlation, result_type = "expand", axis = 0, ref_data = ref_data)
215
+ # predicted_cell = pd.DataFrame(
216
+ # generate_correlation_map(ref_data.to_numpy().T, rna.to_numpy().T)
217
+ # )
218
+ predicted_cell = rna.apply(
219
+ each_ref_correlation, result_type="expand", axis=0, ref_data=ref_data
220
+ )
154
221
  predicted_cell = pd.DataFrame(predicted_cell)
155
222
 
156
223
  # set the index to be the celltype based on the reference_data
@@ -161,60 +228,84 @@ def CELLiD_cluster(rna, ref_data : pd.DataFrame = None, ref_deg : pd.DataFrame =
161
228
  # define a function to apply to each column of the dataframe
162
229
  def get_top_5_indices(col):
163
230
  # get the indices of the top 5 values in the column
164
- indices = np.where(col.rank(method='min', ascending=False) <= 5)[0]
231
+ indices = np.where(col.rank(method="min", ascending=False) <= 5)[0]
165
232
  # convert to numeric and return
166
- return pd.Series(indices).astype('int')
167
-
168
- ct = predicted_cell.apply(get_top_5_indices)
169
-
170
- # ct = pd.DataFrame(predicted_cell.parallel_apply(lambda x: [index for index, each in enumerate(x.rank()) if each <= 5], axis = 0, result_type = "expand"))
233
+ return pd.Series(indices).astype("int")
171
234
 
235
+ ct = predicted_cell.apply(get_top_5_indices)
172
236
  # compute the correleration based on the genes set that is intersection between the user data and reference dataset
237
+
173
238
  def second_correlation(i, ref_data, rna, ct):
174
- ref = ref_data.iloc[:,ct[i]].copy()
175
- g = set(ref_deg.iloc[check_in_list(ref_deg["group"], ref.columns)].copy()["gene"])
239
+ ref = ref_data.iloc[:, list(ct[str(i)])].copy()
240
+ g = set(
241
+ ref_deg.iloc[check_in_list(ref_deg["group"], ref.columns)].copy()["gene"]
242
+ )
176
243
  g = set.intersection(set(ref.index), g)
177
244
  ref = ref.loc[list(g)].copy()
178
- input = rna.loc[list(g), i].copy()
245
+ # print(rna.loc[list(g), str(i)])
246
+ input = rna.loc[list(g), str(i)].copy()
179
247
  # predict = ref.apply(lambda i: np.round(stats.spearmanr(pd.to_numeric(i), pd.to_numeric(input), nan_policy='omit')[0], 3))
180
- predict = ref.apply(lambda i: np.round(pd.Series(i).corr(pd.Series(input), method='spearman'), 3)) # trying with pandas correlation
248
+ predict = ref.apply(
249
+ lambda i: np.round(
250
+ pd.Series(i).corr(pd.Series(input), method="spearman"), 3
251
+ )
252
+ ) # trying with pandas correlation
181
253
  predict = pd.DataFrame(predict)
182
254
  predict.columns = ["cor"]
183
- predict = predict.sort_values(["cor"], ascending = False)
184
- res = [[each.split("--")[0], each.split("--")[1], predict["cor"][index], i] for index, each in enumerate(predict.index) if index < n_predict]
185
- res = pd.DataFrame(res, columns =['cell_type', 'atlas', "score", "input_index"])
255
+ predict = predict.sort_values(["cor"], ascending=False)
256
+ res = [
257
+ [each.split("--")[0], each.split("--")[1], predict["cor"][index], i]
258
+ for index, each in enumerate(predict.index)
259
+ if index < n_predict
260
+ ]
261
+ res = pd.DataFrame(res, columns=["cell_type", "atlas", "score", "input_index"])
186
262
  return res # return list in the format cell_type, atlas, score, input_index
187
263
 
188
264
  # get a data in the format of cell_type, atlas, score, input_index
189
- predicted_cell = Parallel(n_jobs=ncores, batch_size=32, verbose = 2)(delayed(second_correlation)(int(y), ref_data, rna, ct) for y in range(rna.shape[1]))
265
+ predicted_cell = Parallel(n_jobs=ncores, batch_size=32, verbose=2)(
266
+ delayed(second_correlation)(int(y), ref_data, rna, ct)
267
+ for y in range(rna.shape[1])
268
+ )
190
269
 
191
270
  # first concatenate in row wise manner
192
271
  predicted_cell = pd.concat(predicted_cell)
193
272
 
194
- pivot = pd.pivot_table(predicted_cell, index='input_index', columns=predicted_cell.groupby('input_index').cumcount()+1,
195
- values=['cell_type', 'atlas', 'score'], aggfunc='first')
273
+ pivot = pd.pivot_table(
274
+ predicted_cell,
275
+ index="input_index",
276
+ columns=predicted_cell.groupby("input_index").cumcount() + 1,
277
+ values=["cell_type", "atlas", "score"],
278
+ aggfunc="first",
279
+ )
196
280
 
197
- pivot = pivot[["cell_type", "atlas", "score"]]
281
+ pivot = pivot[["cell_type", "atlas", "score"]]
198
282
 
199
283
  # flatten multi-level column index
200
- pivot.columns = ['_'.join(map(str, col)).strip() for col in pivot.columns.values]
284
+ pivot.columns = ["_".join(map(str, col)).strip() for col in pivot.columns.values]
201
285
 
202
286
  # rename columns
203
287
  column_names = {}
204
288
  for i in range(n_predict):
205
- column_names[f'cell_type_{i+1}'] = f'predicted_cell_type_{i+1}'
206
- column_names[f'atlas_{i+1}'] = f'source_atlas_{i+1}'
207
- column_names[f'score_{i+1}'] = f'score_{i+1}'
208
-
289
+ column_names[f"cell_type_{i+1}"] = f"predicted_cell_type_{i+1}"
290
+ column_names[f"atlas_{i+1}"] = f"source_atlas_{i+1}"
291
+ column_names[f"score_{i+1}"] = f"score_{i+1}"
292
+
209
293
  pivot = pivot.rename(columns=column_names)
210
294
 
211
- return pivot# return pandas dataframe in the format the same original R package
295
+ return pivot # return pandas dataframe in the format the same original R package
296
+
212
297
 
213
298
  """
214
299
  Geneset enrichment analysis using DISCO data
215
300
  """
216
301
 
217
- def CELLiD_enrichment(input : pd.DataFrame, reference : pd.DataFrame = None, ref_path : str = None, ncores : int = 1):
302
+
303
+ def CELLiD_enrichment(
304
+ input: pd.DataFrame,
305
+ reference: pd.DataFrame = None,
306
+ ref_path: str = None,
307
+ ncores: int = 1,
308
+ ):
218
309
  """Function to generate enrichment analysis based on the reference gene sets and following the DISCO pipeline.
219
310
 
220
311
  Args:
@@ -229,7 +320,7 @@ def CELLiD_enrichment(input : pd.DataFrame, reference : pd.DataFrame = None, ref
229
320
 
230
321
  # check input data
231
322
  # check if the input type is a DataFrame
232
- if not(isinstance(input, pd.DataFrame)):
323
+ if not (isinstance(input, pd.DataFrame)):
233
324
  logging.error("The input must be a dataframe")
234
325
 
235
326
  # check if the user provide more than the needed column which are gene and fc
@@ -240,7 +331,7 @@ def CELLiD_enrichment(input : pd.DataFrame, reference : pd.DataFrame = None, ref
240
331
  if input.shape[1] == 2:
241
332
  input_shape = 2
242
333
  input.columns = ["gene", "fc"]
243
-
334
+
244
335
  # else we can just take a gene list for the enrichment
245
336
  else:
246
337
  input_shape = 1
@@ -248,7 +339,6 @@ def CELLiD_enrichment(input : pd.DataFrame, reference : pd.DataFrame = None, ref
248
339
 
249
340
  # if the user does not provide reference geneset list
250
341
  if reference is None:
251
-
252
342
  # check for the data path if it is provided by the user
253
343
  if ref_path is None:
254
344
  ref_path = "DISCOtmp"
@@ -256,31 +346,45 @@ def CELLiD_enrichment(input : pd.DataFrame, reference : pd.DataFrame = None, ref
256
346
  # if the path does not exist, we create a default directory
257
347
  if not os.path.exists(ref_path):
258
348
  os.mkdir(ref_path)
259
-
349
+
260
350
  # check if the file does not exist
261
351
  if not (os.path.exists(ref_path + "/ref_geneset.pkl")):
262
352
  # downloading the geneset data from disco database
263
- response = requests.get(url=prefix_disco_url +"/getGeneSetPkl", timeout=timeout)
353
+ response = requests.get(
354
+ url=prefix_disco_url + "/getGeneSetPkl", timeout=timeout
355
+ )
264
356
  open(ref_path + "/ref_geneset.pkl", "wb").write(response.content)
265
- reference = pd.read_pickle(ref_path + "/ref_geneset.pkl", compression = {'method':'gzip','compresslevel':6})
357
+ reference = pd.read_pickle(
358
+ ref_path + "/ref_geneset.pkl",
359
+ compression={"method": "gzip", "compresslevel": 6},
360
+ )
266
361
 
267
362
  else:
268
363
  # read the data into pandas dataframe for subsequent analysis
269
- reference = pd.read_pickle(ref_path + "/ref_geneset.pkl", compression = {'method':'gzip','compresslevel':6})
364
+ reference = pd.read_pickle(
365
+ ref_path + "/ref_geneset.pkl",
366
+ compression={"method": "gzip", "compresslevel": 6},
367
+ )
270
368
 
271
369
  # rename the name data to include the reference atlas
272
370
  reference["name"] = reference["name"] + " in " + reference["atlas"]
273
- input["gene"] = input["gene"].str.upper() # convert all the gene to upper string as the reference gene name is in uppercase
371
+ input["gene"] = input[
372
+ "gene"
373
+ ].str.upper() # convert all the gene to upper string as the reference gene name is in uppercase
274
374
  # condition when the user provide the fold change for the enrichment analysis
275
375
  if input_shape == 2:
276
- input["fc"] = 2 ** input["fc"] # 2 to the power of fc
277
- input = input.set_index("gene", drop = False) # set index to the gene
278
- input = input.loc[list(set(reference["gene"]) & set(input['gene']))] # only get the common genes for comparison
376
+ input["fc"] = 2 ** input["fc"] # 2 to the power of fc
377
+ input = input.set_index("gene", drop=False) # set index to the gene
378
+ input = input.loc[
379
+ list(set(reference["gene"]) & set(input["gene"]))
380
+ ] # only get the common genes for comparison
279
381
 
280
382
  # else we only look at the ranked gene list
281
383
  else:
282
- input = input.set_index("gene", drop = False)
283
- input = input.loc[list(set(reference["gene"]) & set(input['gene']))] # only get the common genes for comparison
384
+ input = input.set_index("gene", drop=False)
385
+ input = input.loc[
386
+ list(set(reference["gene"]) & set(input["gene"]))
387
+ ] # only get the common genes for comparison
284
388
  # filter to get only the geneset that contain the input genes from the user
285
389
  # this might good different result from the website so lets remove it for
286
390
  # unique_names = reference[reference["gene"].isin(input["gene"])]["name"].unique()
@@ -291,8 +395,8 @@ def CELLiD_enrichment(input : pd.DataFrame, reference : pd.DataFrame = None, ref
291
395
  # optimise the CELLiD_enrichment function
292
396
  atlas_dict = {}
293
397
  name_dict = {}
294
- reference_atlas = reference['atlas']
295
- reference_name = reference['name']
398
+ reference_atlas = reference["atlas"]
399
+ reference_name = reference["name"]
296
400
 
297
401
  # pre compute the parameters of the fisher exact test for the reference data
298
402
  for rownum in range(len(reference)):
@@ -305,57 +409,105 @@ def CELLiD_enrichment(input : pd.DataFrame, reference : pd.DataFrame = None, ref
305
409
  name_dict[reference_name[rownum]] = [rownum]
306
410
  else:
307
411
  name_dict[reference_name[rownum]].append(rownum)
308
-
412
+
309
413
  # apply function to the dataframe
310
- def process_unique_name(reference_filter, input, atlas_dfs, input_shape, atlas_dict):
414
+ def process_unique_name(
415
+ reference_filter, input, atlas_dfs, input_shape, atlas_dict
416
+ ):
311
417
  # use the compile`d pattern to search for matches
312
- unique_name = reference_filter['name'].head(1).values[0]
313
- atlas = reference_filter['atlas'].head(1).values
418
+ unique_name = reference_filter["name"].head(1).values[0]
419
+ atlas = reference_filter["atlas"].head(1).values
314
420
  # print(unique_name)
315
421
  reference_full = atlas_dfs[list(atlas_dict.keys()).index(atlas)]
316
422
  # reference_filter = reference.iloc[name_dict[unique_name]].copy() # subset the reference data
317
423
  # reference_full = reference.iloc[atlas_dict[atlas]].copy() # full reference to the atlas
318
- reference_filter = reference_filter.set_index(["gene"], drop = False) # set gene as the index
424
+ reference_filter = reference_filter.set_index(
425
+ ["gene"], drop=False
426
+ ) # set gene as the index
319
427
  # reference_filter["gene"] = reference_filter.index
320
- input_filter = input.loc[list(set(reference_full["gene"]) & set(input["gene"]))] # subset the input genes
428
+ input_filter = input.loc[
429
+ list(set(reference_full["gene"]) & set(input["gene"]))
430
+ ] # subset the input genes
321
431
 
322
432
  # condition for no passed gene set
323
433
  if input_filter.empty:
324
434
  return None
325
-
435
+
326
436
  # different computation to either include the fold change in the fisher exact test
327
437
  if input_shape == 2:
328
- a = (reference_filter.loc[np.intersect1d(reference_filter["gene"], (input_filter["gene"]))].iloc[:, 0] * input_filter.loc[np.intersect1d(input_filter["gene"], reference_filter["gene"]), "fc"]).sum() + 1
329
- b = input_filter.loc[np.setdiff1d(input_filter["gene"], reference_filter["gene"]), "fc"].sum() + 1
330
- c = reference_filter.loc[np.setdiff1d(reference_filter["gene"], input_filter["gene"])].iloc[:, 0].sum() + 1
331
- d = len(set(reference_full["gene"])) - len(set(reference_filter["gene"]).union(set(input_filter["gene"])))
438
+ a = (
439
+ reference_filter.loc[
440
+ np.intersect1d(reference_filter["gene"], (input_filter["gene"]))
441
+ ].iloc[:, 0]
442
+ * input_filter.loc[
443
+ np.intersect1d(input_filter["gene"], reference_filter["gene"]), "fc"
444
+ ]
445
+ ).sum() + 1
446
+ b = (
447
+ input_filter.loc[
448
+ np.setdiff1d(input_filter["gene"], reference_filter["gene"]), "fc"
449
+ ].sum()
450
+ + 1
451
+ )
452
+ c = (
453
+ reference_filter.loc[
454
+ np.setdiff1d(reference_filter["gene"], input_filter["gene"])
455
+ ]
456
+ .iloc[:, 0]
457
+ .sum()
458
+ + 1
459
+ )
460
+ d = len(set(reference_full["gene"])) - len(
461
+ set(reference_filter["gene"]).union(set(input_filter["gene"]))
462
+ )
332
463
  else:
333
464
  a = len(np.intersect1d(reference_filter["gene"], input_filter["gene"])) + 1
334
465
  b = len(np.setdiff1d(input_filter["gene"], reference_filter["gene"])) + 1
335
466
  c = len(np.setdiff1d(reference_filter["gene"], input_filter["gene"])) + 1
336
467
  d = len(set(reference_full["gene"])) - a - b - c
337
-
468
+
338
469
  # get both value from the fisher exact test
339
470
  # pval = pvalue(a, b, c, d).two_tail
340
471
  _, pval = stats.fisher_exact(np.array([[a, b], [c, d]]))
341
- odds = (a * d)/(b * c)
472
+ odds = (a * d) / (b * c)
342
473
  # only get the significant p_value
343
474
  # we can make changes to the p_value as in like we allow the user to specify it so that they have more control on the result they can obtain
344
475
  if pval < 0.01:
345
- return pd.Series({"pval": pval, "or": odds, "name": unique_name,
346
- "gene": ",".join(reference_filter.loc[reference_filter["gene"].isin(input_filter["gene"]), "gene"]),
347
- "background": len(set(reference_full["gene"])), "overlap": len(reference_filter.loc[reference_filter["gene"].isin(input_filter["gene"])]), "geneset": len(reference_filter)})
476
+ return pd.Series(
477
+ {
478
+ "pval": pval,
479
+ "or": odds,
480
+ "name": unique_name,
481
+ "gene": ",".join(
482
+ reference_filter.loc[
483
+ reference_filter["gene"].isin(input_filter["gene"]), "gene"
484
+ ]
485
+ ),
486
+ "background": len(set(reference_full["gene"])),
487
+ "overlap": len(
488
+ reference_filter.loc[
489
+ reference_filter["gene"].isin(input_filter["gene"])
490
+ ]
491
+ ),
492
+ "geneset": len(reference_filter),
493
+ }
494
+ )
348
495
  else:
349
496
  return None
350
497
 
351
498
  # Split them into cores
352
499
  unique_name_dfs = [reference.iloc[name_dict[key], :] for key in name_dict.keys()]
353
500
  atlas_dfs = [reference.iloc[atlas_dict[key], :] for key in atlas_dict.keys()]
354
-
501
+
355
502
  # return unique_name_dfs, atlas_dfs, input, input_shape
356
503
  # return unique_name_dfs, atlas_dfs
357
504
  # using joblib to apply multiprocessing
358
- results = Parallel(n_jobs=ncores, verbose = 2, batch_size = 64)(delayed(process_unique_name)(unique_name_df, input, atlas_dfs, input_shape, atlas_dict) for unique_name_df in unique_name_dfs)
505
+ results = Parallel(n_jobs=ncores, verbose=2, batch_size=64)(
506
+ delayed(process_unique_name)(
507
+ unique_name_df, input, atlas_dfs, input_shape, atlas_dict
508
+ )
509
+ for unique_name_df in unique_name_dfs
510
+ )
359
511
  results = [res for res in results if res is not None]
360
512
 
361
513
  # concatenate the result into the dataframe to the user
@@ -363,8 +515,9 @@ def CELLiD_enrichment(input : pd.DataFrame, reference : pd.DataFrame = None, ref
363
515
  res_df = pd.concat(results, axis=1).transpose()
364
516
  res_df["pval"] = res_df["pval"].astype(float).round(3)
365
517
  res_df["or"] = res_df["or"].astype(float).round(3)
366
- res_df = res_df.sort_values(by=["pval", "or"], ascending=[True, False]).head(min(50, len(results)))
518
+ res_df = res_df.sort_values(by=["pval", "or"], ascending=[True, False]).head(
519
+ min(50, len(results))
520
+ )
367
521
  return res_df
368
522
  else:
369
523
  return None
370
-
@@ -6,10 +6,10 @@ class Filter:
6
6
  """
7
7
  Filter class object to save the attributes for filtering the dataset from DISCO
8
8
 
9
- sample String e.g. GSM3891625_3;
10
- project String;
11
- tissue String e.g. Lung, Bladder;
12
- disease String e.g. PDAC;
9
+ sample_id String e.g. ERX2757110;
10
+ project_id String;
11
+ tissue String e.g. lung, bladder;
12
+ disease String e.g. COVID-19;
13
13
  platform String e.g. 10x3';
14
14
  sample_type String;
15
15
  cell_type String;
@@ -20,12 +20,12 @@ class Filter:
20
20
  return Class object
21
21
  """
22
22
 
23
- def __init__(self, sample = None, project = None, tissue = None, disease = None, platform = None, sample_type = None,
23
+ def __init__(self, sample_id = None, project_id = None, tissue = None, disease = None, platform = None, sample_type = None,
24
24
  cell_type = None, cell_type_confidence : str = "medium", include_cell_type_children : bool = True, min_cell_per_sample : int = 100):
25
25
 
26
26
  # handling for string and list input
27
- self.sample = self.convert_to_list(sample) # sample id
28
- self.project = self.convert_to_list(project) # project, lab, or dataset from different author
27
+ self.sample_id = self.convert_to_list(sample_id) # sample id
28
+ self.project_id = self.convert_to_list(project_id) # project, lab, or dataset from different author
29
29
  self.tissue = self.convert_to_list(tissue) # organ tissue
30
30
  self.disease = self.convert_to_list(disease) # cancer or non cancer, or COVID-1e9 disease
31
31
  self.platform = self.convert_to_list(platform) # sequencing platform