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.
- discotoolkit-1.2.1/MANIFEST.in +2 -0
- discotoolkit-1.2.1/PKG-INFO +146 -0
- discotoolkit-1.2.1/README.md +111 -0
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/CELLiD.py +90 -56
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/DiscoClass.py +29 -17
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/DownloadDiscoData.py +12 -8
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/GeneSearch.py +9 -7
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/GetMetadata.py +18 -20
- discotoolkit-1.2.1/discotoolkit/GlobalVariable.py +81 -0
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/__init__.py +2 -1
- discotoolkit-1.2.1/discotoolkit.egg-info/PKG-INFO +146 -0
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit.egg-info/SOURCES.txt +9 -1
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit.egg-info/requires.txt +4 -0
- discotoolkit-1.2.1/pyproject.toml +3 -0
- discotoolkit-1.2.1/requirements.txt +12 -0
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/setup.py +12 -6
- discotoolkit-1.2.1/tests/test_docs.py +90 -0
- discotoolkit-1.2.1/tests/test_gene_search.py +61 -0
- discotoolkit-1.2.1/tests/test_reference_loading.py +98 -0
- discotoolkit-1.2.1/tests/test_server_contract.py +173 -0
- discotoolkit-1.2.1/tests/test_settings.py +90 -0
- discotoolkit-1.2.1/tests/test_version.py +41 -0
- discotoolkit-1.1.4/MANIFEST.in +0 -1
- discotoolkit-1.1.4/PKG-INFO +0 -13
- discotoolkit-1.1.4/README.md +0 -72
- discotoolkit-1.1.4/discotoolkit/GlobalVariable.py +0 -33
- discotoolkit-1.1.4/discotoolkit.egg-info/PKG-INFO +0 -13
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/CellMapper.py +0 -0
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit/Utilities.py +0 -0
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit.egg-info/dependency_links.txt +0 -0
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/discotoolkit.egg-info/top_level.txt +0 -0
- {discotoolkit-1.1.4 → discotoolkit-1.2.1}/setup.cfg +0 -0
|
@@ -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
|
+
[](https://disco.bii.a-star.edu.sg/v1/docs/toolkit/guide/) [](https://pepy.tech/project/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
|
+
[](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
|
+
[](https://disco.bii.a-star.edu.sg/v1/docs/toolkit/guide/) [](https://pepy.tech/project/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
|
+
[](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,
|
|
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
|
-
|
|
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
|
|
75
|
+
# download the reference data from the server (once) and read it as a pandas dataframe
|
|
76
76
|
if ref_data is None:
|
|
77
|
-
|
|
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
|
|
211
|
+
# download the reference data from the server (once) and read it as a pandas dataframe
|
|
143
212
|
if ref_data is None:
|
|
144
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
"""
|
|
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)
|
|
29
|
-
output_dir (
|
|
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:
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
31
|
-
response
|
|
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
|
|
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,
|
|
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()
|