discotoolkit 1.1.4__tar.gz → 1.2.1__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.
Files changed (32) hide show
  1. discotoolkit-1.2.1/MANIFEST.in +2 -0
  2. discotoolkit-1.2.1/PKG-INFO +146 -0
  3. discotoolkit-1.2.1/README.md +111 -0
  4. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/CELLiD.py +90 -56
  5. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/DiscoClass.py +29 -17
  6. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/DownloadDiscoData.py +12 -8
  7. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/GeneSearch.py +9 -7
  8. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/GetMetadata.py +18 -20
  9. discotoolkit-1.2.1/discotoolkit/GlobalVariable.py +81 -0
  10. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/__init__.py +2 -1
  11. discotoolkit-1.2.1/discotoolkit.egg-info/PKG-INFO +146 -0
  12. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit.egg-info/SOURCES.txt +9 -1
  13. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit.egg-info/requires.txt +4 -0
  14. discotoolkit-1.2.1/pyproject.toml +3 -0
  15. discotoolkit-1.2.1/requirements.txt +12 -0
  16. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/setup.py +12 -6
  17. discotoolkit-1.2.1/tests/test_docs.py +90 -0
  18. discotoolkit-1.2.1/tests/test_gene_search.py +61 -0
  19. discotoolkit-1.2.1/tests/test_reference_loading.py +98 -0
  20. discotoolkit-1.2.1/tests/test_server_contract.py +173 -0
  21. discotoolkit-1.2.1/tests/test_settings.py +90 -0
  22. discotoolkit-1.2.1/tests/test_version.py +41 -0
  23. discotoolkit-1.1.4/MANIFEST.in +0 -1
  24. discotoolkit-1.1.4/PKG-INFO +0 -13
  25. discotoolkit-1.1.4/README.md +0 -72
  26. discotoolkit-1.1.4/discotoolkit/GlobalVariable.py +0 -33
  27. discotoolkit-1.1.4/discotoolkit.egg-info/PKG-INFO +0 -13
  28. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/CellMapper.py +0 -0
  29. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/Utilities.py +0 -0
  30. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit.egg-info/dependency_links.txt +0 -0
  31. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit.egg-info/top_level.txt +0 -0
  32. {discotoolkit-1.1.4 → discotoolkit-1.2.1}/setup.cfg +0 -0
@@ -0,0 +1,2 @@
1
+ include README.md
2
+ include requirements.txt
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.4
2
+ Name: discotoolkit
3
+ Version: 1.2.1
4
+ Summary: DISCOtoolkit is an python package that allows users to access data and use the tools provided by the DISCO database.
5
+ Home-page: https://disco.bii.a-star.edu.sg/
6
+ Author: Li Mengwei, Rom Uddamvathanak
7
+ Author-email: uddamvathanak_rom@immunol.a-star.edu.sg
8
+ Project-URL: Documentation, https://disco.bii.a-star.edu.sg/v1/docs/toolkit/guide/
9
+ Project-URL: Source, https://github.com/JinmiaoChenLab/DISCOtoolkit_py
10
+ Project-URL: Issues, https://github.com/JinmiaoChenLab/DISCOtoolkit_py/issues
11
+ Project-URL: DISCO, https://disco.bii.a-star.edu.sg/v1/
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: pandas>=1.4.2
15
+ Requires-Dist: numpy>=1.21.6
16
+ Requires-Dist: scanpy>=1.9.3
17
+ Requires-Dist: scipy>=1.10.1
18
+ Requires-Dist: joblib>=1.1.0
19
+ Requires-Dist: pandarallel>=1.6.5
20
+ Requires-Dist: requests>=2.28.1
21
+ Requires-Dist: colorcet>=3.0.1
22
+ Requires-Dist: leidenalg
23
+ Requires-Dist: h5py>=3.8
24
+ Requires-Dist: matplotlib>=3.5
25
+ Requires-Dist: seaborn>=0.12
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: description
29
+ Dynamic: description-content-type
30
+ Dynamic: home-page
31
+ Dynamic: project-url
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
35
+
36
+ <!--
37
+ * @Descripttion:
38
+ * @version:
39
+ * @Author: Mengwei Li
40
+ * @Date: 2023-04-16 21:20:42
41
+ * @LastEditors: Mengwei Li
42
+ * @LastEditTime: 2023-04-16 21:22:03
43
+ -->
44
+ [![Documentation](https://img.shields.io/badge/docs-disco.bii.a--star.edu.sg-blue)](https://disco.bii.a-star.edu.sg/v1/docs/toolkit/guide/) [![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)
45
+
46
+ # DISCOtoolkit 1.2.1
47
+
48
+ DISCOtoolkit is a Python package for accessing the data and tools of the [DISCO database](https://disco.bii.a-star.edu.sg/) (DISCO v1). Read the documentation, with tutorials and the API reference, at [disco.bii.a-star.edu.sg/v1/docs/toolkit/guide](https://disco.bii.a-star.edu.sg/v1/docs/toolkit/guide/).
49
+
50
+ - Filter and download DISCO data based on sample metadata and cell type information
51
+ - Gene search: a gene's expression across cell types and tissues
52
+ - CELLiD: cell type annotation
53
+ - scEnrichment: gene set enrichment using DISCO DEGs
54
+
55
+ > **DISCO v1 and v2.** The toolkit talks to **DISCO v1** by default. DISCO v2 has its own R package ([DISCOtoolkit](https://github.com/JinmiaoChenLab/DISCOtoolkit)); the Python package can still be pointed at a v2 server, see [Choosing a server](#choosing-a-server).
56
+
57
+ ## Quickstart (Google Colab)
58
+
59
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/JinmiaoChenLab/DISCOtoolkit_py/blob/main/docs/quickstart_disco_v1.ipynb)
60
+
61
+ Installs, checks the server, filters, downloads and plots in about ten cells, with nothing to set up locally.
62
+
63
+ ## Installation
64
+
65
+ Python 3.9 or newer. In your current environment:
66
+
67
+ ```
68
+ pip install discotoolkit
69
+ ```
70
+
71
+ To try the latest development version straight from GitHub:
72
+
73
+ ```
74
+ pip install "git+https://github.com/JinmiaoChenLab/DISCOtoolkit_py.git"
75
+ ```
76
+
77
+ To work on the code, or to test changes before they are released, install from a local clone. `-e` links the install to the folder, so edits take effect without reinstalling:
78
+
79
+ ```
80
+ git clone https://github.com/JinmiaoChenLab/DISCOtoolkit_py.git
81
+ cd DISCOtoolkit_py
82
+ pip install -e .
83
+ ```
84
+
85
+ `pip install discotoolkit` and a local install give the same code when the versions match. The difference is the source: PyPI delivers a released, packaged copy, while a local install uses the files in your folder.
86
+
87
+ Dependencies (installed automatically): numpy, pandas, scanpy, scipy, joblib, pandarallel, requests, colorcet, leidenalg, h5py, matplotlib, seaborn.
88
+
89
+ We recommend a virtual environment, for example with miniconda:
90
+
91
+ ```
92
+ conda create --name disco python=3.10
93
+ conda activate disco
94
+ conda install ipykernel
95
+ python -m ipykernel install --user --name disco --display-name "disco"
96
+ python -m pip install -U discotoolkit
97
+ ```
98
+
99
+ ## Choosing a server
100
+
101
+ ```python
102
+ import discotoolkit as dt
103
+
104
+ dt.get_server() # 'https://disco.bii.a-star.edu.sg/disco_v3_api/' (DISCO v1, the default)
105
+ dt.set_server("v2") # DISCO v2
106
+ dt.set_server("https://my.server/disco_v3_api/") # any server with the same API
107
+ ```
108
+
109
+ or set the `DISCO_API_URL` environment variable before importing the package.
110
+
111
+ ## Testing
112
+
113
+ Two small test files need nothing beyond `requests`, so they run anywhere, including Colab:
114
+
115
+ ```
116
+ python tests/test_settings.py # offline: server selection logic
117
+ python tests/test_version.py # offline: setup.py and __init__.py agree on the version
118
+ python tests/test_docs.py # offline: notebooks are clean, every public function is in the API reference
119
+ python tests/test_server_contract.py # online: does the server answer everything the toolkit needs?
120
+ python tests/test_server_contract.py https://immunesinglecell.org/disco_v3_api/ # check another server
121
+ ```
122
+
123
+ GitHub Actions runs these, and installs the package on Python 3.9-3.12, on every push. Maintainers: see [RELEASING.md](RELEASING.md) for how a release, and its documentation, is published.
124
+
125
+ `test_server_contract.py` checks status codes and the shape of each response (the columns and file types the toolkit reads). It only samples the large reference files, it does not download them.
126
+
127
+ ## Basic Usage
128
+ Example in Jupyter notebook.
129
+
130
+ <em>please select disco as the kernel for running the jupyter notebook</em>
131
+
132
+ ### [Quickstart for DISCO v1](https://github.com/JinmiaoChenLab/DISCOtoolkit_py/blob/main/docs/quickstart_disco_v1.ipynb)
133
+
134
+ ### [Filter and download DISCO data](https://github.com/JinmiaoChenLab/DISCOtoolkit_py/blob/main/docs/download_data.ipynb)
135
+
136
+ ### [Cell Type Annotation using CELLiD](https://github.com/JinmiaoChenLab/DISCOtoolkit_py/blob/main/docs/CELLiD_celltype_annotation.ipynb)
137
+
138
+ ### [scEnrichment](https://github.com/JinmiaoChenLab/DISCOtoolkit_py/blob/main/docs/scEnrichment.ipynb)
139
+
140
+ ## Citation
141
+ 1. [Li, Mengwei, et al. "DISCO: a database of Deeply Integrated human Single-Cell Omics data." Nucleic acids research 50.D1 (2022): D596-D602.](https://academic.oup.com/nar/article/50/D1/D596/6430491)
142
+ 2. [Mengwei Li, Kok Siong Ang, Brian Teo, Uddamvathanak Rom, Minh N Nguyen, Sebastian Maurer-Stroh, Jinmiao Chen. "Rediscovering publicly available single-cell data with the DISCO platform." Nucleic Acids Research (2024): gkae1108](https://academic.oup.com/nar/advance-article/doi/10.1093/nar/gkae1108/7899529)
143
+
144
+ ## Follow us on our social media!
145
+ - [HSCRM2](https://twitter.com/HSCRM2)
146
+ - [JinmiaoChenLab Github repo](https://github.com/JinmiaoChenLab)
@@ -0,0 +1,111 @@
1
+ <!--
2
+ * @Descripttion:
3
+ * @version:
4
+ * @Author: Mengwei Li
5
+ * @Date: 2023-04-16 21:20:42
6
+ * @LastEditors: Mengwei Li
7
+ * @LastEditTime: 2023-04-16 21:22:03
8
+ -->
9
+ [![Documentation](https://img.shields.io/badge/docs-disco.bii.a--star.edu.sg-blue)](https://disco.bii.a-star.edu.sg/v1/docs/toolkit/guide/) [![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
+
11
+ # DISCOtoolkit 1.2.1
12
+
13
+ DISCOtoolkit is a Python package for accessing the data and tools of the [DISCO database](https://disco.bii.a-star.edu.sg/) (DISCO v1). Read the documentation, with tutorials and the API reference, at [disco.bii.a-star.edu.sg/v1/docs/toolkit/guide](https://disco.bii.a-star.edu.sg/v1/docs/toolkit/guide/).
14
+
15
+ - Filter and download DISCO data based on sample metadata and cell type information
16
+ - Gene search: a gene's expression across cell types and tissues
17
+ - CELLiD: cell type annotation
18
+ - scEnrichment: gene set enrichment using DISCO DEGs
19
+
20
+ > **DISCO v1 and v2.** The toolkit talks to **DISCO v1** by default. DISCO v2 has its own R package ([DISCOtoolkit](https://github.com/JinmiaoChenLab/DISCOtoolkit)); the Python package can still be pointed at a v2 server, see [Choosing a server](#choosing-a-server).
21
+
22
+ ## Quickstart (Google Colab)
23
+
24
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/JinmiaoChenLab/DISCOtoolkit_py/blob/main/docs/quickstart_disco_v1.ipynb)
25
+
26
+ Installs, checks the server, filters, downloads and plots in about ten cells, with nothing to set up locally.
27
+
28
+ ## Installation
29
+
30
+ Python 3.9 or newer. In your current environment:
31
+
32
+ ```
33
+ pip install discotoolkit
34
+ ```
35
+
36
+ To try the latest development version straight from GitHub:
37
+
38
+ ```
39
+ pip install "git+https://github.com/JinmiaoChenLab/DISCOtoolkit_py.git"
40
+ ```
41
+
42
+ To work on the code, or to test changes before they are released, install from a local clone. `-e` links the install to the folder, so edits take effect without reinstalling:
43
+
44
+ ```
45
+ git clone https://github.com/JinmiaoChenLab/DISCOtoolkit_py.git
46
+ cd DISCOtoolkit_py
47
+ pip install -e .
48
+ ```
49
+
50
+ `pip install discotoolkit` and a local install give the same code when the versions match. The difference is the source: PyPI delivers a released, packaged copy, while a local install uses the files in your folder.
51
+
52
+ Dependencies (installed automatically): numpy, pandas, scanpy, scipy, joblib, pandarallel, requests, colorcet, leidenalg, h5py, matplotlib, seaborn.
53
+
54
+ We recommend a virtual environment, for example with miniconda:
55
+
56
+ ```
57
+ conda create --name disco python=3.10
58
+ conda activate disco
59
+ conda install ipykernel
60
+ python -m ipykernel install --user --name disco --display-name "disco"
61
+ python -m pip install -U discotoolkit
62
+ ```
63
+
64
+ ## Choosing a server
65
+
66
+ ```python
67
+ import discotoolkit as dt
68
+
69
+ dt.get_server() # 'https://disco.bii.a-star.edu.sg/disco_v3_api/' (DISCO v1, the default)
70
+ dt.set_server("v2") # DISCO v2
71
+ dt.set_server("https://my.server/disco_v3_api/") # any server with the same API
72
+ ```
73
+
74
+ or set the `DISCO_API_URL` environment variable before importing the package.
75
+
76
+ ## Testing
77
+
78
+ Two small test files need nothing beyond `requests`, so they run anywhere, including Colab:
79
+
80
+ ```
81
+ python tests/test_settings.py # offline: server selection logic
82
+ python tests/test_version.py # offline: setup.py and __init__.py agree on the version
83
+ python tests/test_docs.py # offline: notebooks are clean, every public function is in the API reference
84
+ python tests/test_server_contract.py # online: does the server answer everything the toolkit needs?
85
+ python tests/test_server_contract.py https://immunesinglecell.org/disco_v3_api/ # check another server
86
+ ```
87
+
88
+ GitHub Actions runs these, and installs the package on Python 3.9-3.12, on every push. Maintainers: see [RELEASING.md](RELEASING.md) for how a release, and its documentation, is published.
89
+
90
+ `test_server_contract.py` checks status codes and the shape of each response (the columns and file types the toolkit reads). It only samples the large reference files, it does not download them.
91
+
92
+ ## Basic Usage
93
+ Example in Jupyter notebook.
94
+
95
+ <em>please select disco as the kernel for running the jupyter notebook</em>
96
+
97
+ ### [Quickstart for DISCO v1](https://github.com/JinmiaoChenLab/DISCOtoolkit_py/blob/main/docs/quickstart_disco_v1.ipynb)
98
+
99
+ ### [Filter and download DISCO data](https://github.com/JinmiaoChenLab/DISCOtoolkit_py/blob/main/docs/download_data.ipynb)
100
+
101
+ ### [Cell Type Annotation using CELLiD](https://github.com/JinmiaoChenLab/DISCOtoolkit_py/blob/main/docs/CELLiD_celltype_annotation.ipynb)
102
+
103
+ ### [scEnrichment](https://github.com/JinmiaoChenLab/DISCOtoolkit_py/blob/main/docs/scEnrichment.ipynb)
104
+
105
+ ## Citation
106
+ 1. [Li, Mengwei, et al. "DISCO: a database of Deeply Integrated human Single-Cell Omics data." Nucleic acids research 50.D1 (2022): D596-D602.](https://academic.oup.com/nar/article/50/D1/D596/6430491)
107
+ 2. [Mengwei Li, Kok Siong Ang, Brian Teo, Uddamvathanak Rom, Minh N Nguyen, Sebastian Maurer-Stroh, Jinmiao Chen. "Rediscovering publicly available single-cell data with the DISCO platform." Nucleic Acids Research (2024): gkae1108](https://academic.oup.com/nar/advance-article/doi/10.1093/nar/gkae1108/7899529)
108
+
109
+ ## Follow us on our social media!
110
+ - [HSCRM2](https://twitter.com/HSCRM2)
111
+ - [JinmiaoChenLab Github repo](https://github.com/JinmiaoChenLab)
@@ -18,7 +18,7 @@ from pandarallel import pandarallel # multiprocessing library
18
18
  pd.options.mode.chained_assignment = None
19
19
 
20
20
  # import variable and class from other script
21
- from .GlobalVariable import logging, prefix_disco_url, timeout
21
+ from .GlobalVariable import logging, api_url, timeout
22
22
  from .DiscoClass import FilterData, Filter
23
23
  from .GetMetadata import check_in_list
24
24
 
@@ -56,11 +56,11 @@ def generate_correlation_map(x, y):
56
56
 
57
57
 
58
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):
59
+ def get_atlas(ref_data=None, ref_path=None) -> list:
60
60
  """get the all the atlas string from the DISCO website and return to the user
61
61
 
62
62
  Returns:
63
- List: return list of string
63
+ list: the atlas names, as a list of strings
64
64
  """
65
65
  # Download reference data and ref_deg if missing
66
66
  if ref_data is None:
@@ -72,23 +72,92 @@ def get_atlas(ref_data=None, ref_path=None):
72
72
  if not os.path.exists(ref_path):
73
73
  os.mkdir(ref_path)
74
74
 
75
- # download reference data from the server in pickle extension and read as pandas dataframe
75
+ # download the reference data from the server (once) and read it as a pandas dataframe
76
76
  if ref_data is None:
77
- if not (os.path.exists(ref_path + "/ref_data.pkl")):
78
- logging.info("Downloading reference dataset...")
79
- response = requests.get(
80
- url=prefix_disco_url + "toolkit/getRef?type=pkl", timeout=timeout
81
- )
82
- open(ref_path + "/ref_data.pkl", "wb").write(response.content)
83
- ref_data = pd.read_pickle(
84
- ref_path + "/ref_data.pkl",
85
- compression={"method": "gzip", "compresslevel": 6},
86
- )
77
+ ref_data = _load_reference(ref_path, "ref_data", "getRef", index_col=0)
87
78
 
88
79
  all_atlas = [each.split("--")[1] for each in ref_data.columns]
89
80
  return list(set(all_atlas))
90
81
 
91
82
 
83
+ def _load_reference(ref_path: str, name: str, endpoint: str, **csv_options) -> pd.DataFrame:
84
+ """Get a CELLiD reference table (`name` is "ref_data" or "ref_deg"), downloading it once.
85
+
86
+ DISCO v1 serves it as plain CSV (`toolkit/<endpoint>?type=csv`, gzip-compressed on the wire),
87
+ read with pandas.read_csv. A copy already in `ref_path` is used as it is (a CSV, or the
88
+ pickle that earlier versions saved). Older servers only offer a pickle; that is the fallback,
89
+ with a warning, because unpickling data from a network is only safe if the server is trusted.
90
+ """
91
+ csv_file = "%s/%s.csv" % (ref_path, name)
92
+ pkl_file = "%s/%s.pkl" % (ref_path, name)
93
+
94
+ if os.path.exists(csv_file):
95
+ return pd.read_csv(csv_file, **csv_options)
96
+ if os.path.exists(pkl_file):
97
+ return pd.read_pickle(pkl_file, compression={"method": "gzip", "compresslevel": 6})
98
+
99
+ logging.info("Downloading reference dataset (%s)...", name)
100
+ with requests.get(
101
+ url=api_url("toolkit/" + endpoint), params={"type": "csv"}, stream=True, timeout=timeout
102
+ ) as response:
103
+ if response.status_code == 200:
104
+ # write to a temporary name so an interrupted download is not mistaken for the file
105
+ with open(csv_file + ".part", "wb") as handle:
106
+ for chunk in response.iter_content(chunk_size=1 << 20):
107
+ handle.write(chunk)
108
+ os.replace(csv_file + ".part", csv_file)
109
+ return pd.read_csv(csv_file, **csv_options)
110
+
111
+ logging.warning(
112
+ "This server has no CSV for %s (HTTP %s); falling back to the pickle download.",
113
+ name,
114
+ response.status_code,
115
+ )
116
+ response = requests.get(
117
+ url=api_url("toolkit/" + endpoint), params={"type": "pkl"}, timeout=timeout
118
+ )
119
+ response.raise_for_status()
120
+ with open(pkl_file, "wb") as handle:
121
+ handle.write(response.content)
122
+ return pd.read_pickle(pkl_file, compression={"method": "gzip", "compresslevel": 6})
123
+
124
+
125
+ def _load_geneset(ref_path: str) -> pd.DataFrame:
126
+ """Get the gene-set reference (columns logfc, gene, atlas, name), downloading it once.
127
+
128
+ DISCO v1 serves it as plain CSV (`toolkit/getGeneSet?format=csv`), which is read with
129
+ pandas.read_csv. Older servers only offer a pickle (`getGeneSetPkl`); that is used as a
130
+ fallback, with a warning, because unpickling data from a network is only safe if the
131
+ server is trusted.
132
+ """
133
+ csv_file = ref_path + "/ref_geneset.csv"
134
+ pkl_file = ref_path + "/ref_geneset.pkl"
135
+
136
+ if os.path.exists(csv_file):
137
+ return pd.read_csv(csv_file)
138
+ if os.path.exists(pkl_file):
139
+ return pd.read_pickle(pkl_file, compression={"method": "gzip", "compresslevel": 6})
140
+
141
+ logging.info("Downloading gene set reference...")
142
+ response = requests.get(
143
+ url=api_url("toolkit/getGeneSet"), params={"format": "csv"}, timeout=timeout
144
+ )
145
+ if response.status_code == 200:
146
+ with open(csv_file, "wb") as handle:
147
+ handle.write(response.content)
148
+ return pd.read_csv(csv_file)
149
+
150
+ logging.warning(
151
+ "This server has no CSV gene set (HTTP %s); falling back to the pickle download.",
152
+ response.status_code,
153
+ )
154
+ response = requests.get(url=api_url("getGeneSetPkl"), timeout=timeout)
155
+ response.raise_for_status()
156
+ with open(pkl_file, "wb") as handle:
157
+ handle.write(response.content)
158
+ return pd.read_pickle(pkl_file, compression={"method": "gzip", "compresslevel": 6})
159
+
160
+
92
161
  def CELLiD_cluster(
93
162
  rna,
94
163
  ref_data: pd.DataFrame = None,
@@ -97,7 +166,7 @@ def CELLiD_cluster(
97
166
  n_predict: int = 1,
98
167
  ref_path: str = None,
99
168
  ncores: int = 10,
100
- ):
169
+ ) -> pd.DataFrame:
101
170
  """Cell type annotation using reference data and compute the correlation between the user cell gene expression as compare
102
171
  to the reference data. The celltype with highest correlation will be concluded as the celltype
103
172
 
@@ -139,31 +208,13 @@ def CELLiD_cluster(
139
208
  if not os.path.exists(ref_path):
140
209
  os.mkdir(ref_path)
141
210
 
142
- # download reference data from the server in pickle extension and read as pandas dataframe
211
+ # download the reference data from the server (once) and read it as a pandas dataframe
143
212
  if ref_data is None:
144
- if not (os.path.exists(ref_path + "/ref_data.pkl")):
145
- logging.info("Downloading reference dataset...")
146
- response = requests.get(
147
- url=prefix_disco_url + "toolkit/getRef?type=pkl", timeout=timeout
148
- )
149
- open(ref_path + "/ref_data.pkl", "wb").write(response.content)
150
- ref_data = pd.read_pickle(
151
- ref_path + "/ref_data.pkl",
152
- compression={"method": "gzip", "compresslevel": 6},
153
- )
213
+ ref_data = _load_reference(ref_path, "ref_data", "getRef", index_col=0)
154
214
 
155
215
  # similarly do the same for the DEG reference
156
216
  if ref_deg is None:
157
- if not (os.path.exists(ref_path + "/ref_deg.pkl")):
158
- logging.info("Downloading deg dataset...")
159
- response = requests.get(
160
- url=prefix_disco_url + "toolkit/getRefDeg?type=pkl", timeout=timeout
161
- )
162
- open(ref_path + "/ref_deg.pkl", "wb").write(response.content)
163
- ref_deg = pd.read_pickle(
164
- ref_path + "/ref_deg.pkl",
165
- compression={"method": "gzip", "compresslevel": 6},
166
- )
217
+ ref_deg = _load_reference(ref_path, "ref_deg", "getRefDeg")
167
218
 
168
219
  ####
169
220
  # write list of atlas function
@@ -254,7 +305,7 @@ def CELLiD_cluster(
254
305
  predict.columns = ["cor"]
255
306
  predict = predict.sort_values(["cor"], ascending=False)
256
307
  res = [
257
- [each.split("--")[0], each.split("--")[1], predict["cor"][index], i]
308
+ [each.split("--")[0], each.split("--")[1], predict["cor"].iloc[index], i]
258
309
  for index, each in enumerate(predict.index)
259
310
  if index < n_predict
260
311
  ]
@@ -305,7 +356,7 @@ def CELLiD_enrichment(
305
356
  reference: pd.DataFrame = None,
306
357
  ref_path: str = None,
307
358
  ncores: int = 1,
308
- ):
359
+ ) -> pd.DataFrame:
309
360
  """Function to generate enrichment analysis based on the reference gene sets and following the DISCO pipeline.
310
361
 
311
362
  Args:
@@ -347,24 +398,7 @@ def CELLiD_enrichment(
347
398
  if not os.path.exists(ref_path):
348
399
  os.mkdir(ref_path)
349
400
 
350
- # check if the file does not exist
351
- if not (os.path.exists(ref_path + "/ref_geneset.pkl")):
352
- # downloading the geneset data from disco database
353
- response = requests.get(
354
- url=prefix_disco_url + "/getGeneSetPkl", timeout=timeout
355
- )
356
- open(ref_path + "/ref_geneset.pkl", "wb").write(response.content)
357
- reference = pd.read_pickle(
358
- ref_path + "/ref_geneset.pkl",
359
- compression={"method": "gzip", "compresslevel": 6},
360
- )
361
-
362
- else:
363
- # read the data into pandas dataframe for subsequent analysis
364
- reference = pd.read_pickle(
365
- ref_path + "/ref_geneset.pkl",
366
- compression={"method": "gzip", "compresslevel": 6},
367
- )
401
+ reference = _load_geneset(ref_path)
368
402
 
369
403
  # rename the name data to include the reference atlas
370
404
  reference["name"] = reference["name"] + " in " + reference["atlas"]
@@ -3,21 +3,25 @@ Class for filtering dataset
3
3
  """
4
4
 
5
5
  class Filter:
6
- """
7
- Filter class object to save the attributes for filtering the dataset from DISCO
8
-
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
- platform String e.g. 10x3';
14
- sample_type String;
15
- cell_type String;
16
- cell_type_confidence String e.g. high;
17
- include_cell_type_children Bool e.g. True;
18
- min_cell_per_sample Int e.g. 300;
19
-
20
- return Class object
6
+ """Which DISCO samples and cells to look for.
7
+
8
+ Every argument is optional; a filter with none of them matches everything. Give a string or a
9
+ list of strings. The list of values each field accepts is `list_metadata_item(field)`.
10
+
11
+ Args:
12
+ sample_id (str or list, optional): sample identifier, e.g. "ERX2757110".
13
+ project_id (str or list, optional): project (a study or dataset), e.g. "GSE147520".
14
+ tissue (str or list, optional): e.g. "lung", "bladder".
15
+ disease (str or list, optional): e.g. "COVID-19".
16
+ platform (str or list, optional): sequencing platform, e.g. "10x3'".
17
+ sample_type (str or list, optional): e.g. "control".
18
+ cell_type (str or list, optional): keep samples that contain these cell types, and download
19
+ only those cells.
20
+ cell_type_confidence (str): how sure DISCO's annotation must be: "high", "medium" or "all".
21
+ Defaults to "medium".
22
+ include_cell_type_children (bool): also match the more specific cell types under
23
+ `cell_type`. Defaults to True.
24
+ min_cell_per_sample (int): drop samples with fewer matching cells than this. Defaults to 100.
21
25
  """
22
26
 
23
27
  def __init__(self, sample_id = None, project_id = None, tissue = None, disease = None, platform = None, sample_type = None,
@@ -43,8 +47,16 @@ class Filter:
43
47
 
44
48
  class FilterData:
45
49
 
46
- """
47
- Wrapper class on top of the Filter object to get dataset's summary such as cell count and sample count and the metadata
50
+ """The result of a filter: the matching samples, with their counts.
51
+
52
+ Returned by `filter_disco_metadata` and passed to `download_disco_data`.
53
+
54
+ Attributes:
55
+ sample_metadata (pandas.DataFrame): one row per matching sample.
56
+ cell_type_metadata (pandas.DataFrame): the cell types found in each sample.
57
+ sample_count (int): number of matching samples.
58
+ cell_count (int): number of matching cells.
59
+ filter (Filter): the filter that produced this result.
48
60
  """
49
61
  def __init__(self, sample_metadata = None, cell_type_metadata = None, sample_count = None, cell_count = None, filter = Filter()):
50
62
  self.sample_metadata = sample_metadata
@@ -17,19 +17,23 @@ import hashlib
17
17
  import scanpy as sc
18
18
 
19
19
  # import variable and class from other script
20
- from .GlobalVariable import logging, prefix_disco_url
20
+ from .GlobalVariable import logging, api_url
21
21
  from .DiscoClass import FilterData, Filter
22
22
  from .GetMetadata import check_in_list
23
23
 
24
24
 
25
- def download_disco_data(metadata, output_dir: str = "DISCOtmp"):
26
- """function to download the data based on the given filter
25
+ def download_disco_data(metadata, output_dir: str = "DISCOtmp") -> None:
26
+ """Download the samples of a filter result, one AnnData `.h5ad` file per sample.
27
+
28
+ Each file holds only the cells that matched the filter, with DISCO's annotation in
29
+ `obs["cell_type"]`.
30
+
27
31
  Args:
28
- metadata (FilterData) : FilterData class to filters data from DISCO database
29
- output_dir (Sting) : directory for storing the downloaded data. Default DISCOtmp
32
+ metadata (FilterData): the result of `filter_disco_metadata`.
33
+ output_dir (str): directory to save the files in; created if missing. Defaults to "DISCOtmp".
30
34
 
31
35
  Returns:
32
- None: This function does not return any object and instead download the data for the user
36
+ None: the files are written to `output_dir`.
33
37
  """
34
38
 
35
39
  # define a list to store the error sample that can not be download
@@ -52,11 +56,11 @@ def download_disco_data(metadata, output_dir: str = "DISCOtmp"):
52
56
  if os.path.exists(output_file):
53
57
  os.remove(output_file)
54
58
 
55
- url = prefix_disco_url + "download/getRawH5/" + p + "/" + s
59
+ url = api_url("download/getRawH5/" + p + "/" + s)
56
60
  rna = sc.read_10x_h5(filename=output_file, backup_url=url)
57
61
 
58
62
  cell = pd.read_csv(
59
- prefix_disco_url + "toolkit/" + "getCellTypeSample?sampleId=" + s,
63
+ api_url("toolkit/getCellTypeSample?sampleId=" + s),
60
64
  sep="\t",
61
65
  header=0,
62
66
  )
@@ -7,8 +7,10 @@ import numpy as np
7
7
  from typing import Union
8
8
  import colorcet as cc
9
9
 
10
+ from .GlobalVariable import api_url
10
11
 
11
- def gene_search(gene : str, atlas : Union[str, list] = None, figsize : tuple = None, dpi : int = 300):
12
+
13
+ def gene_search(gene : str, atlas : Union[str, list] = None, figsize : tuple = None, dpi : int = 300) -> None:
12
14
 
13
15
  """Function to search for the gene expression level the same as the input gene search bar in DISCO website.
14
16
 
@@ -27,8 +29,8 @@ def gene_search(gene : str, atlas : Union[str, list] = None, figsize : tuple = N
27
29
  atlas = [atlas]
28
30
 
29
31
  # url to get the API data
30
- url = "https://www.immunesinglecell.org/api/vishuo/geneExp/getRefExp?gene=%s" % (gene)
31
- response = requests.get(url)
32
+ response = requests.get(api_url("geneExp/getRefExp"), params={"gene": gene})
33
+ response.raise_for_status()
32
34
  data = response.json()
33
35
 
34
36
  # Extract relevant information from JSON data
@@ -56,8 +58,8 @@ def gene_search(gene : str, atlas : Union[str, list] = None, figsize : tuple = N
56
58
  if atlas is not None:
57
59
  sample_df = sample_df[sample_df["atlases"].isin(atlas)].copy()
58
60
 
59
- # Define the colorcet paletteasdasd
60
- custom_palette = cc.glasbey_hv
61
+ # Define the colorcet palette, one colour per atlas shown
62
+ custom_palette = cc.glasbey_hv[: max(sample_df["atlases"].nunique(), 1)]
61
63
 
62
64
  # saturation for the plot color
63
65
  saturation=0.8
@@ -78,7 +80,7 @@ def gene_search(gene : str, atlas : Union[str, list] = None, figsize : tuple = N
78
80
  fig = plt.figure(figsize=figsize)
79
81
 
80
82
  # Create the violin plot with different colors based on the 'Category' variable and adding boxplot to assist user with median value
81
- ax = sns.violinplot(data=sample_df, x='cell types', y='value', hue="atlases", width=0.8, dodge=False, cut=1, saturation = saturation, plot_kws={'alpha':0.1},
83
+ ax = sns.violinplot(data=sample_df, x='cell types', y='value', hue="atlases", width=0.8, dodge=False, cut=1, saturation = saturation,
82
84
  inner=None, linewidth=0.0, palette=custom_palette)
83
85
 
84
86
  ax_2 = sns.boxplot(x='cell types', y='value', hue="atlases", data=sample_df, palette=custom_palette, dodge=False, width=0.5, saturation = saturation,
@@ -111,7 +113,7 @@ def gene_search(gene : str, atlas : Union[str, list] = None, figsize : tuple = N
111
113
  # Set labels and title
112
114
  plt.xlabel('Cell Types')
113
115
  plt.ylabel('Expression Value')
114
- plt.title(gene, fontweight='bold')
116
+ plt.title(gene, fontweight='bold', loc='left') # left: the legend sits above the centre
115
117
 
116
118
  # Show the plot
117
119
  plt.show()