From cfd4b2f60e019d9b68048a3188d61328ab4979e5 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 02:38:42 +0100
Subject: [PATCH 01/36] Update _utilities.py
fix for #145 ?
---
dandelion/utilities/_utilities.py | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/dandelion/utilities/_utilities.py b/dandelion/utilities/_utilities.py
index b62cce86e..744036537 100644
--- a/dandelion/utilities/_utilities.py
+++ b/dandelion/utilities/_utilities.py
@@ -2,14 +2,20 @@
# @Author: kt16
# @Date: 2020-05-12 14:01:32
# @Last Modified by: Kelvin
-# @Last Modified time: 2022-03-11 20:32:54
+# @Last Modified time: 2022-05-18 02:37:52
import os
import re
import pandas as pd
import numpy as np
-from collections import defaultdict, Iterable
+from collections import defaultdict
+## for compatibility with python>=3.10
+try:
+ from collections.abc import Iterable
+except ImportError:
+ from collections import Iterable
+
from airr import RearrangementSchema
from subprocess import run
From dc656963bc170e7f9c91221f9dcf078515650e26 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 02:38:56 +0100
Subject: [PATCH 02/36] Update tests.yml
add python 3.10 to tests
---
.github/workflows/tests.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 407b739d0..733ba2599 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -25,9 +25,11 @@ jobs:
- { python-version: 3.7, os: ubuntu-latest }
- { python-version: 3.8, os: ubuntu-latest }
- { python-version: 3.9, os: ubuntu-latest }
+ - { python-version: 3.10, os: ubuntu-latest }
- { python-version: 3.7, os: macos-latest }
- { python-version: 3.8, os: macos-latest }
- { python-version: 3.9, os: macos-latest } # segmentation fault due to missing py3.9 macOSX wheel https://github.com/rpy2/rpy2/issues/846
+ - { python-version: 3.10, os: macos-latest }
# disabled until it's fixed.
runs-on: ${{ matrix.config.os }}
env:
From cd7839fb301843a933983a7c4bc686f2303c79b6 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 02:41:54 +0100
Subject: [PATCH 03/36] Update tests.yml
---
.github/workflows/tests.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 733ba2599..f05e540b1 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -25,11 +25,11 @@ jobs:
- { python-version: 3.7, os: ubuntu-latest }
- { python-version: 3.8, os: ubuntu-latest }
- { python-version: 3.9, os: ubuntu-latest }
- - { python-version: 3.10, os: ubuntu-latest }
+ - { python-version: "3.10", os: ubuntu-latest }
- { python-version: 3.7, os: macos-latest }
- { python-version: 3.8, os: macos-latest }
- { python-version: 3.9, os: macos-latest } # segmentation fault due to missing py3.9 macOSX wheel https://github.com/rpy2/rpy2/issues/846
- - { python-version: 3.10, os: macos-latest }
+ - { python-version: "3.10", os: macos-latest }
# disabled until it's fixed.
runs-on: ${{ matrix.config.os }}
env:
From e724d57b20906f25349ce7d97fdb87d44b909465 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 02:48:10 +0100
Subject: [PATCH 04/36] Update tests.yml
---
.github/workflows/tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index f05e540b1..fe8963fcd 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -66,7 +66,7 @@ jobs:
hashFiles('environment.yml') }}
- name: Setup Miniconda
- uses: conda-incubator/setup-miniconda@v2
+ uses: conda-incubator/setup-miniconda@v2.1.1
with:
auto-activate-base: true
auto-update-conda : true
From 4c4042eeb22be6561d889c63d7b2b3a6568daef6 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 03:02:14 +0100
Subject: [PATCH 05/36] Update requirements.txt
---
requirements.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/requirements.txt b/requirements.txt
index acb6265c7..f95b10ff1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,7 +6,8 @@ changeo>=1.0.0
anndata>=0.7.1
scanpy>=1.4.6
scikit-learn>=0.23.0
-scikit-bio==0.5.6
+scikit-bio==0.5.6; python_version < '3.10'
+scikit-bio>=0.5.7; python_version >= '3.10'
scipy>=1.4.1
numba>=0.48.0
seaborn>=0.10.1
From e0beeb9821ee56a300864b169ae39ae30ae242c3 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 05:01:19 +0100
Subject: [PATCH 06/36] Update tests.yml
hmm
---
.github/workflows/tests.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index fe8963fcd..05d2fef2f 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -154,6 +154,7 @@ jobs:
install.packages(c('RCurl','XML'))
remotes::install_cran("BiocManager")
BiocManager::install(version = ${{ steps.R.outputs.biocversion}}, ask = FALSE)
+ BiocManager::install(c('GenomeInfoDb', 'Rhtslib', 'Rsamtools'))
BiocManager::install(c('Biostrings', 'GenomicAlignments', 'IRanges'))
install.packages('matrixStats')
install.packages(c('shazam', 'alakazam', 'tigger', 'airr', 'optparse'))
From a52342b56e086ad9207f20d641c7cbb121d99c75 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 05:28:19 +0100
Subject: [PATCH 07/36] Update tests.yml
---
.github/workflows/tests.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 05d2fef2f..296ba963f 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -143,6 +143,7 @@ jobs:
install.packages(c('RCurl','XML'))
remotes::install_cran("BiocManager")
BiocManager::install(version = ${{ steps.R.outputs.biocversion}}, ask = FALSE)
+ BiocManager::install(c('GenomeInfoDb', 'Rsamtools'))
BiocManager::install(c('Biostrings', 'GenomicAlignments', 'IRanges'))
install.packages(c('shazam', 'alakazam', 'tigger', 'airr', 'optparse'))
shell: Rscript {0}
@@ -154,7 +155,7 @@ jobs:
install.packages(c('RCurl','XML'))
remotes::install_cran("BiocManager")
BiocManager::install(version = ${{ steps.R.outputs.biocversion}}, ask = FALSE)
- BiocManager::install(c('GenomeInfoDb', 'Rhtslib', 'Rsamtools'))
+ BiocManager::install(c('GenomeInfoDb', 'Rsamtools'))
BiocManager::install(c('Biostrings', 'GenomicAlignments', 'IRanges'))
install.packages('matrixStats')
install.packages(c('shazam', 'alakazam', 'tigger', 'airr', 'optparse'))
From 30fe017e096b4b7b6cde7d0908f340a9eb3812af Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 06:05:11 +0100
Subject: [PATCH 08/36] Update tests.yml
---
.github/workflows/tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 296ba963f..1e5ff2b08 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -47,7 +47,7 @@ jobs:
if: matrix.config.os == 'ubuntu-latest'
run: |
sudo apt-get install libcurl4-openssl-dev
- sudo apt-get update -y && sudo apt-get install -y zlib1g-dev libglpk-dev libgmp3-dev libxml2-dev libicu-dev libhdf5-serial-dev
+ sudo apt-get update -y && sudo apt-get install -y zlib1g-dev libglpk-dev libgmp3-dev libxml2-dev libicu-dev libhdf5-serial-dev libcurl4-gnutls-dev
- name: Install macOS system dependencies
if: matrix.config.os == 'macos-latest'
From 2ff687959b2bdc6faf52447d23c7c9d66c3dd406 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 06:08:20 +0100
Subject: [PATCH 09/36] Update _diversity.py
to prevent potential future issues for scirpy's test workflow #141 #145
---
dandelion/tools/_diversity.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/dandelion/tools/_diversity.py b/dandelion/tools/_diversity.py
index a89932e3f..a18fe464d 100644
--- a/dandelion/tools/_diversity.py
+++ b/dandelion/tools/_diversity.py
@@ -2,7 +2,7 @@
# @Author: Kelvin
# @Date: 2020-08-13 21:08:53
# @Last Modified by: Kelvin
-# @Last Modified time: 2021-08-06 00:04:38
+# @Last Modified time: 2022-05-18 06:07:42
import pandas as pd
import numpy as np
@@ -418,6 +418,7 @@ def diversity_gini(self: Union[Dandelion, AnnData],
`pandas` dataframe or `Dandelion` object with updated `.metadata` slot.
"""
start = logg.info('Calculating Gini indices')
+ from skbio.diversity.alpha import gini_index
def gini_indices(self: Dandelion,
groupby: str,
@@ -839,6 +840,7 @@ def diversity_chao1(
`pandas` dataframe, `Dandelion` object with updated `.metadata` slot or `AnnData` object with updated `.obs` slot.
"""
start = logg.info('Calculating Chao1 estimates')
+ from skbio.diversity.alpha import chao1
def chao1_estimates(self: Union[Dandelion, AnnData],
groupby: str,
@@ -1038,6 +1040,7 @@ def diversity_shannon(
`pandas` dataframe, `Dandelion` object with updated `.metadata` slot or `AnnData` object with updated `.obs` slot.
"""
start = logg.info('Calculating Shannon entropy')
+ from skbio.diversity.alpha import shannon
def shannon_entropy(self: Union[Dandelion, AnnData],
groupby: str,
From e30321440fec07633ce788e930132ddb905f3be6 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 06:37:54 +0100
Subject: [PATCH 10/36] Update _diversity.py
---
dandelion/tools/_diversity.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dandelion/tools/_diversity.py b/dandelion/tools/_diversity.py
index a18fe464d..be0b646c5 100644
--- a/dandelion/tools/_diversity.py
+++ b/dandelion/tools/_diversity.py
@@ -2,7 +2,7 @@
# @Author: Kelvin
# @Date: 2020-08-13 21:08:53
# @Last Modified by: Kelvin
-# @Last Modified time: 2022-05-18 06:07:42
+# @Last Modified time: 2022-05-18 06:37:42
import pandas as pd
import numpy as np
@@ -13,7 +13,7 @@
from ..tools._network import clone_centrality, clone_degree, generate_network
from scipy.special import gammaln
from anndata import AnnData
-from skbio.diversity.alpha import chao1, gini_index, shannon
+# from skbio.diversity.alpha import chao1, gini_index, shannon
from tqdm import tqdm
from time import sleep
from scanpy import logging as logg
From 3cccc345e61abe6771723d7aae6fd6db0b131c88 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 13:08:41 +0100
Subject: [PATCH 11/36] Update _network.py
---
dandelion/tools/_network.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dandelion/tools/_network.py b/dandelion/tools/_network.py
index bdca82d55..e455fb98c 100644
--- a/dandelion/tools/_network.py
+++ b/dandelion/tools/_network.py
@@ -2,7 +2,7 @@
# @Author: Kelvin
# @Date: 2020-08-12 18:08:04
# @Last Modified by: Kelvin
-# @Last Modified time: 2021-08-12 09:55:11
+# @Last Modified time: 2022-05-18 06:55:37
import pandas as pd
import numpy as np
@@ -11,7 +11,10 @@
from ..utilities._utilities import *
from ..utilities._core import *
from ..utilities._io import *
-from networkx.utils import random_state
+try:
+ from networkx.utils import np_random_state as random_state
+except:
+ from networkx.utils import random_state
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import minimum_spanning_tree
from scipy.spatial.distance import pdist, squareform
From ba7692e23795e3ac0179d11d2cabd20a9e86932f Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 13:11:21 +0100
Subject: [PATCH 12/36] Update _tools.py
---
dandelion/tools/_tools.py | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/dandelion/tools/_tools.py b/dandelion/tools/_tools.py
index fd7da9ce0..4d853daa6 100644
--- a/dandelion/tools/_tools.py
+++ b/dandelion/tools/_tools.py
@@ -2,7 +2,7 @@
# @Author: Kelvin
# @Date: 2020-05-13 23:22:18
# @Last Modified by: Kelvin
-# @Last Modified time: 2022-03-11 18:11:55
+# @Last Modified time: 2022-05-18 09:37:54
import os
import sys
@@ -1282,6 +1282,7 @@ def clone_overlap(
groupby: str,
colorby: str,
min_clone_size: Optional[int] = None,
+ weighted_overlap: bool = False,
clone_key: Optional[str] = None) -> Union[AnnData, pd.DataFrame]:
"""
A function to tabulate clonal overlap for input as a circos-style plot.
@@ -1296,6 +1297,9 @@ def clone_overlap(
column name in obs/metadata for grouping and color of nodes in circos plot.
min_clone_size : int, Optional
minimum size of clone for plotting connections. Defaults to 2 if left as None.
+ weighted_overlap : bool
+ if True, instead of collapsing to overlap to binary, overlap will be returned as the number of cells.
+ In the future, there will be the option to use something like a jaccard index.
clone_key : str, Optional
column name for clones. None defaults to 'clone_id'.
@@ -1338,11 +1342,12 @@ def clone_overlap(
if min_size == 0:
raise ValueError('min_size must be greater than 0.')
- elif min_size > 2:
- overlap[overlap < min_size] = 0
- overlap[overlap >= min_size] = 1
- elif min_size == 2:
- overlap[overlap >= min_size] = 1
+ if not weighted_overlap:
+ if min_size > 2:
+ overlap[overlap < min_size] = 0
+ overlap[overlap >= min_size] = 1
+ elif min_size == 2:
+ overlap[overlap >= min_size] = 1
overlap.index.name = None
overlap.columns.name = None
From 392b72636223150c348bd51a2ff9ae4a2f4ee57f Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 13:11:24 +0100
Subject: [PATCH 13/36] Update _plotting.py
---
dandelion/plotting/_plotting.py | 160 +++++++++++++++++++++++---------
1 file changed, 115 insertions(+), 45 deletions(-)
diff --git a/dandelion/plotting/_plotting.py b/dandelion/plotting/_plotting.py
index 4204902a1..b956423d1 100644
--- a/dandelion/plotting/_plotting.py
+++ b/dandelion/plotting/_plotting.py
@@ -2,7 +2,7 @@
# @Author: Kelvin
# @Date: 2020-05-18 00:15:00
# @Last Modified by: Kelvin
-# @Last Modified time: 2021-07-31 19:08:07
+# @Last Modified time: 2022-05-18 13:10:30
import seaborn as sns
import pandas as pd
@@ -365,7 +365,7 @@ def stackedbarplot(self: Union[AnnData, Dandelion],
dat_ = pd.DataFrame(data_.groupby(color)[groupby].value_counts(
normalize=normalize).unstack(fill_value=0).stack(),
- columns=['value'])
+ columns=['value'])
dat_.reset_index(drop=False, inplace=True)
dat_order = pd.DataFrame(data[color].value_counts(normalize=normalize))
dat_ = dat_.pivot(index=color, columns=groupby, values='value')
@@ -551,7 +551,7 @@ def spectratype(self: Union[AnnData, Dandelion],
data[groupby] = [str(l) for l in data[groupby]]
dat_ = pd.DataFrame(data.groupby(color)[groupby].value_counts(
normalize=False).unstack(fill_value=0).stack(),
- columns=['value'])
+ columns=['value'])
dat_.reset_index(drop=False, inplace=True)
dat_[color] = pd.to_numeric(dat_[color], errors='coerce')
dat_.sort_values(by=color)
@@ -654,6 +654,7 @@ def clone_overlap(self: Union[AnnData, Dandelion],
groupby: str,
colorby: str,
min_clone_size: Optional[int] = None,
+ weighted_overlap: bool = False,
clone_key: Optional[str] = None,
color_mapping: Optional[Union[Sequence, Dict]] = None,
node_labels: bool = True,
@@ -666,10 +667,14 @@ def clone_overlap(self: Union[AnnData, Dandelion],
float]] = (8, 8),
return_graph: bool = False,
save: Optional[str] = None,
+ show_plot: bool = True,
**kwargs):
"""
A plot function to visualise clonal overlap as a circos-style plot. Requires nxviz.
+ Written with nxviz < 0.7.3. Will need to revisit for newer nxviz versions, or change how it's called?
+ TODO: workout how to modify edge thickness with both old and new versions.
+
Parameters
----------
self : Dandelion, AnnData
@@ -680,10 +685,15 @@ def clone_overlap(self: Union[AnnData, Dandelion],
column name in obs/metadata for grouping and color of nodes in circos plot.
min_clone_size : int, Optional
minimum size of clone for plotting connections. Defaults to 2 if left as None.
+ weighted_overlapt : bool
+ if True, instead of collapsing to overlap to binary, edge thickness will reflect the number of
+ cells found in the overlap. In the future, there will be the option to use something like a jaccard
+ index instead.
clone_key : str, Optional
column name for clones. None defaults to 'clone_id'.
color_maopping : Dict, Sequence, Optional
- custom color mapping provided as a sequence (correpsonding to order of categories or alpha-numeric order if dtype is not category), or dictionary containing custom {category:color} mapping.
+ custom color mapping provided as a sequence (correpsonding to order of categories or
+ alpha-numeric order ifdtype is not category), or dictionary containing custom {category:color} mapping.
node_labels : bool, Optional
whether to use node objects as labels or not
node_label_layout : bool, Optional
@@ -696,6 +706,10 @@ def clone_overlap(self: Union[AnnData, Dandelion],
figure size. Default is (8, 8).
return_graph : bool
whether or not to return the graph for fine tuning. Default is False.
+ save : str
+ file path for saving plot
+ show_plot : bool
+ whether or not to show the plot.
**kwargs
passed to `matplotlib.pyplot.savefig`.
@@ -740,15 +754,16 @@ def clone_overlap(self: Union[AnnData, Dandelion],
dictg_ = dict(data[groupby])
datc_[groupby] = [dictg_[l] for l in datc_['cell_id']]
- overlap = pd.crosstab(data[clone_], data[groupby])
+ overlap = pd.crosstab(datc_[clone_], datc_[groupby])
if min_size == 0:
raise ValueError('min_size must be greater than 0.')
- elif min_size > 2:
- overlap[overlap < min_size] = 0
- overlap[overlap >= min_size] = 1
- elif min_size == 2:
- overlap[overlap >= min_size] = 1
+ if not weighted_overlap:
+ if min_size > 2:
+ overlap[overlap < min_size] = 0
+ overlap[overlap >= min_size] = 1
+ elif min_size == 2:
+ overlap[overlap >= min_size] = 1
overlap.index.name = None
overlap.columns.name = None
@@ -767,30 +782,58 @@ def clone_overlap(self: Union[AnnData, Dandelion],
dictg_ = dict(data[groupby])
datc_[groupby] = [dictg_[l] for l in datc_['cell_id']]
- overlap = pd.crosstab(data[clone_], data[groupby])
-
+ overlap = pd.crosstab(datc_[clone_], datc_[groupby])
if min_size == 0:
raise ValueError('min_size must be greater than 0.')
- elif min_size > 2:
- overlap[overlap < min_size] = 0
- overlap[overlap >= min_size] = 1
- elif min_size == 2:
- overlap[overlap >= min_size] = 1
+ if not weighted_overlap:
+ if min_size > 2:
+ overlap[overlap < min_size] = 0
+ overlap[overlap >= min_size] = 1
+ elif min_size == 2:
+ overlap[overlap >= min_size] = 1
overlap.index.name = None
overlap.columns.name = None
edges = {}
- for x in overlap.index:
- if overlap.loc[x].sum() > 1:
- edges[x] = [
- y + ({
- str(clone_): x
- }, ) for y in list(
- combinations(
- [i for i in overlap.loc[x][overlap.loc[x] == 1].index],
- 2))
- ]
+ if not weighted_overlap:
+ for x in overlap.index:
+ if overlap.loc[x].sum() > 1:
+ edges[x] = [
+ y + ({
+ str(clone_): x
+ }, ) for y in list(
+ combinations([
+ i for i in overlap.loc[x][overlap.loc[x] > 0].index
+ ], 2))
+ ]
+ else:
+ tmp_overlap = overlap.astype(bool).sum(axis=1)
+ combis = {
+ x: list(
+ combinations(
+ [i for i in overlap.loc[x][overlap.loc[x] > 0].index], 2))
+ for x in tmp_overlap.index if tmp_overlap.loc[x] > 1
+ }
+
+ tmp_edge_weight_dict = defaultdict(list)
+ for k_clone, val_pair in combis.items():
+ for pair in val_pair:
+ tmp_edge_weight_dict[pair].append(
+ overlap.loc[k_clone, list(pair)].sum())
+ for combix in tmp_edge_weight_dict:
+ tmp_edge_weight_dict[combix] = sum(tmp_edge_weight_dict[combix])
+ for x in overlap.index:
+ if overlap.loc[x].sum() > 1:
+ edges[x] = [
+ y + ({
+ str(clone_): x,
+ 'weight': tmp_edge_weight_dict[y],
+ }, ) for y in list(
+ combinations([
+ i for i in overlap.loc[x][overlap.loc[x] > 0].index
+ ], 2))
+ ]
# create graph
G = nx.Graph()
@@ -802,6 +845,12 @@ def clone_overlap(self: Union[AnnData, Dandelion],
# unpack the edgelist and add to the graph
for edge in edges:
G.add_edges_from(edges[edge])
+
+ if not weighted_overlap:
+ weighted_attr = None
+ else:
+ weighted_attr = 'weight'
+
groupby_dict = dict(zip(data[groupby], data[colorby]))
if color_mapping is None:
if self.__class__ == AnnData:
@@ -832,21 +881,42 @@ def clone_overlap(self: Union[AnnData, Dandelion],
df = df.sort_values(colorby).drop_duplicates(
subset=groupby, keep="first").reset_index(drop=True)
- c = nxv.CircosPlot(G,
- node_color=colorby,
- node_grouping=colorby,
- node_labels=node_labels,
- node_label_layout=node_label_layout,
- group_label_position=group_label_position,
- group_label_offset=group_label_offset,
- figsize=figsize)
- c.nodes = list(df[groupby])
- if 'colorby_dict' in locals():
- c.node_colors = [colorby_dict[groupby_dict[c]] for c in c.nodes]
- c.compute_group_label_positions()
- c.compute_group_colors()
- c.draw()
- if save is not None:
- plt.savefig(save, bbox_inches='tight', **kwargs)
- if return_graph:
- return (c)
+ from importlib.metadata import version
+ if version('nxviz') < '0.7.3':
+ c = nxv.CircosPlot(G,
+ node_color=colorby,
+ node_grouping=colorby,
+ node_labels=node_labels,
+ node_label_layout=node_label_layout,
+ group_label_position=group_label_position,
+ group_label_offset=group_label_offset,
+ edge_width=weighted_attr,
+ figsize=figsize)
+ c.nodes = list(df[groupby])
+ if 'colorby_dict' in locals():
+ c.node_colors = [colorby_dict[groupby_dict[c]] for c in c.nodes]
+ c.compute_group_label_positions()
+ c.compute_group_colors()
+ if show_plot:
+ c.draw()
+ if save is not None:
+ plt.savefig(save, bbox_inches='tight', **kwargs)
+ if return_graph:
+ return (c)
+ else:
+ # some limited support for future nxviz plotting api
+ from nxviz import annotate
+ c = nxv.circos(
+ G,
+ group_by=colorby,
+ node_color_by=colorby,
+ edge_lw_by=weighted_attr,
+ ) # group_by
+ annotate.circos_group(G, group_by=colorby)
+ annotate.node_colormapping(G, color_by=colorby)
+ if show_plot:
+ plt.show()
+ if save is not None:
+ plt.savefig(save, bbox_inches='tight', **kwargs)
+ if return_graph:
+ return (c.fig, c.ax)
From f685cb26c6bac73fe2861609aa9dc1bef754a6b0 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 13:11:27 +0100
Subject: [PATCH 14/36] Create test_mouse_plotting.py
---
tests/test_mouse_plotting.py | 46 ++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 tests/test_mouse_plotting.py
diff --git a/tests/test_mouse_plotting.py b/tests/test_mouse_plotting.py
new file mode 100644
index 000000000..4d3851dfb
--- /dev/null
+++ b/tests/test_mouse_plotting.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+import pandas as pd
+import dandelion as ddl
+from pathlib import Path
+
+from fixtures_mouse import (annotation_10x_mouse, database_paths_mouse,
+ dummy_adata_mouse)
+from fixtures import create_testfolder
+
+
+def test_setup(create_testfolder, annotation_10x_mouse, dummy_adata_mouse):
+ annot_file = str(
+ create_testfolder) + "/test_filtered_contig_annotations.csv"
+ annotation_10x_mouse.to_csv(annot_file, index=False)
+ vdj = ddl.read_10x_vdj(str(create_testfolder))
+ ddl.pp.filter_contigs(vdj)
+ ddl.tl.find_clones(vdj)
+ assert vdj.data.shape[0] == 1987
+ assert vdj.metadata.shape[0] == 547
+ ddl.tl.transfer(dummy_adata_mouse, vdj)
+ assert dummy_adata_mouse.n_obs == 547
+ # create a sample column
+ label = []
+ for x in range(0, dummy_adata_mouse.n_obs):
+ if x < 100:
+ label.append('A')
+ elif x < 200:
+ label.append('B')
+ elif x < 300:
+ label.append('C')
+ elif x < 400:
+ label.append('D')
+ elif x < 500:
+ label.append('E')
+ else:
+ label.append('F')
+ dummy_adata_mouse.obs['sample_idx'] = label
+ dummy_adata_mouse.write(str(create_testfolder) + "/test_adata.h5ad")
+ ddl.tl.clone_overlap(dummy_adata_mouse,
+ groupby='sample_idx',
+ colorby='sample_idx')
+ assert 'clone_overlap' in dummy_adata_mouse.uns
+ ddl.pl.clone_overlap(dummy_adata_mouse,
+ groupby='sample_idx',
+ colorby='sample_idx',
+ show_plot = False)
From 328f02feb83b5c7717bffd1c030d9bca23e8d1ec Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 14:10:02 +0100
Subject: [PATCH 15/36] Update _plotting.py
---
dandelion/plotting/_plotting.py | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/dandelion/plotting/_plotting.py b/dandelion/plotting/_plotting.py
index b956423d1..dcca98eb3 100644
--- a/dandelion/plotting/_plotting.py
+++ b/dandelion/plotting/_plotting.py
@@ -2,7 +2,7 @@
# @Author: Kelvin
# @Date: 2020-05-18 00:15:00
# @Last Modified by: Kelvin
-# @Last Modified time: 2022-05-18 13:10:30
+# @Last Modified time: 2022-05-18 14:09:49
import seaborn as sns
import pandas as pd
@@ -881,8 +881,13 @@ def clone_overlap(self: Union[AnnData, Dandelion],
df = df.sort_values(colorby).drop_duplicates(
subset=groupby, keep="first").reset_index(drop=True)
- from importlib.metadata import version
- if version('nxviz') < '0.7.3':
+ try:
+ from importlib.metadata import version
+ NXVIZVERSION = version("nxviz")
+ except:
+ from pkg_resources import get_distribution
+ NXVIZVERSION = get_distribution("nxviz").version
+ if NXVIZVERSION < '0.7.3':
c = nxv.CircosPlot(G,
node_color=colorby,
node_grouping=colorby,
From d1010b29f2f5cb59dc4cf0375d9a78e334056618 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 15:09:16 +0100
Subject: [PATCH 16/36] let's try this
---
environment.yml | 4 ++--
requirements.txt | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/environment.yml b/environment.yml
index be6461e89..a49da4146 100644
--- a/environment.yml
+++ b/environment.yml
@@ -5,7 +5,6 @@ channels:
- anaconda
- defaults
dependencies:
-- numpy
- pandas
- pandoc
- pyyaml
@@ -24,6 +23,7 @@ dependencies:
- rpy2==3.4.2
- pytest-cov
- -r requirements.txt
- - git+https://www.github.com/zktuong/nxviz.git
+ - git+https://www.github.com/zktuong/nxviz.git; python_version < '3.10'
+ - nxviz==0.7.4; python_version >= '3.10'
- scirpy
- scrublet
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index f95b10ff1..c61220827 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,6 @@
pip
setuptools_scm[toml]>=6.0
+numpy>=1.22.3; python_version >= '3.10'
numpy>=1.18.4
pandas>=1.0.3
changeo>=1.0.0
From 277a4109b761218efee928d63c0ba503cec73168 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 15:23:24 +0100
Subject: [PATCH 17/36] Update environment.yml
---
environment.yml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/environment.yml b/environment.yml
index a49da4146..5bf7ec3ac 100644
--- a/environment.yml
+++ b/environment.yml
@@ -23,7 +23,6 @@ dependencies:
- rpy2==3.4.2
- pytest-cov
- -r requirements.txt
- - git+https://www.github.com/zktuong/nxviz.git; python_version < '3.10'
- - nxviz==0.7.4; python_version >= '3.10'
+ - nxviz>=0.7.3
- scirpy
- scrublet
\ No newline at end of file
From 94d5d0ef53ab90a2587dd84ff81038f751f22979 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 15:23:28 +0100
Subject: [PATCH 18/36] Create environment_pre3.10.yml
---
environment_pre3.10.yml | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 environment_pre3.10.yml
diff --git a/environment_pre3.10.yml b/environment_pre3.10.yml
new file mode 100644
index 000000000..5079ab33d
--- /dev/null
+++ b/environment_pre3.10.yml
@@ -0,0 +1,28 @@
+name: dandelion
+channels:
+- conda-forge
+- bioconda
+- anaconda
+- defaults
+dependencies:
+- pandas
+- pandoc
+- pyyaml
+- changeo
+- seaborn
+- statsmodels
+- numba
+- pytables
+- pytest
+- pip
+- tbb
+- pip:
+ - nbsphinx
+ - sphinx-autodoc-typehints
+ - annoy==1.16.3
+ - rpy2==3.4.2
+ - pytest-cov
+ - -r requirements.txt
+ - git+https://www.github.com/zktuong/nxviz.git
+ - scirpy
+ - scrublet
\ No newline at end of file
From df97c850f93c69c0d6ae922c16f512d0ef8d0bd3 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 15:23:32 +0100
Subject: [PATCH 19/36] Update tests.yml
---
.github/workflows/tests.yml | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 1e5ff2b08..ab8fb84e9 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -22,14 +22,14 @@ jobs:
max-parallel: 6
matrix:
config:
- - { python-version: 3.7, os: ubuntu-latest }
- - { python-version: 3.8, os: ubuntu-latest }
- - { python-version: 3.9, os: ubuntu-latest }
- - { python-version: "3.10", os: ubuntu-latest }
- - { python-version: 3.7, os: macos-latest }
- - { python-version: 3.8, os: macos-latest }
- - { python-version: 3.9, os: macos-latest } # segmentation fault due to missing py3.9 macOSX wheel https://github.com/rpy2/rpy2/issues/846
- - { python-version: "3.10", os: macos-latest }
+ - { python-version: 3.7, os: ubuntu-latest, yml-file: environment_pre3.10.yml}
+ - { python-version: 3.8, os: ubuntu-latest, yml-file: environment_pre3.10.yml}
+ - { python-version: 3.9, os: ubuntu-latest, yml-file: environment_pre3.10.yml}
+ - { python-version: "3.10", os: ubuntu-latest, yml-file: environment.yml}
+ - { python-version: 3.7, os: macos-latest, yml-file: environment_pre3.10.yml}
+ - { python-version: 3.8, os: macos-latest, yml-file: environment_pre3.10.yml}
+ - { python-version: 3.9, os: macos-latest, yml-file: environment_pre3.10.yml}
+ - { python-version: "3.10", os: macos-latest, yml-file: environment.yml}
# disabled until it's fixed.
runs-on: ${{ matrix.config.os }}
env:
@@ -74,7 +74,7 @@ jobs:
channels: conda-forge, bioconda, anaconda, defaults
channel-priority: true
python-version: ${{ matrix.config.python-version }}
- environment-file: environment.yml
+ environment-file: ${{ matrix.config.yml-file }}
use-only-tar-bz2: true # IMPORTANT: This needs to be set for caching to work properly!
- name: Display Python version
From e5c63391f2765362c7bf1bc4d2abfff5c570b45c Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 15:34:54 +0100
Subject: [PATCH 20/36] swap back
---
environment.yml | 1 +
environment_pre3.10.yml | 1 +
requirements.txt | 1 -
3 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/environment.yml b/environment.yml
index 5bf7ec3ac..adfef9ad0 100644
--- a/environment.yml
+++ b/environment.yml
@@ -5,6 +5,7 @@ channels:
- anaconda
- defaults
dependencies:
+- numpy>=1.22.3
- pandas
- pandoc
- pyyaml
diff --git a/environment_pre3.10.yml b/environment_pre3.10.yml
index 5079ab33d..be6461e89 100644
--- a/environment_pre3.10.yml
+++ b/environment_pre3.10.yml
@@ -5,6 +5,7 @@ channels:
- anaconda
- defaults
dependencies:
+- numpy
- pandas
- pandoc
- pyyaml
diff --git a/requirements.txt b/requirements.txt
index c61220827..f95b10ff1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,5 @@
pip
setuptools_scm[toml]>=6.0
-numpy>=1.22.3; python_version >= '3.10'
numpy>=1.18.4
pandas>=1.0.3
changeo>=1.0.0
From 90ed5d40961e6be6c6d2ae6704a84e557cbd461d Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 16:18:23 +0100
Subject: [PATCH 21/36] remove skbio dependency
---
.github/workflows/tests.yml | 18 +--
dandelion/logging/_logging.py | 4 +-
dandelion/tools/_chao1.py | 252 ++++++++++++++++++++++++++++++
dandelion/tools/_diversity.py | 9 +-
dandelion/tools/_gini.py | 108 +++++++++++++
dandelion/tools/_shannon.py | 49 ++++++
dandelion/utilities/_utilities.py | 21 ++-
environment.yml | 4 +-
environment_pre3.10.yml | 29 ----
requirements.txt | 2 -
requirements_dev.txt | 2 -
11 files changed, 443 insertions(+), 55 deletions(-)
create mode 100644 dandelion/tools/_chao1.py
create mode 100644 dandelion/tools/_gini.py
create mode 100644 dandelion/tools/_shannon.py
delete mode 100644 environment_pre3.10.yml
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index ab8fb84e9..04d8bb3ca 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -22,14 +22,14 @@ jobs:
max-parallel: 6
matrix:
config:
- - { python-version: 3.7, os: ubuntu-latest, yml-file: environment_pre3.10.yml}
- - { python-version: 3.8, os: ubuntu-latest, yml-file: environment_pre3.10.yml}
- - { python-version: 3.9, os: ubuntu-latest, yml-file: environment_pre3.10.yml}
- - { python-version: "3.10", os: ubuntu-latest, yml-file: environment.yml}
- - { python-version: 3.7, os: macos-latest, yml-file: environment_pre3.10.yml}
- - { python-version: 3.8, os: macos-latest, yml-file: environment_pre3.10.yml}
- - { python-version: 3.9, os: macos-latest, yml-file: environment_pre3.10.yml}
- - { python-version: "3.10", os: macos-latest, yml-file: environment.yml}
+ - { python-version: 3.7, os: ubuntu-latest}
+ - { python-version: 3.8, os: ubuntu-latest}
+ - { python-version: 3.9, os: ubuntu-latest}
+ - { python-version: "3.10", os: ubuntu-latest}
+ - { python-version: 3.7, os: macos-latest}
+ - { python-version: 3.8, os: macos-latest}
+ - { python-version: 3.9, os: macos-latest}
+ - { python-version: "3.10", os: macos-latest}
# disabled until it's fixed.
runs-on: ${{ matrix.config.os }}
env:
@@ -74,7 +74,7 @@ jobs:
channels: conda-forge, bioconda, anaconda, defaults
channel-priority: true
python-version: ${{ matrix.config.python-version }}
- environment-file: ${{ matrix.config.yml-file }}
+ environment-file: environment.yml
use-only-tar-bz2: true # IMPORTANT: This needs to be set for caching to work properly!
- name: Display Python version
diff --git a/dandelion/logging/_logging.py b/dandelion/logging/_logging.py
index db811de38..263dcd333 100644
--- a/dandelion/logging/_logging.py
+++ b/dandelion/logging/_logging.py
@@ -2,11 +2,11 @@
# @Author: Kelvin
# @Date: 2021-02-06 13:18:58
# @Last Modified by: Kelvin
-# @Last Modified time: 2021-02-20 09:07:55
+# @Last Modified time: 2022-05-18 16:18:14
from typing import Union, Sequence, Tuple
modules = ['dandelion', 'pandas', 'numpy', 'matplotlib',
- 'networkx', 'scipy', 'skbio', 'distance', 'polyleven']
+ 'networkx', 'scipy', 'distance', 'polyleven']
# borrowed from scanpy's logging module
diff --git a/dandelion/tools/_chao1.py b/dandelion/tools/_chao1.py
new file mode 100644
index 000000000..ca8adc3d5
--- /dev/null
+++ b/dandelion/tools/_chao1.py
@@ -0,0 +1,252 @@
+#!/usr/bin/env python
+# @Author: Kelvin
+# @Date: 2020-08-12 18:08:04
+# @Last Modified by: Kelvin
+# @Last Modified time: 2022-05-18 16:10:11
+
+# Lifted from skibio==0.5.6
+# because of issue with having skbio as a dependency
+
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, scikit-bio development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+# ----------------------------------------------------------------------------
+import numpy as np
+from ..utilities._utilities import _validate_counts_vector
+
+
+def osd(counts):
+ """Calculate observed OTUs, singles, and doubles.
+ Parameters
+ ----------
+ counts : 1-D array_like, int
+ Vector of counts.
+ Returns
+ -------
+ osd : tuple
+ Observed OTUs, singles, and doubles.
+ See Also
+ --------
+ observed_otus
+ singles
+ doubles
+ Notes
+ -----
+ This is a convenience function used by many of the other measures that rely
+ on these three measures.
+ """
+ counts = _validate_counts_vector(counts)
+ return observed_otus(counts), singles(counts), doubles(counts)
+
+
+def singles(counts):
+ """Calculate number of single occurrences (singletons).
+ Parameters
+ ----------
+ counts : 1-D array_like, int
+ Vector of counts.
+ Returns
+ -------
+ int
+ Singleton count.
+ """
+ counts = _validate_counts_vector(counts)
+ return (counts == 1).sum()
+
+
+def doubles(counts):
+ """Calculate number of double occurrences (doubletons).
+ Parameters
+ ----------
+ counts : 1-D array_like, int
+ Vector of counts.
+ Returns
+ -------
+ int
+ Doubleton count.
+ """
+ counts = _validate_counts_vector(counts)
+ return (counts == 2).sum()
+
+
+def observed_otus(counts):
+ """Calculate the number of distinct OTUs.
+ Parameters
+ ----------
+ counts : 1-D array_like, int
+ Vector of counts.
+ Returns
+ -------
+ int
+ Distinct OTU count.
+ """
+ counts = _validate_counts_vector(counts)
+ return (counts != 0).sum()
+
+
+def chao1(counts, bias_corrected=True):
+ r"""Calculate chao1 richness estimator.
+ Uses the bias-corrected version unless `bias_corrected` is ``False`` *and*
+ there are both singletons and doubletons.
+ Parameters
+ ----------
+ counts : 1-D array_like, int
+ Vector of counts.
+ bias_corrected : bool, optional
+ Indicates whether or not to use the bias-corrected version of the
+ equation. If ``False`` *and* there are both singletons and doubletons,
+ the uncorrected version will be used. The biased-corrected version will
+ be used otherwise.
+ Returns
+ -------
+ double
+ Computed chao1 richness estimator.
+ See Also
+ --------
+ chao1_ci
+ Notes
+ -----
+ The uncorrected version is based on Equation 6 in [1]_:
+ .. math::
+ chao1=S_{obs}+\frac{F_1^2}{2F_2}
+ where :math:`F_1` and :math:`F_2` are the count of singletons and
+ doubletons, respectively.
+ The bias-corrected version is defined as
+ .. math::
+ chao1=S_{obs}+\frac{F_1(F_1-1)}{2(F_2+1)}
+ References
+ ----------
+ .. [1] Chao, A. 1984. Non-parametric estimation of the number of classes in
+ a population. Scandinavian Journal of Statistics 11, 265-270.
+ """
+ counts = _validate_counts_vector(counts)
+ o, s, d = osd(counts)
+
+ if not bias_corrected and s and d:
+ return o + s**2 / (d * 2)
+ else:
+ return o + s * (s - 1) / (2 * (d + 1))
+
+
+def chao1_ci(counts, bias_corrected=True, zscore=1.96):
+ """Calculate chao1 confidence interval.
+ Parameters
+ ----------
+ counts : 1-D array_like, int
+ Vector of counts.
+ bias_corrected : bool, optional
+ Indicates whether or not to use the bias-corrected version of the
+ equation. If ``False`` *and* there are both singletons and doubletons,
+ the uncorrected version will be used. The biased-corrected version will
+ be used otherwise.
+ zscore : scalar, optional
+ Score to use for confidence. Default of 1.96 is for a 95% confidence
+ interval.
+ Returns
+ -------
+ tuple
+ chao1 confidence interval as ``(lower_bound, upper_bound)``.
+ See Also
+ --------
+ chao1
+ Notes
+ -----
+ The implementation here is based on the equations in the EstimateS manual
+ [1]_. Different equations are employed to calculate the chao1 variance and
+ confidence interval depending on `bias_corrected` and the presence/absence
+ of singletons and/or doubletons.
+ Specifically, the following EstimateS equations are used:
+ 1. No singletons, Equation 14.
+ 2. Singletons but no doubletons, Equations 7, 13.
+ 3. Singletons and doubletons, ``bias_corrected=True``, Equations 6, 13.
+ 4. Singletons and doubletons, ``bias_corrected=False``, Equations 5, 13.
+ References
+ ----------
+ .. [1] http://viceroy.eeb.uconn.edu/estimates/
+ """
+ counts = _validate_counts_vector(counts)
+ o, s, d = osd(counts)
+ if s:
+ chao = chao1(counts, bias_corrected)
+ chaovar = _chao1_var(counts, bias_corrected)
+ return _chao_confidence_with_singletons(chao, o, chaovar, zscore)
+ else:
+ n = counts.sum()
+ return _chao_confidence_no_singletons(n, o, zscore)
+
+
+def _chao1_var(counts, bias_corrected=True):
+ """Calculates chao1 variance using decision rules in EstimateS."""
+ o, s, d = osd(counts)
+ if not d:
+ c = chao1(counts, bias_corrected)
+ return _chao1_var_no_doubletons(s, c)
+ if not s:
+ n = counts.sum()
+ return _chao1_var_no_singletons(n, o)
+ if bias_corrected:
+ return _chao1_var_bias_corrected(s, d)
+ else:
+ return _chao1_var_uncorrected(s, d)
+
+
+def _chao1_var_uncorrected(singles, doubles):
+ """Calculates chao1, uncorrected.
+ From EstimateS manual, equation 5.
+ """
+ r = singles / doubles
+ return doubles * (.5 * r**2 + r**3 + .24 * r**4)
+
+
+def _chao1_var_bias_corrected(s, d):
+ """Calculates chao1 variance, bias-corrected.
+ `s` is the number of singletons and `d` is the number of doubletons.
+ From EstimateS manual, equation 6.
+ """
+ return (s * (s - 1) / (2 * (d + 1)) + (s * (2 * s - 1)**2) /
+ (4 * (d + 1)**2) + (s**2 * d * (s - 1)**2) / (4 * (d + 1)**4))
+
+
+def _chao1_var_no_doubletons(s, chao1):
+ """Calculates chao1 variance in absence of doubletons.
+ From EstimateS manual, equation 7.
+ `s` is the number of singletons, and `chao1` is the estimate of the mean of
+ Chao1 from the same dataset.
+ """
+ return s * (s - 1) / 2 + s * (2 * s - 1)**2 / 4 - s**4 / (4 * chao1)
+
+
+def _chao1_var_no_singletons(n, o):
+ """Calculates chao1 variance in absence of singletons.
+ `n` is the number of individuals and `o` is the number of observed OTUs.
+ From EstimateS manual, equation 8.
+ """
+ return o * np.exp(-n / o) * (1 - np.exp(-n / o))
+
+
+def _chao_confidence_with_singletons(chao, observed, var_chao, zscore=1.96):
+ """Calculates confidence bounds for chao1 or chao2.
+ Uses Eq. 13 of EstimateS manual.
+ `zscore` is the score to use for confidence. The default of 1.96 is for 95%
+ confidence.
+ """
+ T = chao - observed
+ # if no diff betweeh chao and observed, CI is just point estimate of
+ # observed
+ if T == 0:
+ return observed, observed
+ K = np.exp(abs(zscore) * np.sqrt(np.log(1 + (var_chao / T**2))))
+ return observed + T / K, observed + T * K
+
+
+def _chao_confidence_no_singletons(n, s, zscore=1.96):
+ """Calculates confidence bounds for chao1/chao2 in absence of singletons.
+ Uses Eq. 14 of EstimateS manual.
+ `n` is the number of individuals and `s` is the number of OTUs.
+ """
+ P = np.exp(-n / s)
+ return (max(s, s / (1 - P) - zscore * np.sqrt(
+ (s * P / (1 - P)))), s / (1 - P) + zscore * np.sqrt(s * P / (1 - P)))
\ No newline at end of file
diff --git a/dandelion/tools/_diversity.py b/dandelion/tools/_diversity.py
index be0b646c5..932b9e380 100644
--- a/dandelion/tools/_diversity.py
+++ b/dandelion/tools/_diversity.py
@@ -2,7 +2,7 @@
# @Author: Kelvin
# @Date: 2020-08-13 21:08:53
# @Last Modified by: Kelvin
-# @Last Modified time: 2022-05-18 06:37:42
+# @Last Modified time: 2022-05-18 16:15:56
import pandas as pd
import numpy as np
@@ -11,9 +11,11 @@
from ..utilities._core import *
from ..utilities._io import *
from ..tools._network import clone_centrality, clone_degree, generate_network
+from ._chao1 import chao1
+from ._gini import gini_index
+from ._shannon import shannon
from scipy.special import gammaln
from anndata import AnnData
-# from skbio.diversity.alpha import chao1, gini_index, shannon
from tqdm import tqdm
from time import sleep
from scanpy import logging as logg
@@ -418,7 +420,6 @@ def diversity_gini(self: Union[Dandelion, AnnData],
`pandas` dataframe or `Dandelion` object with updated `.metadata` slot.
"""
start = logg.info('Calculating Gini indices')
- from skbio.diversity.alpha import gini_index
def gini_indices(self: Dandelion,
groupby: str,
@@ -840,7 +841,6 @@ def diversity_chao1(
`pandas` dataframe, `Dandelion` object with updated `.metadata` slot or `AnnData` object with updated `.obs` slot.
"""
start = logg.info('Calculating Chao1 estimates')
- from skbio.diversity.alpha import chao1
def chao1_estimates(self: Union[Dandelion, AnnData],
groupby: str,
@@ -1040,7 +1040,6 @@ def diversity_shannon(
`pandas` dataframe, `Dandelion` object with updated `.metadata` slot or `AnnData` object with updated `.obs` slot.
"""
start = logg.info('Calculating Shannon entropy')
- from skbio.diversity.alpha import shannon
def shannon_entropy(self: Union[Dandelion, AnnData],
groupby: str,
diff --git a/dandelion/tools/_gini.py b/dandelion/tools/_gini.py
new file mode 100644
index 000000000..e0474e136
--- /dev/null
+++ b/dandelion/tools/_gini.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# @Author: Kelvin
+# @Date: 2020-08-12 18:08:04
+# @Last Modified by: Kelvin
+# @Last Modified time: 2022-05-18 16:07:24
+
+# Lifted from skibio==0.5.6
+# because of issue with having skbio as a dependency
+
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, scikit-bio development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+# ----------------------------------------------------------------------------
+import numpy as np
+from ..utilities._utilities import _validate_counts_vector
+
+def gini_index(data, method='rectangles'):
+ r"""Calculate the Gini index.
+ The Gini index is defined as
+ .. math::
+ G=\frac{A}{A+B}
+ where :math:`A` is the area between :math:`y=x` and the Lorenz curve and
+ :math:`B` is the area under the Lorenz curve. Simplifies to :math:`1-2B`
+ since :math:`A+B=0.5`.
+ Parameters
+ ----------
+ data : 1-D array_like
+ Vector of counts, abundances, proportions, etc. All entries must be
+ non-negative.
+ method : {'rectangles', 'trapezoids'}
+ Method for calculating the area under the Lorenz curve. If
+ ``'rectangles'``, connects the Lorenz curve points by lines parallel to
+ the x axis. This is the correct method (in our opinion) though
+ ``'trapezoids'`` might be desirable in some circumstances. If
+ ``'trapezoids'``, connects the Lorenz curve points by linear segments
+ between them. Basically assumes that the given sampling is accurate and
+ that more features of given data would fall on linear gradients between
+ the values of this data.
+ Returns
+ -------
+ double
+ Gini index.
+ Raises
+ ------
+ ValueError
+ If `method` isn't one of the supported methods for calculating the area
+ under the curve.
+ Notes
+ -----
+ The Gini index was introduced in [1]_. The formula for
+ ``method='rectangles'`` is
+ .. math::
+ dx\sum_{i=1}^n h_i
+ The formula for ``method='trapezoids'`` is
+ .. math::
+ dx(\frac{h_0+h_n}{2}+\sum_{i=1}^{n-1} h_i)
+ References
+ ----------
+ .. [1] Gini, C. (1912). "Variability and Mutability", C. Cuppini, Bologna,
+ 156 pages. Reprinted in Memorie di metodologica statistica (Ed. Pizetti
+ E, Salvemini, T). Rome: Libreria Eredi Virgilio Veschi (1955).
+ """
+ # Suppress cast to int because this method supports ints and floats.
+ data = _validate_counts_vector(data, suppress_cast=True)
+ lorenz_points = _lorenz_curve(data)
+ B = _lorenz_curve_integrator(lorenz_points, method)
+ return 1 - 2 * B
+
+
+def _lorenz_curve(data):
+ """Calculate the Lorenz curve for input data.
+ Notes
+ -----
+ Formula available on wikipedia.
+ """
+ sorted_data = np.sort(data)
+ Sn = sorted_data.sum()
+ n = sorted_data.shape[0]
+ return np.arange(1, n + 1) / n, sorted_data.cumsum() / Sn
+
+
+def _lorenz_curve_integrator(lc_pts, method):
+ """Calculates the area under a Lorenz curve.
+ Notes
+ -----
+ Could be utilized for integrating other simple, non-pathological
+ "functions" where width of the trapezoids is constant.
+ """
+ x, y = lc_pts
+
+ # each point differs by 1/n
+ dx = 1 / x.shape[0]
+
+ if method == 'trapezoids':
+ # 0 percent of the population has zero percent of the goods
+ h_0 = 0.0
+ h_n = y[-1]
+ # the 0th entry is at x=1/n
+ sum_hs = y[:-1].sum()
+ return dx * ((h_0 + h_n) / 2 + sum_hs)
+ elif method == 'rectangles':
+ return dx * y.sum()
+ else:
+ raise ValueError("Method '%s' not implemented. Available methods: "
+ "'rectangles', 'trapezoids'." % method)
diff --git a/dandelion/tools/_shannon.py b/dandelion/tools/_shannon.py
new file mode 100644
index 000000000..0e7b64c0e
--- /dev/null
+++ b/dandelion/tools/_shannon.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# @Author: Kelvin
+# @Date: 2020-08-12 18:08:04
+# @Last Modified by: Kelvin
+# @Last Modified time: 2022-05-18 16:14:13
+
+# Lifted from skibio==0.5.6
+# because of issue with having skbio as a dependency
+
+# ----------------------------------------------------------------------------
+# Copyright (c) 2013--, scikit-bio development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+# ----------------------------------------------------------------------------
+import numpy as np
+from ..utilities._utilities import _validate_counts_vector
+
+def shannon(counts, base=2):
+ r"""Calculate Shannon entropy of counts, default in bits.
+ Shannon-Wiener diversity index is defined as:
+ .. math::
+ H = -\sum_{i=1}^s\left(p_i\log_2 p_i\right)
+ where :math:`s` is the number of OTUs and :math:`p_i` is the proportion of
+ the community represented by OTU :math:`i`.
+ Parameters
+ ----------
+ counts : 1-D array_like, int
+ Vector of counts.
+ base : scalar, optional
+ Logarithm base to use in the calculations.
+ Returns
+ -------
+ double
+ Shannon diversity index H.
+ Notes
+ -----
+ The implementation here is based on the description given in the SDR-IV
+ online manual [1]_ except that the default logarithm base used here is 2
+ instead of :math:`e`.
+ References
+ ----------
+ .. [1] http://www.pisces-conservation.com/sdrhelp/index.html
+ """
+ counts = _validate_counts_vector(counts)
+ freqs = counts / counts.sum()
+ nonzero_freqs = freqs[freqs.nonzero()]
+ return -(nonzero_freqs * np.log(nonzero_freqs)).sum() / np.log(base)
diff --git a/dandelion/utilities/_utilities.py b/dandelion/utilities/_utilities.py
index 744036537..2d5d02aa6 100644
--- a/dandelion/utilities/_utilities.py
+++ b/dandelion/utilities/_utilities.py
@@ -2,7 +2,7 @@
# @Author: kt16
# @Date: 2020-05-12 14:01:32
# @Last Modified by: Kelvin
-# @Last Modified time: 2022-05-18 02:37:52
+# @Last Modified time: 2022-05-18 16:15:18
import os
import re
@@ -29,7 +29,6 @@
class LiteralMeta(type):
"""LiteralMeta class."""
-
def __getitem__(self, values):
"""Return Literal."""
if not isinstance(values, tuple):
@@ -42,7 +41,6 @@ class Literal(metaclass=LiteralMeta):
class Tree(defaultdict):
"""Create a recursive defaultdict."""
-
def __init__(self, value=None):
super(Tree, self).__init__(Tree)
self.value = value
@@ -527,7 +525,6 @@ def load_data(obj: Union[pd.DataFrame, str]) -> pd.DataFrame:
class ContigDict(dict):
"""Class Object to extract the contigs as a dictionary."""
-
def __setitem__(self, key, value):
"""Standard __setitem__."""
super().__setitem__(key, value)
@@ -586,3 +583,19 @@ def write_airr(data, save):
def write_blastn(data, save):
data = sanitize_blastn(data)
data.to_csv(save, sep='\t', index=False)
+
+
+## from skbio==0.5.6
+def _validate_counts_vector(counts, suppress_cast=False):
+ """Validate and convert input to an acceptable counts vector type.
+ Note: may not always return a copy of `counts`!
+ """
+ counts = np.asarray(counts)
+ if not np.all(np.isreal(counts)):
+ raise ValueError("Counts vector must contain real-valued entries.")
+ if counts.ndim != 1:
+ raise ValueError("Only 1-D vectors are supported.")
+ elif (counts < 0).any():
+ raise ValueError("Counts vector cannot contain negative values.")
+
+ return counts
diff --git a/environment.yml b/environment.yml
index adfef9ad0..76634d6c4 100644
--- a/environment.yml
+++ b/environment.yml
@@ -5,7 +5,7 @@ channels:
- anaconda
- defaults
dependencies:
-- numpy>=1.22.3
+- numpy
- pandas
- pandoc
- pyyaml
@@ -24,6 +24,6 @@ dependencies:
- rpy2==3.4.2
- pytest-cov
- -r requirements.txt
- - nxviz>=0.7.3
+ - nxviz>=0.6.2
- scirpy
- scrublet
\ No newline at end of file
diff --git a/environment_pre3.10.yml b/environment_pre3.10.yml
deleted file mode 100644
index be6461e89..000000000
--- a/environment_pre3.10.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-name: dandelion
-channels:
-- conda-forge
-- bioconda
-- anaconda
-- defaults
-dependencies:
-- numpy
-- pandas
-- pandoc
-- pyyaml
-- changeo
-- seaborn
-- statsmodels
-- numba
-- pytables
-- pytest
-- pip
-- tbb
-- pip:
- - nbsphinx
- - sphinx-autodoc-typehints
- - annoy==1.16.3
- - rpy2==3.4.2
- - pytest-cov
- - -r requirements.txt
- - git+https://www.github.com/zktuong/nxviz.git
- - scirpy
- - scrublet
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index f95b10ff1..6206acc0b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,8 +6,6 @@ changeo>=1.0.0
anndata>=0.7.1
scanpy>=1.4.6
scikit-learn>=0.23.0
-scikit-bio==0.5.6; python_version < '3.10'
-scikit-bio>=0.5.7; python_version >= '3.10'
scipy>=1.4.1
numba>=0.48.0
seaborn>=0.10.1
diff --git a/requirements_dev.txt b/requirements_dev.txt
index b365ed99c..dcc419e07 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -5,8 +5,6 @@ pandas>=1.0.3
changeo>=1.0.0
anndata>=0.7.6
scanpy>=1.4.6
-scikit-learn>=0.23.0
-scikit-bio==0.5.6
scipy>=1.4.1
numba>=0.48.0
seaborn>=0.10.1
From 064fcbe08a30f75c48c3bf4f11f96b6f0ef3d6f9 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 16:35:05 +0100
Subject: [PATCH 22/36] Update _chao1.py
block out unused code
---
dandelion/tools/_chao1.py | 240 +++++++++++++++++++-------------------
1 file changed, 120 insertions(+), 120 deletions(-)
diff --git a/dandelion/tools/_chao1.py b/dandelion/tools/_chao1.py
index ca8adc3d5..626c2b3a9 100644
--- a/dandelion/tools/_chao1.py
+++ b/dandelion/tools/_chao1.py
@@ -2,7 +2,7 @@
# @Author: Kelvin
# @Date: 2020-08-12 18:08:04
# @Last Modified by: Kelvin
-# @Last Modified time: 2022-05-18 16:10:11
+# @Last Modified time: 2022-05-18 16:34:56
# Lifted from skibio==0.5.6
# because of issue with having skbio as a dependency
@@ -131,122 +131,122 @@ def chao1(counts, bias_corrected=True):
return o + s * (s - 1) / (2 * (d + 1))
-def chao1_ci(counts, bias_corrected=True, zscore=1.96):
- """Calculate chao1 confidence interval.
- Parameters
- ----------
- counts : 1-D array_like, int
- Vector of counts.
- bias_corrected : bool, optional
- Indicates whether or not to use the bias-corrected version of the
- equation. If ``False`` *and* there are both singletons and doubletons,
- the uncorrected version will be used. The biased-corrected version will
- be used otherwise.
- zscore : scalar, optional
- Score to use for confidence. Default of 1.96 is for a 95% confidence
- interval.
- Returns
- -------
- tuple
- chao1 confidence interval as ``(lower_bound, upper_bound)``.
- See Also
- --------
- chao1
- Notes
- -----
- The implementation here is based on the equations in the EstimateS manual
- [1]_. Different equations are employed to calculate the chao1 variance and
- confidence interval depending on `bias_corrected` and the presence/absence
- of singletons and/or doubletons.
- Specifically, the following EstimateS equations are used:
- 1. No singletons, Equation 14.
- 2. Singletons but no doubletons, Equations 7, 13.
- 3. Singletons and doubletons, ``bias_corrected=True``, Equations 6, 13.
- 4. Singletons and doubletons, ``bias_corrected=False``, Equations 5, 13.
- References
- ----------
- .. [1] http://viceroy.eeb.uconn.edu/estimates/
- """
- counts = _validate_counts_vector(counts)
- o, s, d = osd(counts)
- if s:
- chao = chao1(counts, bias_corrected)
- chaovar = _chao1_var(counts, bias_corrected)
- return _chao_confidence_with_singletons(chao, o, chaovar, zscore)
- else:
- n = counts.sum()
- return _chao_confidence_no_singletons(n, o, zscore)
-
-
-def _chao1_var(counts, bias_corrected=True):
- """Calculates chao1 variance using decision rules in EstimateS."""
- o, s, d = osd(counts)
- if not d:
- c = chao1(counts, bias_corrected)
- return _chao1_var_no_doubletons(s, c)
- if not s:
- n = counts.sum()
- return _chao1_var_no_singletons(n, o)
- if bias_corrected:
- return _chao1_var_bias_corrected(s, d)
- else:
- return _chao1_var_uncorrected(s, d)
-
-
-def _chao1_var_uncorrected(singles, doubles):
- """Calculates chao1, uncorrected.
- From EstimateS manual, equation 5.
- """
- r = singles / doubles
- return doubles * (.5 * r**2 + r**3 + .24 * r**4)
-
-
-def _chao1_var_bias_corrected(s, d):
- """Calculates chao1 variance, bias-corrected.
- `s` is the number of singletons and `d` is the number of doubletons.
- From EstimateS manual, equation 6.
- """
- return (s * (s - 1) / (2 * (d + 1)) + (s * (2 * s - 1)**2) /
- (4 * (d + 1)**2) + (s**2 * d * (s - 1)**2) / (4 * (d + 1)**4))
-
-
-def _chao1_var_no_doubletons(s, chao1):
- """Calculates chao1 variance in absence of doubletons.
- From EstimateS manual, equation 7.
- `s` is the number of singletons, and `chao1` is the estimate of the mean of
- Chao1 from the same dataset.
- """
- return s * (s - 1) / 2 + s * (2 * s - 1)**2 / 4 - s**4 / (4 * chao1)
-
-
-def _chao1_var_no_singletons(n, o):
- """Calculates chao1 variance in absence of singletons.
- `n` is the number of individuals and `o` is the number of observed OTUs.
- From EstimateS manual, equation 8.
- """
- return o * np.exp(-n / o) * (1 - np.exp(-n / o))
-
-
-def _chao_confidence_with_singletons(chao, observed, var_chao, zscore=1.96):
- """Calculates confidence bounds for chao1 or chao2.
- Uses Eq. 13 of EstimateS manual.
- `zscore` is the score to use for confidence. The default of 1.96 is for 95%
- confidence.
- """
- T = chao - observed
- # if no diff betweeh chao and observed, CI is just point estimate of
- # observed
- if T == 0:
- return observed, observed
- K = np.exp(abs(zscore) * np.sqrt(np.log(1 + (var_chao / T**2))))
- return observed + T / K, observed + T * K
-
-
-def _chao_confidence_no_singletons(n, s, zscore=1.96):
- """Calculates confidence bounds for chao1/chao2 in absence of singletons.
- Uses Eq. 14 of EstimateS manual.
- `n` is the number of individuals and `s` is the number of OTUs.
- """
- P = np.exp(-n / s)
- return (max(s, s / (1 - P) - zscore * np.sqrt(
- (s * P / (1 - P)))), s / (1 - P) + zscore * np.sqrt(s * P / (1 - P)))
\ No newline at end of file
+# def chao1_ci(counts, bias_corrected=True, zscore=1.96):
+# """Calculate chao1 confidence interval.
+# Parameters
+# ----------
+# counts : 1-D array_like, int
+# Vector of counts.
+# bias_corrected : bool, optional
+# Indicates whether or not to use the bias-corrected version of the
+# equation. If ``False`` *and* there are both singletons and doubletons,
+# the uncorrected version will be used. The biased-corrected version will
+# be used otherwise.
+# zscore : scalar, optional
+# Score to use for confidence. Default of 1.96 is for a 95% confidence
+# interval.
+# Returns
+# -------
+# tuple
+# chao1 confidence interval as ``(lower_bound, upper_bound)``.
+# See Also
+# --------
+# chao1
+# Notes
+# -----
+# The implementation here is based on the equations in the EstimateS manual
+# [1]_. Different equations are employed to calculate the chao1 variance and
+# confidence interval depending on `bias_corrected` and the presence/absence
+# of singletons and/or doubletons.
+# Specifically, the following EstimateS equations are used:
+# 1. No singletons, Equation 14.
+# 2. Singletons but no doubletons, Equations 7, 13.
+# 3. Singletons and doubletons, ``bias_corrected=True``, Equations 6, 13.
+# 4. Singletons and doubletons, ``bias_corrected=False``, Equations 5, 13.
+# References
+# ----------
+# .. [1] http://viceroy.eeb.uconn.edu/estimates/
+# """
+# counts = _validate_counts_vector(counts)
+# o, s, d = osd(counts)
+# if s:
+# chao = chao1(counts, bias_corrected)
+# chaovar = _chao1_var(counts, bias_corrected)
+# return _chao_confidence_with_singletons(chao, o, chaovar, zscore)
+# else:
+# n = counts.sum()
+# return _chao_confidence_no_singletons(n, o, zscore)
+
+
+# def _chao1_var(counts, bias_corrected=True):
+# """Calculates chao1 variance using decision rules in EstimateS."""
+# o, s, d = osd(counts)
+# if not d:
+# c = chao1(counts, bias_corrected)
+# return _chao1_var_no_doubletons(s, c)
+# if not s:
+# n = counts.sum()
+# return _chao1_var_no_singletons(n, o)
+# if bias_corrected:
+# return _chao1_var_bias_corrected(s, d)
+# else:
+# return _chao1_var_uncorrected(s, d)
+
+
+# def _chao1_var_uncorrected(singles, doubles):
+# """Calculates chao1, uncorrected.
+# From EstimateS manual, equation 5.
+# """
+# r = singles / doubles
+# return doubles * (.5 * r**2 + r**3 + .24 * r**4)
+
+
+# def _chao1_var_bias_corrected(s, d):
+# """Calculates chao1 variance, bias-corrected.
+# `s` is the number of singletons and `d` is the number of doubletons.
+# From EstimateS manual, equation 6.
+# """
+# return (s * (s - 1) / (2 * (d + 1)) + (s * (2 * s - 1)**2) /
+# (4 * (d + 1)**2) + (s**2 * d * (s - 1)**2) / (4 * (d + 1)**4))
+
+
+# def _chao1_var_no_doubletons(s, chao1):
+# """Calculates chao1 variance in absence of doubletons.
+# From EstimateS manual, equation 7.
+# `s` is the number of singletons, and `chao1` is the estimate of the mean of
+# Chao1 from the same dataset.
+# """
+# return s * (s - 1) / 2 + s * (2 * s - 1)**2 / 4 - s**4 / (4 * chao1)
+
+
+# def _chao1_var_no_singletons(n, o):
+# """Calculates chao1 variance in absence of singletons.
+# `n` is the number of individuals and `o` is the number of observed OTUs.
+# From EstimateS manual, equation 8.
+# """
+# return o * np.exp(-n / o) * (1 - np.exp(-n / o))
+
+
+# def _chao_confidence_with_singletons(chao, observed, var_chao, zscore=1.96):
+# """Calculates confidence bounds for chao1 or chao2.
+# Uses Eq. 13 of EstimateS manual.
+# `zscore` is the score to use for confidence. The default of 1.96 is for 95%
+# confidence.
+# """
+# T = chao - observed
+# # if no diff betweeh chao and observed, CI is just point estimate of
+# # observed
+# if T == 0:
+# return observed, observed
+# K = np.exp(abs(zscore) * np.sqrt(np.log(1 + (var_chao / T**2))))
+# return observed + T / K, observed + T * K
+
+
+# def _chao_confidence_no_singletons(n, s, zscore=1.96):
+# """Calculates confidence bounds for chao1/chao2 in absence of singletons.
+# Uses Eq. 14 of EstimateS manual.
+# `n` is the number of individuals and `s` is the number of OTUs.
+# """
+# P = np.exp(-n / s)
+# return (max(s, s / (1 - P) - zscore * np.sqrt(
+# (s * P / (1 - P)))), s / (1 - P) + zscore * np.sqrt(s * P / (1 - P)))
\ No newline at end of file
From 26e3bc2ed01fc499723fd37c93dda83189dd036b Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Wed, 18 May 2022 17:41:45 +0100
Subject: [PATCH 23/36] remove joblib as dependency
---
README.md | 2 --
dandelion/preprocessing/_preprocessing.py | 3 +--
docs/README.md | 2 --
docs/README.rst | 2 --
docs/environment.yml | 2 --
requirements.txt | 1 -
requirements_dev.txt | 1 -
7 files changed, 1 insertion(+), 12 deletions(-)
diff --git a/README.md b/README.md
index 16204b2fe..ad956fb9f 100644
--- a/README.md
+++ b/README.md
@@ -136,7 +136,6 @@ python>=3.7,<=3.8 (conda-forge)
numpy>=1.18.4 (conda-forge)
pandas>=1.0.3 (conda-forge)
distance>=0.1.3 (conda-forge)
-joblib>=0.14.1 (conda-forge)
jupyter (conda-forge) # if running via a notebook
scikit-learn>=0.23.0 (conda-forge)
numba>=0.48.0 (conda-forge)
@@ -153,7 +152,6 @@ igblast>=1.15.0 (bioconda)
anndata>=0.7.1
scanpy>=1.4.6
scrublet>=0.2.1
-scikit-bio>=0.5.6
changeo>=1.0.0
presto>=0.6.0
polyleven>=0.5
diff --git a/dandelion/preprocessing/_preprocessing.py b/dandelion/preprocessing/_preprocessing.py
index e8c7427a2..7cffa9095 100644
--- a/dandelion/preprocessing/_preprocessing.py
+++ b/dandelion/preprocessing/_preprocessing.py
@@ -2,13 +2,12 @@
# @Author: kt16
# @Date: 2020-05-12 17:56:02
# @Last Modified by: Kelvin
-# @Last Modified time: 2022-04-08 11:40:40
+# @Last Modified time: 2022-05-18 17:37:10
import os
import pandas as pd
from subprocess import run
from tqdm import tqdm
-from joblib import Parallel, delayed
from collections import OrderedDict
from time import sleep
from ..utilities._utilities import *
diff --git a/docs/README.md b/docs/README.md
index 1645381c6..89cd9b284 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -128,7 +128,6 @@ python>=3.7,<=3.8 (conda-forge)
numpy>=1.18.4 (conda-forge)
pandas>=1.0.3 (conda-forge)
distance>=0.1.3 (conda-forge)
-joblib>=0.14.1 (conda-forge)
jupyter (conda-forge) # if running via a notebook
scikit-learn>=0.23.0 (conda-forge)
numba>=0.48.0 (conda-forge)
@@ -145,7 +144,6 @@ igblast>=1.15.0 (bioconda)
anndata>=0.7.1
scanpy>=1.4.6
scrublet>=0.2.1
-scikit-bio>=0.5.6
changeo>=1.0.0
presto>=0.6.0
polyleven>=0.5
diff --git a/docs/README.rst b/docs/README.rst
index 52f691dab..0e2e1c1bd 100644
--- a/docs/README.rst
+++ b/docs/README.rst
@@ -185,7 +185,6 @@ Python packages
numpy>=1.18.4 (conda-forge)
pandas>=1.0.3 (conda-forge)
distance>=0.1.3 (conda-forge)
- joblib>=0.14.1 (conda-forge)
jupyter (conda-forge) # if running via a notebook
scikit-learn>=0.23.0 (conda-forge)
numba>=0.48.0 (conda-forge)
@@ -202,7 +201,6 @@ Python packages
anndata>=0.7.1
scanpy>=1.4.6
scrublet>=0.2.1
- scikit-bio>=0.5.6
changeo>=1.0.0
presto>=0.6.0
polyleven>=0.5
diff --git a/docs/environment.yml b/docs/environment.yml
index 1538fe58d..fe5126760 100644
--- a/docs/environment.yml
+++ b/docs/environment.yml
@@ -34,9 +34,7 @@ dependencies:
- anndata>=0.7.1
- scanpy>=1.7.0
- distance>=0.1.3
- - joblib>=0.14.1
- scikit-learn>=0.23.0
- - scikit-bio>=0.5.6
- scipy>=1.4.1
- numba>=0.48.0,<0.54.0
- seaborn>=0.10.1
diff --git a/requirements.txt b/requirements.txt
index 6206acc0b..41cf1d8a4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -15,5 +15,4 @@ polyleven>=0.5
h5py>=3.1.0
adjustText>=0.7
distance>=0.1.3
-joblib>=0.14.1
plotnine>=0.6.0
diff --git a/requirements_dev.txt b/requirements_dev.txt
index dcc419e07..9c0c4c5d7 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -14,5 +14,4 @@ polyleven>=0.5
h5py>=3.1.0
adjustText>=0.7
distance>=0.1.3
-joblib>=0.14.1
plotnine>=0.6.0
From 117d0fb391c16a01c3a69ba57e63e8ebfbc22645 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Thu, 19 May 2022 03:47:53 +0100
Subject: [PATCH 24/36] try to unstuck the macos runners
---
tests/test_tools.py | 36 +++++++++++++++++++++---------------
1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 46849014a..0c9e48d8b 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -10,6 +10,7 @@
json_10x_cr6, dummy_adata_cr6)
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_setup(create_testfolder, airr_reannotated, dummy_adata):
vdj, adata = ddl.pp.filter_contigs(airr_reannotated, dummy_adata)
assert airr_reannotated.shape[0] == 9
@@ -23,6 +24,7 @@ def test_setup(create_testfolder, airr_reannotated, dummy_adata):
assert vdj2.metadata is not None
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_find_clones(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -33,6 +35,7 @@ def test_find_clones(create_testfolder):
vdj.write_h5(f)
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_clone_size(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -42,6 +45,7 @@ def test_clone_size(create_testfolder):
assert not vdj.metadata.clone_id_size.empty
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize(
"resample,expected",
[pytest.param(None, 4), pytest.param(3, 3)])
@@ -64,6 +68,7 @@ def test_generate_network(create_testfolder, resample, expected):
assert vdj.edges is not None
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_find_clones_key(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -77,6 +82,7 @@ def test_find_clones_key(create_testfolder):
assert vdj.graph is not None
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_transfer(create_testfolder, dummy_adata):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -90,6 +96,7 @@ def test_transfer(create_testfolder, dummy_adata):
dummy_adata.write_h5ad(f2)
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity_gini(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -107,6 +114,7 @@ def test_diversity_gini(create_testfolder):
assert isinstance(tmp, pd.DataFrame)
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity_gini(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -117,6 +125,7 @@ def test_diversity_gini(create_testfolder):
assert isinstance(tmp, pd.DataFrame)
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize("resample", [True, False])
def test_diversity_chao(create_testfolder, resample):
f = create_testfolder / "test.h5"
@@ -140,6 +149,7 @@ def test_diversity_chao(create_testfolder, resample):
assert isinstance(tmp, pd.DataFrame)
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize("method,diversitykey", [
pytest.param('chao1', None),
pytest.param('chao1', 'test_diversity_key'),
@@ -159,6 +169,7 @@ def test_diversity_anndata(create_testfolder, method, diversitykey):
assert 'test_diversity_key' in adata.uns
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize("resample,normalize", [
pytest.param(True, True),
pytest.param(False, True),
@@ -192,6 +203,7 @@ def test_diversity_shannon(create_testfolder, resample, normalize):
assert isinstance(tmp, pd.DataFrame)
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_setup2(create_testfolder, json_10x_cr6, dummy_adata_cr6):
json_file = str(create_testfolder) + "/test_all_contig_annotations.json"
with open(json_file, 'w') as outfile:
@@ -211,6 +223,7 @@ def test_setup2(create_testfolder, json_10x_cr6, dummy_adata_cr6):
adata.write_h5ad(f2)
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity_rarefaction(create_testfolder):
f = create_testfolder / "test.h5ad"
adata = sc.read_h5ad(f)
@@ -224,6 +237,7 @@ def test_diversity_rarefaction(create_testfolder):
assert p is not None
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity_rarefaction2(create_testfolder):
f = create_testfolder / "test.h5ad"
adata = sc.read_h5ad(f)
@@ -236,6 +250,7 @@ def test_diversity_rarefaction2(create_testfolder):
assert p is not None
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity_rarefaction3(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -251,6 +266,7 @@ def test_diversity_rarefaction3(create_testfolder):
assert p is not None
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize(
"metric", ['clone_network', None, 'clone_degree', 'clone_centrality'])
def test_diversity_gini2(create_testfolder, metric):
@@ -281,6 +297,7 @@ def test_diversity_gini2(create_testfolder, metric):
assert not vdj.metadata.clone_centrality_gini.empty
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity2a(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -298,6 +315,7 @@ def test_diversity2a(create_testfolder):
assert not vdj.metadata.clone_network_vertex_size_gini.empty
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity2b(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -315,6 +333,7 @@ def test_diversity2b(create_testfolder):
assert not vdj.metadata.clone_network_vertex_size_gini.empty
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity2c(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -331,21 +350,7 @@ def test_diversity2c(create_testfolder):
assert isinstance(x, pd.DataFrame)
-def test_overlap1(create_testfolder):
- f = create_testfolder / "test.h5ad"
- adata = sc.read_h5ad(f)
- ddl.tl.clone_overlap(adata, groupby='group3', colorby='group2')
- assert 'clone_overlap' in adata.uns
- assert isinstance(adata.uns['clone_overlap'], pd.DataFrame)
- ddl.pl.clone_overlap(adata, groupby='group3', colorby='group2')
-
-
-def test_overlap2(create_testfolder):
- f = create_testfolder / "test.h5ad"
- adata = sc.read_h5ad(f)
- ddl.pl.clone_overlap(adata, groupby='group3', colorby='group2')
-
-
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_extract_edge_weights(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -355,6 +360,7 @@ def test_extract_edge_weights(create_testfolder):
assert x is None
+@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize("method", [
pytest.param('chao1'),
pytest.param('shannon'),
From b0731785dbd210b243330690aaabd6ec4582bede Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Thu, 19 May 2022 04:00:11 +0100
Subject: [PATCH 25/36] Update test_tools.py
---
tests/test_tools.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 0c9e48d8b..01602e3e1 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+import sys
import pytest
import json
import pandas as pd
From eb7d1e1bbc72db1eae29d97cb783fc5929bdf93d Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Thu, 19 May 2022 05:00:58 +0100
Subject: [PATCH 26/36] Update test_tools.py
---
tests/test_tools.py | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 01602e3e1..388136713 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -11,7 +11,6 @@
json_10x_cr6, dummy_adata_cr6)
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_setup(create_testfolder, airr_reannotated, dummy_adata):
vdj, adata = ddl.pp.filter_contigs(airr_reannotated, dummy_adata)
assert airr_reannotated.shape[0] == 9
@@ -25,7 +24,6 @@ def test_setup(create_testfolder, airr_reannotated, dummy_adata):
assert vdj2.metadata is not None
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_find_clones(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -36,7 +34,6 @@ def test_find_clones(create_testfolder):
vdj.write_h5(f)
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_clone_size(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -46,7 +43,6 @@ def test_clone_size(create_testfolder):
assert not vdj.metadata.clone_id_size.empty
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize(
"resample,expected",
[pytest.param(None, 4), pytest.param(3, 3)])
@@ -69,7 +65,6 @@ def test_generate_network(create_testfolder, resample, expected):
assert vdj.edges is not None
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_find_clones_key(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -83,7 +78,6 @@ def test_find_clones_key(create_testfolder):
assert vdj.graph is not None
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_transfer(create_testfolder, dummy_adata):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -97,7 +91,6 @@ def test_transfer(create_testfolder, dummy_adata):
dummy_adata.write_h5ad(f2)
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity_gini(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -115,7 +108,6 @@ def test_diversity_gini(create_testfolder):
assert isinstance(tmp, pd.DataFrame)
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity_gini(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -126,7 +118,6 @@ def test_diversity_gini(create_testfolder):
assert isinstance(tmp, pd.DataFrame)
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize("resample", [True, False])
def test_diversity_chao(create_testfolder, resample):
f = create_testfolder / "test.h5"
@@ -150,7 +141,6 @@ def test_diversity_chao(create_testfolder, resample):
assert isinstance(tmp, pd.DataFrame)
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize("method,diversitykey", [
pytest.param('chao1', None),
pytest.param('chao1', 'test_diversity_key'),
@@ -170,7 +160,6 @@ def test_diversity_anndata(create_testfolder, method, diversitykey):
assert 'test_diversity_key' in adata.uns
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize("resample,normalize", [
pytest.param(True, True),
pytest.param(False, True),
@@ -204,7 +193,6 @@ def test_diversity_shannon(create_testfolder, resample, normalize):
assert isinstance(tmp, pd.DataFrame)
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_setup2(create_testfolder, json_10x_cr6, dummy_adata_cr6):
json_file = str(create_testfolder) + "/test_all_contig_annotations.json"
with open(json_file, 'w') as outfile:
@@ -224,7 +212,6 @@ def test_setup2(create_testfolder, json_10x_cr6, dummy_adata_cr6):
adata.write_h5ad(f2)
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity_rarefaction(create_testfolder):
f = create_testfolder / "test.h5ad"
adata = sc.read_h5ad(f)
@@ -238,7 +225,6 @@ def test_diversity_rarefaction(create_testfolder):
assert p is not None
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity_rarefaction2(create_testfolder):
f = create_testfolder / "test.h5ad"
adata = sc.read_h5ad(f)
@@ -251,7 +237,6 @@ def test_diversity_rarefaction2(create_testfolder):
assert p is not None
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity_rarefaction3(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -267,7 +252,6 @@ def test_diversity_rarefaction3(create_testfolder):
assert p is not None
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize(
"metric", ['clone_network', None, 'clone_degree', 'clone_centrality'])
def test_diversity_gini2(create_testfolder, metric):
@@ -298,7 +282,6 @@ def test_diversity_gini2(create_testfolder, metric):
assert not vdj.metadata.clone_centrality_gini.empty
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity2a(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -316,7 +299,6 @@ def test_diversity2a(create_testfolder):
assert not vdj.metadata.clone_network_vertex_size_gini.empty
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity2b(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -334,7 +316,6 @@ def test_diversity2b(create_testfolder):
assert not vdj.metadata.clone_network_vertex_size_gini.empty
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_diversity2c(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -351,7 +332,6 @@ def test_diversity2c(create_testfolder):
assert isinstance(x, pd.DataFrame)
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
def test_extract_edge_weights(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -361,7 +341,6 @@ def test_extract_edge_weights(create_testfolder):
assert x is None
-@pytest.mark.skipif(sys.platform == 'darwin', reason="macos CI stalls.")
@pytest.mark.parametrize("method", [
pytest.param('chao1'),
pytest.param('shannon'),
From 63dfc94aac30454c5b2a89400762f4b7d749db3e Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Thu, 19 May 2022 05:36:38 +0100
Subject: [PATCH 27/36] Update test_tools.py
---
tests/test_tools.py | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 388136713..0d739a16a 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -11,6 +11,7 @@
json_10x_cr6, dummy_adata_cr6)
+@pytest.mark.tryfirst
def test_setup(create_testfolder, airr_reannotated, dummy_adata):
vdj, adata = ddl.pp.filter_contigs(airr_reannotated, dummy_adata)
assert airr_reannotated.shape[0] == 9
@@ -24,6 +25,7 @@ def test_setup(create_testfolder, airr_reannotated, dummy_adata):
assert vdj2.metadata is not None
+@pytest.mark.tryfirst
def test_find_clones(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -34,6 +36,7 @@ def test_find_clones(create_testfolder):
vdj.write_h5(f)
+@pytest.mark.tryfirst
def test_clone_size(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -43,6 +46,7 @@ def test_clone_size(create_testfolder):
assert not vdj.metadata.clone_id_size.empty
+@pytest.mark.tryfirst
@pytest.mark.parametrize(
"resample,expected",
[pytest.param(None, 4), pytest.param(3, 3)])
@@ -65,6 +69,7 @@ def test_generate_network(create_testfolder, resample, expected):
assert vdj.edges is not None
+@pytest.mark.tryfirst
def test_find_clones_key(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -78,6 +83,7 @@ def test_find_clones_key(create_testfolder):
assert vdj.graph is not None
+@pytest.mark.tryfirst
def test_transfer(create_testfolder, dummy_adata):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -91,6 +97,7 @@ def test_transfer(create_testfolder, dummy_adata):
dummy_adata.write_h5ad(f2)
+@pytest.mark.tryfirst
def test_diversity_gini(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -108,6 +115,7 @@ def test_diversity_gini(create_testfolder):
assert isinstance(tmp, pd.DataFrame)
+@pytest.mark.tryfirst
def test_diversity_gini(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -118,6 +126,7 @@ def test_diversity_gini(create_testfolder):
assert isinstance(tmp, pd.DataFrame)
+@pytest.mark.tryfirst
@pytest.mark.parametrize("resample", [True, False])
def test_diversity_chao(create_testfolder, resample):
f = create_testfolder / "test.h5"
@@ -141,6 +150,7 @@ def test_diversity_chao(create_testfolder, resample):
assert isinstance(tmp, pd.DataFrame)
+@pytest.mark.tryfirst
@pytest.mark.parametrize("method,diversitykey", [
pytest.param('chao1', None),
pytest.param('chao1', 'test_diversity_key'),
@@ -160,6 +170,7 @@ def test_diversity_anndata(create_testfolder, method, diversitykey):
assert 'test_diversity_key' in adata.uns
+@pytest.mark.tryfirst
@pytest.mark.parametrize("resample,normalize", [
pytest.param(True, True),
pytest.param(False, True),
@@ -193,6 +204,7 @@ def test_diversity_shannon(create_testfolder, resample, normalize):
assert isinstance(tmp, pd.DataFrame)
+@pytest.mark.tryfirst
def test_setup2(create_testfolder, json_10x_cr6, dummy_adata_cr6):
json_file = str(create_testfolder) + "/test_all_contig_annotations.json"
with open(json_file, 'w') as outfile:
@@ -212,6 +224,7 @@ def test_setup2(create_testfolder, json_10x_cr6, dummy_adata_cr6):
adata.write_h5ad(f2)
+@pytest.mark.tryfirst
def test_diversity_rarefaction(create_testfolder):
f = create_testfolder / "test.h5ad"
adata = sc.read_h5ad(f)
@@ -225,6 +238,7 @@ def test_diversity_rarefaction(create_testfolder):
assert p is not None
+@pytest.mark.tryfirst
def test_diversity_rarefaction2(create_testfolder):
f = create_testfolder / "test.h5ad"
adata = sc.read_h5ad(f)
@@ -237,6 +251,7 @@ def test_diversity_rarefaction2(create_testfolder):
assert p is not None
+@pytest.mark.tryfirst
def test_diversity_rarefaction3(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -252,6 +267,7 @@ def test_diversity_rarefaction3(create_testfolder):
assert p is not None
+@pytest.mark.tryfirst
@pytest.mark.parametrize(
"metric", ['clone_network', None, 'clone_degree', 'clone_centrality'])
def test_diversity_gini2(create_testfolder, metric):
@@ -282,6 +298,7 @@ def test_diversity_gini2(create_testfolder, metric):
assert not vdj.metadata.clone_centrality_gini.empty
+@pytest.mark.tryfirst
def test_diversity2a(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -299,6 +316,7 @@ def test_diversity2a(create_testfolder):
assert not vdj.metadata.clone_network_vertex_size_gini.empty
+@pytest.mark.tryfirst
def test_diversity2b(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -316,6 +334,7 @@ def test_diversity2b(create_testfolder):
assert not vdj.metadata.clone_network_vertex_size_gini.empty
+@pytest.mark.tryfirst
def test_diversity2c(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -332,6 +351,7 @@ def test_diversity2c(create_testfolder):
assert isinstance(x, pd.DataFrame)
+@pytest.mark.tryfirst
def test_extract_edge_weights(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -341,6 +361,7 @@ def test_extract_edge_weights(create_testfolder):
assert x is None
+@pytest.mark.tryfirst
@pytest.mark.parametrize("method", [
pytest.param('chao1'),
pytest.param('shannon'),
From 697f38e1e622543baee3b732e3f3a96f665f40be Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Thu, 19 May 2022 05:39:50 +0100
Subject: [PATCH 28/36] Update test_tools.py
---
tests/test_tools.py | 42 +++++++++++++++++++++---------------------
1 file changed, 21 insertions(+), 21 deletions(-)
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 0d739a16a..b558b8de2 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -11,7 +11,7 @@
json_10x_cr6, dummy_adata_cr6)
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_setup(create_testfolder, airr_reannotated, dummy_adata):
vdj, adata = ddl.pp.filter_contigs(airr_reannotated, dummy_adata)
assert airr_reannotated.shape[0] == 9
@@ -25,7 +25,7 @@ def test_setup(create_testfolder, airr_reannotated, dummy_adata):
assert vdj2.metadata is not None
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_find_clones(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -36,7 +36,7 @@ def test_find_clones(create_testfolder):
vdj.write_h5(f)
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_clone_size(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -46,7 +46,7 @@ def test_clone_size(create_testfolder):
assert not vdj.metadata.clone_id_size.empty
-@pytest.mark.tryfirst
+@pytest.mark.slow
@pytest.mark.parametrize(
"resample,expected",
[pytest.param(None, 4), pytest.param(3, 3)])
@@ -69,7 +69,7 @@ def test_generate_network(create_testfolder, resample, expected):
assert vdj.edges is not None
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_find_clones_key(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -83,7 +83,7 @@ def test_find_clones_key(create_testfolder):
assert vdj.graph is not None
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_transfer(create_testfolder, dummy_adata):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -97,7 +97,7 @@ def test_transfer(create_testfolder, dummy_adata):
dummy_adata.write_h5ad(f2)
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_diversity_gini(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -115,7 +115,7 @@ def test_diversity_gini(create_testfolder):
assert isinstance(tmp, pd.DataFrame)
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_diversity_gini(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -126,7 +126,7 @@ def test_diversity_gini(create_testfolder):
assert isinstance(tmp, pd.DataFrame)
-@pytest.mark.tryfirst
+@pytest.mark.slow
@pytest.mark.parametrize("resample", [True, False])
def test_diversity_chao(create_testfolder, resample):
f = create_testfolder / "test.h5"
@@ -150,7 +150,7 @@ def test_diversity_chao(create_testfolder, resample):
assert isinstance(tmp, pd.DataFrame)
-@pytest.mark.tryfirst
+@pytest.mark.slow
@pytest.mark.parametrize("method,diversitykey", [
pytest.param('chao1', None),
pytest.param('chao1', 'test_diversity_key'),
@@ -170,7 +170,7 @@ def test_diversity_anndata(create_testfolder, method, diversitykey):
assert 'test_diversity_key' in adata.uns
-@pytest.mark.tryfirst
+@pytest.mark.slow
@pytest.mark.parametrize("resample,normalize", [
pytest.param(True, True),
pytest.param(False, True),
@@ -204,7 +204,7 @@ def test_diversity_shannon(create_testfolder, resample, normalize):
assert isinstance(tmp, pd.DataFrame)
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_setup2(create_testfolder, json_10x_cr6, dummy_adata_cr6):
json_file = str(create_testfolder) + "/test_all_contig_annotations.json"
with open(json_file, 'w') as outfile:
@@ -224,7 +224,7 @@ def test_setup2(create_testfolder, json_10x_cr6, dummy_adata_cr6):
adata.write_h5ad(f2)
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_diversity_rarefaction(create_testfolder):
f = create_testfolder / "test.h5ad"
adata = sc.read_h5ad(f)
@@ -238,7 +238,7 @@ def test_diversity_rarefaction(create_testfolder):
assert p is not None
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_diversity_rarefaction2(create_testfolder):
f = create_testfolder / "test.h5ad"
adata = sc.read_h5ad(f)
@@ -251,7 +251,7 @@ def test_diversity_rarefaction2(create_testfolder):
assert p is not None
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_diversity_rarefaction3(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -267,7 +267,7 @@ def test_diversity_rarefaction3(create_testfolder):
assert p is not None
-@pytest.mark.tryfirst
+@pytest.mark.slow
@pytest.mark.parametrize(
"metric", ['clone_network', None, 'clone_degree', 'clone_centrality'])
def test_diversity_gini2(create_testfolder, metric):
@@ -298,7 +298,7 @@ def test_diversity_gini2(create_testfolder, metric):
assert not vdj.metadata.clone_centrality_gini.empty
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_diversity2a(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -316,7 +316,7 @@ def test_diversity2a(create_testfolder):
assert not vdj.metadata.clone_network_vertex_size_gini.empty
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_diversity2b(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -334,7 +334,7 @@ def test_diversity2b(create_testfolder):
assert not vdj.metadata.clone_network_vertex_size_gini.empty
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_diversity2c(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -351,7 +351,7 @@ def test_diversity2c(create_testfolder):
assert isinstance(x, pd.DataFrame)
-@pytest.mark.tryfirst
+@pytest.mark.slow
def test_extract_edge_weights(create_testfolder):
f = create_testfolder / "test.h5"
vdj = ddl.read_h5(f)
@@ -361,7 +361,7 @@ def test_extract_edge_weights(create_testfolder):
assert x is None
-@pytest.mark.tryfirst
+@pytest.mark.slow
@pytest.mark.parametrize("method", [
pytest.param('chao1'),
pytest.param('shannon'),
From 892ae58dc997122285fd09da29f175025e3e1282 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Thu, 19 May 2022 08:24:56 +0100
Subject: [PATCH 29/36] Update _preprocessing.py
bug fix
---
dandelion/preprocessing/_preprocessing.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/dandelion/preprocessing/_preprocessing.py b/dandelion/preprocessing/_preprocessing.py
index 7cffa9095..802a48ee9 100644
--- a/dandelion/preprocessing/_preprocessing.py
+++ b/dandelion/preprocessing/_preprocessing.py
@@ -2,7 +2,7 @@
# @Author: kt16
# @Date: 2020-05-12 17:56:02
# @Last Modified by: Kelvin
-# @Last Modified time: 2022-05-18 17:37:10
+# @Last Modified time: 2022-05-19 08:24:22
import os
import pandas as pd
@@ -2373,6 +2373,7 @@ def calculate_threshold(self: Union[Dandelion, pd.DataFrame, str],
plot_group: Optional[str] = None,
figsize: Tuple[Union[int, float],
Union[int, float]] = (4.5, 2.5),
+ ncpu: int = 1,
**kwargs) -> Dandelion:
"""
Calculating nearest neighbor distances for tuning clonal assignment with `shazam`.
@@ -2442,6 +2443,8 @@ def calculate_threshold(self: Union[Dandelion, pd.DataFrame, str],
determines the fill color and facets.
figsize : Tuple[Union[int,float], Union[int,float]]
size of plot. Default is (4.5, 2.5).
+ ncpu : float
+ number of cpus to run `distToNearest`. defaults to 1.
**kwargs
passed to shazam's `distToNearest `__.
@@ -2518,7 +2521,7 @@ def calculate_threshold(self: Union[Dandelion, pd.DataFrame, str],
onlyHeavy=onlyHeavy,
normalize=norm_,
model=model_,
- nproc=ncpu_,
+ nproc=ncpu,
**kwargs)
except:
print(
@@ -2535,7 +2538,7 @@ def calculate_threshold(self: Union[Dandelion, pd.DataFrame, str],
vCallColumn=v_call,
model=model_,
normalize=norm_,
- nproc=ncpu_,
+ nproc=ncpu,
**kwargs)
# Find threshold using density method
dist = np.array(dist_ham['dist_nearest'])
From 8dd4d0b8f7d0892a95a7ab5fdc95a43abe25713d Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Thu, 19 May 2022 10:32:33 +0100
Subject: [PATCH 30/36] Update index.rst
---
docs/index.rst | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/docs/index.rst b/docs/index.rst
index 95a72fc6e..7c711058d 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -11,8 +11,13 @@
:maxdepth: 1
:caption: Tutorial:
+ :caption: Singularity:
+ :maxdepth: 1
notebooks/singularity_preprocessing.ipynb
notebooks/gamma_delta.ipynb
+
+ :caption: Advanced:
+ :maxdepth: 1
tutorial_short.rst
notebooks/7_dandelion_TCR_data_10x_data.ipynb
From 2bb500c8bf0711bc8f3090b29335937a37a482a7 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Thu, 19 May 2022 10:32:44 +0100
Subject: [PATCH 31/36] Update README.md
---
docs/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/README.md b/docs/README.md
index 89cd9b284..52b142b52 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -10,7 +10,7 @@
![](notebooks/img/dandelion_logo_illustration.png)
-Hi there! I have put together a python package for analyzing single cell BCR/V(D)J data from 10x Genomics 5' solution! It streamlines the pre-processing, leveraging some tools from immcantation suite, and integrates with scanpy/anndata for single-cell BCR analysis. It also includes a couple of functions for visualization.
+Hi there! I have put together a python package for analyzing single cell BCR/V(D)J data from 10x Genomics 5' solution! It streamlines the pre-processing, leveraging some tools from immcantation suite, and integrates with scanpy/anndata for single-cell BCR analysis. It also includes a couple of functions for visualization. Try it out on Google Colab above!
## Overview
From 861fe1b4eddbe195495b06a1f7065972f02d114c Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Thu, 19 May 2022 10:33:05 +0100
Subject: [PATCH 32/36] Update README.rst
---
docs/README.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/README.rst b/docs/README.rst
index 0e2e1c1bd..cb4bf7e21 100644
--- a/docs/README.rst
+++ b/docs/README.rst
@@ -6,7 +6,7 @@ Hi there! I have put together a python package for analyzing single cell
BCR/V(D)J data from 10x Genomics 5' solution! It streamlines the
pre-processing, leveraging some tools from immcantation suite, and
integrates with scanpy/anndata for single-cell BCR analysis. It also
-includes a couple of functions for visualization.
+includes a couple of functions for visualization. Try it out on Google Colab above!
Overview
--------
From 73f606b604144001ec56e258b727d03d005b07f0 Mon Sep 17 00:00:00 2001
From: Kelvin <26215587+zktuong@users.noreply.github.com>
Date: Thu, 19 May 2022 13:21:49 +0100
Subject: [PATCH 33/36] update notebooks
---
docs/notebooks/0_dandelion_primer.ipynb | 968 +++++++++---------
.../1_dandelion_preprocessing-10x_data.ipynb | 48 +-
...1b_dandelion_noreannotation-10x_data.ipynb | 8 +-
docs/notebooks/1c_dandelion_scirpy.ipynb | 16 +-
.../2_dandelion_filtering-10x_data.ipynb | 386 +++----
.../3_dandelion_findingclones-10x_data.ipynb | 218 ++--
.../4_dandelion_visualization-10x_data.ipynb | 193 ++--
...lion_diversity_and_mutation-10x_data.ipynb | 588 +++++------
.../6_dandelion_running_from_R-10x_data.ipynb | 29 +-
.../7_dandelion_TCR_data_10x_data.ipynb | 102 +-
.../notebooks/singularity_preprocessing.ipynb | 2 +-
11 files changed, 1294 insertions(+), 1264 deletions(-)
diff --git a/docs/notebooks/0_dandelion_primer.ipynb b/docs/notebooks/0_dandelion_primer.ipynb
index d543c1d75..f80c31696 100644
--- a/docs/notebooks/0_dandelion_primer.ipynb
+++ b/docs/notebooks/0_dandelion_primer.ipynb
@@ -29,7 +29,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "dandelion==0.1.12 pandas==1.2.3 numpy==1.21.0 matplotlib==3.3.4 networkx==2.6 scipy==1.7.0 skbio==0.5.6\n"
+ "dandelion==0.2.1 pandas==1.2.3 numpy==1.21.0 matplotlib==3.3.4 networkx==2.6 scipy==1.7.0\n"
]
}
],
@@ -50,13 +50,13 @@
{
"data": {
"text/plain": [
- "Dandelion class object with n_obs = 2472 and n_contigs = 4936\n",
- " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_support', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id', 'clone_id_heavy_only'\n",
- " metadata: 'clone_id', 'clone_id_by_size', 'sample_id', 'locus_VDJ', 'locus_VJ', 'productive_VDJ', 'productive_VJ', 'v_call_genotyped_VDJ', 'v_call_genotyped_VJ', 'd_call_VDJ', 'j_call_VDJ', 'j_call_VJ', 'c_call_VDJ', 'c_call_VJ', 'duplicate_count_VDJ', 'duplicate_count_VJ', 'duplicate_count_VDJ_1', 'duplicate_count_VJ_1', 'duplicate_count_VDJ_2', 'junction_aa_VDJ', 'junction_aa_VJ', 'locus_status', 'locus_status_summary', 'productive', 'productive_summary', 'isotype', 'isotype_summary', 'vdj_status', 'vdj_status_summary', 'constant_status_summary', 'changeo_clone_id', 'fwr1_VDJ', 'fwr1_VJ', 'mu_count_VDJ', 'mu_count_VJ', 'mu_count', 'junction_length_VDJ', 'junction_length_VJ', 'junction_aa_length_VDJ', 'junction_aa_length_VJ', 'np1_length_VDJ', 'np1_length_VJ', 'np2_length_VDJ'\n",
+ "Dandelion class object with n_obs = 2435 and n_contigs = 4862\n",
+ " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'j_support_igblastn', 'j_score_igblastn', 'j_call_igblastn', 'j_call_blastn', 'j_identity_blastn', 'j_alignment_length_blastn', 'j_number_of_mismatches_blastn', 'j_number_of_gap_openings_blastn', 'j_sequence_start_blastn', 'j_sequence_end_blastn', 'j_germline_start_blastn', 'j_germline_end_blastn', 'j_support_blastn', 'j_score_blastn', 'j_sequence_alignment_blastn', 'j_germline_alignment_blastn', 'cell_id_blastn', 'j_source', 'd_support_igblastn', 'd_score_igblastn', 'd_call_igblastn', 'd_call_blastn', 'd_identity_blastn', 'd_alignment_length_blastn', 'd_number_of_mismatches_blastn', 'd_number_of_gap_openings_blastn', 'd_sequence_start_blastn', 'd_sequence_end_blastn', 'd_germline_start_blastn', 'd_germline_end_blastn', 'd_support_blastn', 'd_score_blastn', 'd_sequence_alignment_blastn', 'd_germline_alignment_blastn', 'd_source', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id'\n",
+ " metadata: 'clone_id', 'clone_id_by_size', 'sample_id', 'locus_VDJ', 'locus_VJ', 'productive_VDJ', 'productive_VJ', 'v_call_genotyped_VDJ', 'v_call_genotyped_VJ', 'd_call_VDJ', 'j_call_VDJ', 'j_call_VJ', 'c_call_VDJ', 'c_call_VJ', 'duplicate_count_VDJ', 'duplicate_count_VJ', 'duplicate_count_VDJ_1', 'duplicate_count_VJ_1', 'duplicate_count_VDJ_2', 'junction_aa_VDJ', 'junction_aa_VJ', 'locus_status', 'locus_status_summary', 'productive', 'productive_summary', 'isotype', 'isotype_summary', 'vdj_status', 'vdj_status_summary', 'constant_status_summary', 'changeo_clone_id'\n",
" distance: None\n",
" edges: 'source', 'target', 'weight'\n",
- " layout: layout for 2472 vertices, layout for 1023 vertices\n",
- " graph: networkx graph of 2472 vertices, networkx graph of 1023 vertices "
+ " layout: layout for 2435 vertices, layout for 999 vertices\n",
+ " graph: networkx graph of 2435 vertices, networkx graph of 999 vertices "
]
},
"execution_count": 2,
@@ -122,23 +122,23 @@
"
v_call_genotyped_VJ | \n",
" d_call_VDJ | \n",
" ... | \n",
- " mu_count_VDJ | \n",
- " mu_count_VJ | \n",
- " mu_count | \n",
- " junction_length_VDJ | \n",
- " junction_length_VJ | \n",
- " junction_aa_length_VDJ | \n",
- " junction_aa_length_VJ | \n",
- " np1_length_VDJ | \n",
- " np1_length_VJ | \n",
- " np2_length_VDJ | \n",
+ " locus_status | \n",
+ " locus_status_summary | \n",
+ " productive | \n",
+ " productive_summary | \n",
+ " isotype | \n",
+ " isotype_summary | \n",
+ " vdj_status | \n",
+ " vdj_status_summary | \n",
+ " constant_status_summary | \n",
+ " changeo_clone_id | \n",
" \n",
" \n",
" \n",
" \n",
" sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC | \n",
- " 115_3_1_122_2_2 | \n",
- " 1548 | \n",
+ " 159_3_1_38_2_2 | \n",
+ " 1749 | \n",
" sc5p_v2_hs_PBMC_10k | \n",
" IGH | \n",
" IGK | \n",
@@ -148,21 +148,21 @@
" IGKV1-8 | \n",
" IGHD3-22 | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 63.0 | \n",
- " 33.0 | \n",
- " 21.0 | \n",
- " 11.0 | \n",
- " 4.0 | \n",
- " 0.0 | \n",
- " 5.0 | \n",
+ " IGH + IGK | \n",
+ " IGH + IGK | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Single | \n",
+ " Single | \n",
+ " Single | \n",
+ " 813_478 | \n",
"
\n",
" \n",
" sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG | \n",
- " 22_1_2_18_1_1 | \n",
- " 994 | \n",
+ " 22_1_2_41_1_1 | \n",
+ " 1451 | \n",
" sc5p_v2_hs_PBMC_10k | \n",
" IGH | \n",
" IGL | \n",
@@ -170,23 +170,23 @@
" T | \n",
" IGHV1-2 | \n",
" IGLV5-45 | \n",
- " IGHD3-16|IGHD4-17 | \n",
+ " | \n",
" ... | \n",
- " 22.0 | \n",
- " 8.0 | \n",
- " 15.0 | \n",
- " 42.0 | \n",
- " 33.0 | \n",
- " 14.0 | \n",
- " 11.0 | \n",
- " 6.0 | \n",
- " 0.0 | \n",
- " 6.0 | \n",
+ " IGH + IGL | \n",
+ " IGH + IGL | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Single | \n",
+ " Single | \n",
+ " Single | \n",
+ " 227_479 | \n",
"
\n",
" \n",
" sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC | \n",
- " 143_4_3_118_1_1 | \n",
- " 1838 | \n",
+ " 150_4_2_180_1_1 | \n",
+ " 981 | \n",
" sc5p_v2_hs_PBMC_10k | \n",
" IGH | \n",
" IGK | \n",
@@ -194,23 +194,23 @@
" T | \n",
" IGHV5-51 | \n",
" IGKV1D-8 | \n",
- " IGHD1/OR15-1b|IGHD1/OR15-1a|IGHD1-26 | \n",
+ " | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 54.0 | \n",
- " 33.0 | \n",
- " 18.0 | \n",
- " 11.0 | \n",
- " 5.0 | \n",
- " 0.0 | \n",
- " 13.0 | \n",
+ " IGH + IGK | \n",
+ " IGH + IGK | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Single | \n",
+ " Single | \n",
+ " Single | \n",
+ " 625_480 | \n",
"
\n",
" \n",
" sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA | \n",
- " 194_1_1_35_2_7 | \n",
- " 1088 | \n",
+ " 88_1_1_174_2_7 | \n",
+ " 1213 | \n",
" sc5p_v2_hs_PBMC_10k | \n",
" IGH | \n",
" IGL | \n",
@@ -220,21 +220,21 @@
" IGLV3-19 | \n",
" IGHD6-13 | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 54.0 | \n",
- " 39.0 | \n",
- " 18.0 | \n",
- " 13.0 | \n",
- " 10.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
+ " IGH + IGL | \n",
+ " IGH + IGL | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Multi_VJ_j | \n",
+ " Single | \n",
+ " Single | \n",
+ " 616_481 | \n",
"
\n",
" \n",
" sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG | \n",
- " 16_2_5_57_4_4 | \n",
- " 1355 | \n",
+ " 136_2_1_123_4_4 | \n",
+ " 1797 | \n",
" sc5p_v2_hs_PBMC_10k | \n",
" IGH | \n",
" IGL | \n",
@@ -244,16 +244,16 @@
" IGLV3-21 | \n",
" IGHD3-22 | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 51.0 | \n",
- " 39.0 | \n",
- " 17.0 | \n",
- " 13.0 | \n",
- " 5.0 | \n",
- " 0.0 | \n",
- " 7.0 | \n",
+ " IGH + IGL | \n",
+ " IGH + IGL | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Multi_VJ_j | \n",
+ " Single | \n",
+ " Single | \n",
+ " 1365_482 | \n",
"
\n",
" \n",
" ... | \n",
@@ -281,8 +281,8 @@
"
\n",
" \n",
" vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG | \n",
- " 1_2_1_124_2_7 | \n",
- " 187 | \n",
+ " 86_2_1_48_2_7 | \n",
+ " 157 | \n",
" vdj_v1_hs_pbmc3 | \n",
" IGH | \n",
" IGK | \n",
@@ -292,21 +292,21 @@
" IGKV4-1 | \n",
" IGHD5/OR15-5b|IGHD5/OR15-5a | \n",
" ... | \n",
- " 13.0 | \n",
- " 13.0 | \n",
- " 13.0 | \n",
- " 30.0 | \n",
- " 33.0 | \n",
- " 10.0 | \n",
- " 11.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 14.0 | \n",
+ " IGH + IGK | \n",
+ " IGH + IGK | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Multi_VDJ_d|Multi_VDJ_j + Single | \n",
+ " Multi | \n",
+ " Single | \n",
+ " 1905_473 | \n",
"
\n",
" \n",
" vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT | \n",
- " 176_5_2_10_1_3 | \n",
- " 204 | \n",
+ " 64_5_1_19_1_3 | \n",
+ " 443 | \n",
" vdj_v1_hs_pbmc3 | \n",
" IGH | \n",
" IGK | \n",
@@ -316,21 +316,21 @@
" IGKV2-30 | \n",
" IGHD4-17 | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 60.0 | \n",
- " 33.0 | \n",
- " 20.0 | \n",
- " 11.0 | \n",
- " 4.0 | \n",
- " 0.0 | \n",
- " 10.0 | \n",
+ " IGH + IGK | \n",
+ " IGH + IGK | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Single | \n",
+ " Single | \n",
+ " Single | \n",
+ " 412_474 | \n",
"
\n",
" \n",
" vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA | \n",
- " 128_1_1_25_4_11 | \n",
- " 81 | \n",
+ " 43_1_1_80_4_10 | \n",
+ " 192 | \n",
" vdj_v1_hs_pbmc3 | \n",
" IGH | \n",
" IGK | \n",
@@ -340,21 +340,21 @@
" IGKV1D-39|IGKV1-39 | \n",
" IGHD6-13 | \n",
" ... | \n",
- " 16.0 | \n",
- " 6.0 | \n",
- " 11.0 | \n",
- " 48.0 | \n",
- " 33.0 | \n",
- " 16.0 | \n",
- " 11.0 | \n",
- " 3.0 | \n",
- " 0.0 | \n",
- " 1.0 | \n",
+ " IGH + IGK | \n",
+ " IGH + IGK | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Multi_VJ_v | \n",
+ " Single | \n",
+ " Single | \n",
+ " 966_475 | \n",
"
\n",
" \n",
" vdj_v1_hs_pbmc3_TTTGCGCCATACCATG | \n",
- " 196_6_1_96_3_2 | \n",
- " 301 | \n",
+ " 174_6_2_81_2_2 | \n",
+ " 418 | \n",
" vdj_v1_hs_pbmc3 | \n",
" IGH | \n",
" IGL | \n",
@@ -364,21 +364,21 @@
" IGLV1-47 | \n",
" IGHD2-15 | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 66.0 | \n",
- " 39.0 | \n",
- " 22.0 | \n",
- " 13.0 | \n",
- " 5.0 | \n",
- " 0.0 | \n",
- " 3.0 | \n",
+ " IGH + IGL | \n",
+ " IGH + IGL | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Single | \n",
+ " Single | \n",
+ " Single | \n",
+ " 664_476 | \n",
"
\n",
" \n",
" vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG | \n",
- " 206_5_6_119_3_4 | \n",
- " 113 | \n",
+ " 53_5_4_178_3_2 | \n",
+ " 221 | \n",
" vdj_v1_hs_pbmc3 | \n",
" IGH | \n",
" IGL | \n",
@@ -386,37 +386,37 @@
" T | \n",
" IGHV3-23 | \n",
" IGLV2-11 | \n",
- " IGHD3-3|IGHD3-22 | \n",
+ " | \n",
" ... | \n",
- " 8.0 | \n",
- " 4.0 | \n",
- " 6.0 | \n",
- " 39.0 | \n",
- " 36.0 | \n",
- " 13.0 | \n",
- " 12.0 | \n",
- " 8.0 | \n",
- " 6.0 | \n",
- " 5.0 | \n",
+ " IGH + IGL | \n",
+ " IGH + IGL | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Multi_VJ_j | \n",
+ " Single | \n",
+ " Single | \n",
+ " 1688_477 | \n",
"
\n",
" \n",
"\n",
- "2472 rows × 43 columns
\n",
+ "2435 rows × 31 columns
\n",
""
],
"text/plain": [
" clone_id clone_id_by_size \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 115_3_1_122_2_2 1548 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 22_1_2_18_1_1 994 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 143_4_3_118_1_1 1838 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 194_1_1_35_2_7 1088 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 16_2_5_57_4_4 1355 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 159_3_1_38_2_2 1749 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 22_1_2_41_1_1 1451 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 150_4_2_180_1_1 981 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 88_1_1_174_2_7 1213 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 136_2_1_123_4_4 1797 \n",
"... ... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 1_2_1_124_2_7 187 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 176_5_2_10_1_3 204 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 128_1_1_25_4_11 81 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 196_6_1_96_3_2 301 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 206_5_6_119_3_4 113 \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 86_2_1_48_2_7 157 \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 64_5_1_19_1_3 443 \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 43_1_1_80_4_10 192 \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 174_6_2_81_2_2 418 \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 53_5_4_178_3_2 221 \n",
"\n",
" sample_id locus_VDJ locus_VJ \\\n",
"sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC sc5p_v2_hs_PBMC_10k IGH IGK \n",
@@ -457,85 +457,98 @@
"vdj_v1_hs_pbmc3_TTTGCGCCATACCATG IGHV1-69 IGLV1-47 \n",
"vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG IGHV3-23 IGLV2-11 \n",
"\n",
- " d_call_VDJ \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC IGHD3-22 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG IGHD3-16|IGHD4-17 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC IGHD1/OR15-1b|IGHD1/OR15-1a|IGHD1-26 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA IGHD6-13 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG IGHD3-22 \n",
- "... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG IGHD5/OR15-5b|IGHD5/OR15-5a \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT IGHD4-17 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA IGHD6-13 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG IGHD2-15 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG IGHD3-3|IGHD3-22 \n",
+ " d_call_VDJ ... \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC IGHD3-22 ... \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG ... \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC ... \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA IGHD6-13 ... \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG IGHD3-22 ... \n",
+ "... ... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG IGHD5/OR15-5b|IGHD5/OR15-5a ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT IGHD4-17 ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA IGHD6-13 ... \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG IGHD2-15 ... \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG ... \n",
+ "\n",
+ " locus_status locus_status_summary \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC IGH + IGK IGH + IGK \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG IGH + IGL IGH + IGL \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC IGH + IGK IGH + IGK \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA IGH + IGL IGH + IGL \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG IGH + IGL IGH + IGL \n",
+ "... ... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG IGH + IGK IGH + IGK \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT IGH + IGK IGH + IGK \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA IGH + IGK IGH + IGK \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG IGH + IGL IGH + IGL \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG IGH + IGL IGH + IGL \n",
"\n",
- " ... mu_count_VDJ mu_count_VJ mu_count \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC ... 0.0 0.0 0.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG ... 22.0 8.0 15.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC ... 0.0 0.0 0.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA ... 0.0 0.0 0.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG ... 0.0 0.0 0.0 \n",
- "... ... ... ... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG ... 13.0 13.0 13.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT ... 0.0 0.0 0.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA ... 16.0 6.0 11.0 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG ... 0.0 0.0 0.0 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG ... 8.0 4.0 6.0 \n",
+ " productive productive_summary isotype \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC T + T T + T IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG T + T T + T IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC T + T T + T IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA T + T T + T IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG T + T T + T IgM \n",
+ "... ... ... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG T + T T + T IgM \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT T + T T + T IgM \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA T + T T + T IgM \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG T + T T + T IgM \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG T + T T + T IgM \n",
"\n",
- " junction_length_VDJ junction_length_VJ \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 63.0 33.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 42.0 33.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 54.0 33.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 54.0 39.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 51.0 39.0 \n",
- "... ... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 30.0 33.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 60.0 33.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 48.0 33.0 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 66.0 39.0 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 39.0 36.0 \n",
+ " isotype_summary \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG IgM \n",
+ "... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG IgM \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT IgM \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA IgM \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG IgM \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG IgM \n",
"\n",
- " junction_aa_length_VDJ \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 21.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 14.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 18.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 18.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 17.0 \n",
- "... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 10.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 20.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 16.0 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 22.0 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 13.0 \n",
+ " vdj_status \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC Single + Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG Single + Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC Single + Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA Single + Multi_VJ_j \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG Single + Multi_VJ_j \n",
+ "... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG Multi_VDJ_d|Multi_VDJ_j + Single \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT Single + Single \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA Single + Multi_VJ_v \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG Single + Single \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG Single + Multi_VJ_j \n",
"\n",
- " junction_aa_length_VJ np1_length_VDJ \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 11.0 4.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 11.0 6.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 11.0 5.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 13.0 10.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 13.0 5.0 \n",
- "... ... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 11.0 0.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 11.0 4.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 11.0 3.0 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 13.0 5.0 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 12.0 8.0 \n",
+ " vdj_status_summary \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG Single \n",
+ "... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG Multi \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT Single \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA Single \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG Single \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG Single \n",
"\n",
- " np1_length_VJ np2_length_VDJ \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 0.0 5.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 0.0 6.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 0.0 13.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 0.0 0.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 0.0 7.0 \n",
- "... ... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 0.0 14.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 0.0 10.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 0.0 1.0 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 0.0 3.0 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 6.0 5.0 \n",
+ " constant_status_summary changeo_clone_id \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC Single 813_478 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG Single 227_479 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC Single 625_480 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA Single 616_481 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG Single 1365_482 \n",
+ "... ... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG Single 1905_473 \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT Single 412_474 \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA Single 966_475 \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG Single 664_476 \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG Single 1688_477 \n",
"\n",
- "[2472 rows x 43 columns]"
+ "[2435 rows x 31 columns]"
]
},
"execution_count": 3,
@@ -595,23 +608,23 @@
" v_call_genotyped_VJ | \n",
" d_call_VDJ | \n",
" ... | \n",
- " mu_count_VDJ | \n",
- " mu_count_VJ | \n",
- " mu_count | \n",
- " junction_length_VDJ | \n",
- " junction_length_VJ | \n",
- " junction_aa_length_VDJ | \n",
- " junction_aa_length_VJ | \n",
- " np1_length_VDJ | \n",
- " np1_length_VJ | \n",
- " np2_length_VDJ | \n",
+ " locus_status | \n",
+ " locus_status_summary | \n",
+ " productive | \n",
+ " productive_summary | \n",
+ " isotype | \n",
+ " isotype_summary | \n",
+ " vdj_status | \n",
+ " vdj_status_summary | \n",
+ " constant_status_summary | \n",
+ " changeo_clone_id | \n",
" \n",
" \n",
" \n",
" \n",
" sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC | \n",
- " 115_3_1_122_2_2 | \n",
- " 1548 | \n",
+ " 159_3_1_38_2_2 | \n",
+ " 1749 | \n",
" sc5p_v2_hs_PBMC_10k | \n",
" IGH | \n",
" IGK | \n",
@@ -621,21 +634,21 @@
" IGKV1-8 | \n",
" IGHD3-22 | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 63.0 | \n",
- " 33.0 | \n",
- " 21.0 | \n",
- " 11.0 | \n",
- " 4.0 | \n",
- " 0.0 | \n",
- " 5.0 | \n",
+ " IGH + IGK | \n",
+ " IGH + IGK | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Single | \n",
+ " Single | \n",
+ " Single | \n",
+ " 813_478 | \n",
"
\n",
" \n",
" sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG | \n",
- " 22_1_2_18_1_1 | \n",
- " 994 | \n",
+ " 22_1_2_41_1_1 | \n",
+ " 1451 | \n",
" sc5p_v2_hs_PBMC_10k | \n",
" IGH | \n",
" IGL | \n",
@@ -643,23 +656,23 @@
" T | \n",
" IGHV1-2 | \n",
" IGLV5-45 | \n",
- " IGHD3-16|IGHD4-17 | \n",
+ " | \n",
" ... | \n",
- " 22.0 | \n",
- " 8.0 | \n",
- " 15.0 | \n",
- " 42.0 | \n",
- " 33.0 | \n",
- " 14.0 | \n",
- " 11.0 | \n",
- " 6.0 | \n",
- " 0.0 | \n",
- " 6.0 | \n",
+ " IGH + IGL | \n",
+ " IGH + IGL | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Single | \n",
+ " Single | \n",
+ " Single | \n",
+ " 227_479 | \n",
"
\n",
" \n",
" sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC | \n",
- " 143_4_3_118_1_1 | \n",
- " 1838 | \n",
+ " 150_4_2_180_1_1 | \n",
+ " 981 | \n",
" sc5p_v2_hs_PBMC_10k | \n",
" IGH | \n",
" IGK | \n",
@@ -667,23 +680,23 @@
" T | \n",
" IGHV5-51 | \n",
" IGKV1D-8 | \n",
- " IGHD1/OR15-1b|IGHD1/OR15-1a|IGHD1-26 | \n",
+ " | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 54.0 | \n",
- " 33.0 | \n",
- " 18.0 | \n",
- " 11.0 | \n",
- " 5.0 | \n",
- " 0.0 | \n",
- " 13.0 | \n",
+ " IGH + IGK | \n",
+ " IGH + IGK | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Single | \n",
+ " Single | \n",
+ " Single | \n",
+ " 625_480 | \n",
"
\n",
" \n",
" sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA | \n",
- " 194_1_1_35_2_7 | \n",
- " 1088 | \n",
+ " 88_1_1_174_2_7 | \n",
+ " 1213 | \n",
" sc5p_v2_hs_PBMC_10k | \n",
" IGH | \n",
" IGL | \n",
@@ -693,21 +706,21 @@
" IGLV3-19 | \n",
" IGHD6-13 | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 54.0 | \n",
- " 39.0 | \n",
- " 18.0 | \n",
- " 13.0 | \n",
- " 10.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
+ " IGH + IGL | \n",
+ " IGH + IGL | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Multi_VJ_j | \n",
+ " Single | \n",
+ " Single | \n",
+ " 616_481 | \n",
"
\n",
" \n",
" sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG | \n",
- " 16_2_5_57_4_4 | \n",
- " 1355 | \n",
+ " 136_2_1_123_4_4 | \n",
+ " 1797 | \n",
" sc5p_v2_hs_PBMC_10k | \n",
" IGH | \n",
" IGL | \n",
@@ -717,16 +730,16 @@
" IGLV3-21 | \n",
" IGHD3-22 | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 51.0 | \n",
- " 39.0 | \n",
- " 17.0 | \n",
- " 13.0 | \n",
- " 5.0 | \n",
- " 0.0 | \n",
- " 7.0 | \n",
+ " IGH + IGL | \n",
+ " IGH + IGL | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Multi_VJ_j | \n",
+ " Single | \n",
+ " Single | \n",
+ " 1365_482 | \n",
"
\n",
" \n",
" ... | \n",
@@ -754,8 +767,8 @@
"
\n",
" \n",
" vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG | \n",
- " 1_2_1_124_2_7 | \n",
- " 187 | \n",
+ " 86_2_1_48_2_7 | \n",
+ " 157 | \n",
" vdj_v1_hs_pbmc3 | \n",
" IGH | \n",
" IGK | \n",
@@ -765,21 +778,21 @@
" IGKV4-1 | \n",
" IGHD5/OR15-5b|IGHD5/OR15-5a | \n",
" ... | \n",
- " 13.0 | \n",
- " 13.0 | \n",
- " 13.0 | \n",
- " 30.0 | \n",
- " 33.0 | \n",
- " 10.0 | \n",
- " 11.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 14.0 | \n",
+ " IGH + IGK | \n",
+ " IGH + IGK | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Multi_VDJ_d|Multi_VDJ_j + Single | \n",
+ " Multi | \n",
+ " Single | \n",
+ " 1905_473 | \n",
"
\n",
" \n",
" vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT | \n",
- " 176_5_2_10_1_3 | \n",
- " 204 | \n",
+ " 64_5_1_19_1_3 | \n",
+ " 443 | \n",
" vdj_v1_hs_pbmc3 | \n",
" IGH | \n",
" IGK | \n",
@@ -789,21 +802,21 @@
" IGKV2-30 | \n",
" IGHD4-17 | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 60.0 | \n",
- " 33.0 | \n",
- " 20.0 | \n",
- " 11.0 | \n",
- " 4.0 | \n",
- " 0.0 | \n",
- " 10.0 | \n",
+ " IGH + IGK | \n",
+ " IGH + IGK | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Single | \n",
+ " Single | \n",
+ " Single | \n",
+ " 412_474 | \n",
"
\n",
" \n",
" vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA | \n",
- " 128_1_1_25_4_11 | \n",
- " 81 | \n",
+ " 43_1_1_80_4_10 | \n",
+ " 192 | \n",
" vdj_v1_hs_pbmc3 | \n",
" IGH | \n",
" IGK | \n",
@@ -813,21 +826,21 @@
" IGKV1D-39|IGKV1-39 | \n",
" IGHD6-13 | \n",
" ... | \n",
- " 16.0 | \n",
- " 6.0 | \n",
- " 11.0 | \n",
- " 48.0 | \n",
- " 33.0 | \n",
- " 16.0 | \n",
- " 11.0 | \n",
- " 3.0 | \n",
- " 0.0 | \n",
- " 1.0 | \n",
+ " IGH + IGK | \n",
+ " IGH + IGK | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Multi_VJ_v | \n",
+ " Single | \n",
+ " Single | \n",
+ " 966_475 | \n",
"
\n",
" \n",
" vdj_v1_hs_pbmc3_TTTGCGCCATACCATG | \n",
- " 196_6_1_96_3_2 | \n",
- " 301 | \n",
+ " 174_6_2_81_2_2 | \n",
+ " 418 | \n",
" vdj_v1_hs_pbmc3 | \n",
" IGH | \n",
" IGL | \n",
@@ -837,21 +850,21 @@
" IGLV1-47 | \n",
" IGHD2-15 | \n",
" ... | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 66.0 | \n",
- " 39.0 | \n",
- " 22.0 | \n",
- " 13.0 | \n",
- " 5.0 | \n",
- " 0.0 | \n",
- " 3.0 | \n",
+ " IGH + IGL | \n",
+ " IGH + IGL | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Single | \n",
+ " Single | \n",
+ " Single | \n",
+ " 664_476 | \n",
"
\n",
" \n",
" vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG | \n",
- " 206_5_6_119_3_4 | \n",
- " 113 | \n",
+ " 53_5_4_178_3_2 | \n",
+ " 221 | \n",
" vdj_v1_hs_pbmc3 | \n",
" IGH | \n",
" IGL | \n",
@@ -859,37 +872,37 @@
" T | \n",
" IGHV3-23 | \n",
" IGLV2-11 | \n",
- " IGHD3-3|IGHD3-22 | \n",
+ " | \n",
" ... | \n",
- " 8.0 | \n",
- " 4.0 | \n",
- " 6.0 | \n",
- " 39.0 | \n",
- " 36.0 | \n",
- " 13.0 | \n",
- " 12.0 | \n",
- " 8.0 | \n",
- " 6.0 | \n",
- " 5.0 | \n",
+ " IGH + IGL | \n",
+ " IGH + IGL | \n",
+ " T + T | \n",
+ " T + T | \n",
+ " IgM | \n",
+ " IgM | \n",
+ " Single + Multi_VJ_j | \n",
+ " Single | \n",
+ " Single | \n",
+ " 1688_477 | \n",
"
\n",
" \n",
"\n",
- "2472 rows × 43 columns
\n",
+ "2435 rows × 31 columns
\n",
""
],
"text/plain": [
" clone_id clone_id_by_size \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 115_3_1_122_2_2 1548 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 22_1_2_18_1_1 994 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 143_4_3_118_1_1 1838 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 194_1_1_35_2_7 1088 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 16_2_5_57_4_4 1355 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 159_3_1_38_2_2 1749 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 22_1_2_41_1_1 1451 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 150_4_2_180_1_1 981 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 88_1_1_174_2_7 1213 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 136_2_1_123_4_4 1797 \n",
"... ... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 1_2_1_124_2_7 187 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 176_5_2_10_1_3 204 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 128_1_1_25_4_11 81 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 196_6_1_96_3_2 301 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 206_5_6_119_3_4 113 \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 86_2_1_48_2_7 157 \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 64_5_1_19_1_3 443 \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 43_1_1_80_4_10 192 \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 174_6_2_81_2_2 418 \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 53_5_4_178_3_2 221 \n",
"\n",
" sample_id locus_VDJ locus_VJ \\\n",
"sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC sc5p_v2_hs_PBMC_10k IGH IGK \n",
@@ -930,85 +943,98 @@
"vdj_v1_hs_pbmc3_TTTGCGCCATACCATG IGHV1-69 IGLV1-47 \n",
"vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG IGHV3-23 IGLV2-11 \n",
"\n",
- " d_call_VDJ \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC IGHD3-22 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG IGHD3-16|IGHD4-17 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC IGHD1/OR15-1b|IGHD1/OR15-1a|IGHD1-26 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA IGHD6-13 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG IGHD3-22 \n",
- "... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG IGHD5/OR15-5b|IGHD5/OR15-5a \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT IGHD4-17 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA IGHD6-13 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG IGHD2-15 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG IGHD3-3|IGHD3-22 \n",
+ " d_call_VDJ ... \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC IGHD3-22 ... \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG ... \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC ... \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA IGHD6-13 ... \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG IGHD3-22 ... \n",
+ "... ... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG IGHD5/OR15-5b|IGHD5/OR15-5a ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT IGHD4-17 ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA IGHD6-13 ... \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG IGHD2-15 ... \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG ... \n",
"\n",
- " ... mu_count_VDJ mu_count_VJ mu_count \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC ... 0.0 0.0 0.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG ... 22.0 8.0 15.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC ... 0.0 0.0 0.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA ... 0.0 0.0 0.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG ... 0.0 0.0 0.0 \n",
- "... ... ... ... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG ... 13.0 13.0 13.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT ... 0.0 0.0 0.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA ... 16.0 6.0 11.0 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG ... 0.0 0.0 0.0 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG ... 8.0 4.0 6.0 \n",
+ " locus_status locus_status_summary \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC IGH + IGK IGH + IGK \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG IGH + IGL IGH + IGL \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC IGH + IGK IGH + IGK \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA IGH + IGL IGH + IGL \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG IGH + IGL IGH + IGL \n",
+ "... ... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG IGH + IGK IGH + IGK \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT IGH + IGK IGH + IGK \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA IGH + IGK IGH + IGK \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG IGH + IGL IGH + IGL \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG IGH + IGL IGH + IGL \n",
"\n",
- " junction_length_VDJ junction_length_VJ \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 63.0 33.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 42.0 33.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 54.0 33.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 54.0 39.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 51.0 39.0 \n",
- "... ... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 30.0 33.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 60.0 33.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 48.0 33.0 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 66.0 39.0 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 39.0 36.0 \n",
+ " productive productive_summary isotype \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC T + T T + T IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG T + T T + T IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC T + T T + T IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA T + T T + T IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG T + T T + T IgM \n",
+ "... ... ... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG T + T T + T IgM \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT T + T T + T IgM \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA T + T T + T IgM \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG T + T T + T IgM \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG T + T T + T IgM \n",
"\n",
- " junction_aa_length_VDJ \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 21.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 14.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 18.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 18.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 17.0 \n",
- "... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 10.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 20.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 16.0 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 22.0 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 13.0 \n",
+ " isotype_summary \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA IgM \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG IgM \n",
+ "... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG IgM \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT IgM \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA IgM \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG IgM \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG IgM \n",
"\n",
- " junction_aa_length_VJ np1_length_VDJ \\\n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 11.0 4.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 11.0 6.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 11.0 5.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 13.0 10.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 13.0 5.0 \n",
- "... ... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 11.0 0.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 11.0 4.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 11.0 3.0 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 13.0 5.0 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 12.0 8.0 \n",
+ " vdj_status \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC Single + Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG Single + Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC Single + Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA Single + Multi_VJ_j \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG Single + Multi_VJ_j \n",
+ "... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG Multi_VDJ_d|Multi_VDJ_j + Single \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT Single + Single \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA Single + Multi_VJ_v \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG Single + Single \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG Single + Multi_VJ_j \n",
"\n",
- " np1_length_VJ np2_length_VDJ \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC 0.0 5.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG 0.0 6.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC 0.0 13.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA 0.0 0.0 \n",
- "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG 0.0 7.0 \n",
- "... ... ... \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG 0.0 14.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT 0.0 10.0 \n",
- "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA 0.0 1.0 \n",
- "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG 0.0 3.0 \n",
- "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG 6.0 5.0 \n",
+ " vdj_status_summary \\\n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA Single \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG Single \n",
+ "... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG Multi \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT Single \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA Single \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG Single \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG Single \n",
"\n",
- "[2472 rows x 43 columns]"
+ " constant_status_summary changeo_clone_id \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCCGTTGTC Single 813_478 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCGAGAACG Single 227_479 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACCTGTCTTGAGAC Single 625_480 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGAGCGACGTA Single 616_481 \n",
+ "sc5p_v2_hs_PBMC_10k_AAACGGGCACTGTTAG Single 1365_482 \n",
+ "... ... ... \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCAATATG Single 1905_473 \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGCGCTTAT Single 412_474 \n",
+ "vdj_v1_hs_pbmc3_TTTCCTCAGGGAAACA Single 966_475 \n",
+ "vdj_v1_hs_pbmc3_TTTGCGCCATACCATG Single 664_476 \n",
+ "vdj_v1_hs_pbmc3_TTTGGTTGTAGGCATG Single 1688_477 \n",
+ "\n",
+ "[2435 rows x 31 columns]"
]
},
"execution_count": 4,
@@ -1072,13 +1098,13 @@
{
"data": {
"text/plain": [
- "Dandelion class object with n_obs = 2472 and n_contigs = 4936\n",
- " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_support', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id', 'clone_id_heavy_only'\n",
- " metadata: 'clone_id', 'clone_id_by_size', 'sample_id', 'locus_VDJ', 'locus_VJ', 'productive_VDJ', 'productive_VJ', 'v_call_genotyped_VDJ', 'v_call_genotyped_VJ', 'd_call_VDJ', 'j_call_VDJ', 'j_call_VJ', 'c_call_VDJ', 'c_call_VJ', 'duplicate_count_VDJ', 'duplicate_count_VJ', 'duplicate_count_VDJ_1', 'duplicate_count_VJ_1', 'duplicate_count_VDJ_2', 'junction_aa_VDJ', 'junction_aa_VJ', 'locus_status', 'locus_status_summary', 'productive', 'productive_summary', 'isotype', 'isotype_summary', 'vdj_status', 'vdj_status_summary', 'constant_status_summary', 'changeo_clone_id', 'fwr1_VDJ', 'fwr1_VJ', 'mu_count_VDJ', 'mu_count_VJ', 'mu_count', 'junction_length_VDJ', 'junction_length_VJ', 'junction_aa_length_VDJ', 'junction_aa_length_VJ', 'np1_length_VDJ', 'np1_length_VJ', 'np2_length_VDJ'\n",
+ "Dandelion class object with n_obs = 2435 and n_contigs = 4862\n",
+ " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'j_support_igblastn', 'j_score_igblastn', 'j_call_igblastn', 'j_call_blastn', 'j_identity_blastn', 'j_alignment_length_blastn', 'j_number_of_mismatches_blastn', 'j_number_of_gap_openings_blastn', 'j_sequence_start_blastn', 'j_sequence_end_blastn', 'j_germline_start_blastn', 'j_germline_end_blastn', 'j_support_blastn', 'j_score_blastn', 'j_sequence_alignment_blastn', 'j_germline_alignment_blastn', 'cell_id_blastn', 'j_source', 'd_support_igblastn', 'd_score_igblastn', 'd_call_igblastn', 'd_call_blastn', 'd_identity_blastn', 'd_alignment_length_blastn', 'd_number_of_mismatches_blastn', 'd_number_of_gap_openings_blastn', 'd_sequence_start_blastn', 'd_sequence_end_blastn', 'd_germline_start_blastn', 'd_germline_end_blastn', 'd_support_blastn', 'd_score_blastn', 'd_sequence_alignment_blastn', 'd_germline_alignment_blastn', 'd_source', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id'\n",
+ " metadata: 'clone_id', 'clone_id_by_size', 'sample_id', 'locus_VDJ', 'locus_VJ', 'productive_VDJ', 'productive_VJ', 'v_call_genotyped_VDJ', 'v_call_genotyped_VJ', 'd_call_VDJ', 'j_call_VDJ', 'j_call_VJ', 'c_call_VDJ', 'c_call_VJ', 'duplicate_count_VDJ', 'duplicate_count_VJ', 'duplicate_count_VDJ_1', 'duplicate_count_VJ_1', 'duplicate_count_VDJ_2', 'junction_aa_VDJ', 'junction_aa_VJ', 'locus_status', 'locus_status_summary', 'productive', 'productive_summary', 'isotype', 'isotype_summary', 'vdj_status', 'vdj_status_summary', 'constant_status_summary', 'changeo_clone_id', 'fwr1_VDJ', 'fwr1_VJ'\n",
" distance: None\n",
" edges: 'source', 'target', 'weight'\n",
- " layout: layout for 2472 vertices, layout for 1023 vertices\n",
- " graph: networkx graph of 2472 vertices, networkx graph of 1023 vertices "
+ " layout: layout for 2435 vertices, layout for 999 vertices\n",
+ " graph: networkx graph of 2435 vertices, networkx graph of 999 vertices "
]
},
"execution_count": 5,
@@ -1128,13 +1154,13 @@
{
"data": {
"text/plain": [
- "Dandelion class object with n_obs = 2472 and n_contigs = 4936\n",
- " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_support', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id', 'clone_id_heavy_only'\n",
+ "Dandelion class object with n_obs = 2435 and n_contigs = 4862\n",
+ " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'j_support_igblastn', 'j_score_igblastn', 'j_call_igblastn', 'j_call_blastn', 'j_identity_blastn', 'j_alignment_length_blastn', 'j_number_of_mismatches_blastn', 'j_number_of_gap_openings_blastn', 'j_sequence_start_blastn', 'j_sequence_end_blastn', 'j_germline_start_blastn', 'j_germline_end_blastn', 'j_support_blastn', 'j_score_blastn', 'j_sequence_alignment_blastn', 'j_germline_alignment_blastn', 'cell_id_blastn', 'j_source', 'd_support_igblastn', 'd_score_igblastn', 'd_call_igblastn', 'd_call_blastn', 'd_identity_blastn', 'd_alignment_length_blastn', 'd_number_of_mismatches_blastn', 'd_number_of_gap_openings_blastn', 'd_sequence_start_blastn', 'd_sequence_end_blastn', 'd_germline_start_blastn', 'd_germline_end_blastn', 'd_support_blastn', 'd_score_blastn', 'd_sequence_alignment_blastn', 'd_germline_alignment_blastn', 'd_source', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id'\n",
" metadata: 'clone_id', 'clone_id_by_size', 'sample_id', 'locus_VDJ', 'locus_VJ', 'productive_VDJ', 'productive_VJ', 'v_call_genotyped_VDJ', 'v_call_genotyped_VJ', 'd_call_VDJ', 'j_call_VDJ', 'j_call_VJ', 'c_call_VDJ', 'c_call_VJ', 'duplicate_count_VDJ', 'duplicate_count_VJ', 'duplicate_count_VDJ_1', 'duplicate_count_VJ_1', 'duplicate_count_VDJ_2', 'junction_aa_VDJ', 'junction_aa_VJ', 'locus_status', 'locus_status_summary', 'productive', 'productive_summary', 'isotype', 'isotype_summary', 'vdj_status', 'vdj_status_summary', 'constant_status_summary', 'changeo_clone_id', 'fwr1_VDJ', 'fwr1_VJ', 'mu_count_VDJ', 'mu_count_VJ', 'mu_count', 'junction_length_VDJ', 'junction_length_VJ', 'junction_aa_length_VDJ', 'junction_aa_length_VJ', 'np1_length_VDJ', 'np1_length_VJ', 'np2_length_VDJ'\n",
" distance: None\n",
" edges: 'source', 'target', 'weight'\n",
- " layout: layout for 2472 vertices, layout for 1023 vertices\n",
- " graph: networkx graph of 2472 vertices, networkx graph of 1023 vertices "
+ " layout: layout for 2435 vertices, layout for 999 vertices\n",
+ " graph: networkx graph of 2435 vertices, networkx graph of 999 vertices "
]
},
"execution_count": 6,
@@ -1166,13 +1192,13 @@
{
"data": {
"text/plain": [
- "Dandelion class object with n_obs = 2472 and n_contigs = 4936\n",
- " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_support', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id', 'clone_id_heavy_only'\n",
+ "Dandelion class object with n_obs = 2435 and n_contigs = 4862\n",
+ " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'j_support_igblastn', 'j_score_igblastn', 'j_call_igblastn', 'j_call_blastn', 'j_identity_blastn', 'j_alignment_length_blastn', 'j_number_of_mismatches_blastn', 'j_number_of_gap_openings_blastn', 'j_sequence_start_blastn', 'j_sequence_end_blastn', 'j_germline_start_blastn', 'j_germline_end_blastn', 'j_support_blastn', 'j_score_blastn', 'j_sequence_alignment_blastn', 'j_germline_alignment_blastn', 'cell_id_blastn', 'j_source', 'd_support_igblastn', 'd_score_igblastn', 'd_call_igblastn', 'd_call_blastn', 'd_identity_blastn', 'd_alignment_length_blastn', 'd_number_of_mismatches_blastn', 'd_number_of_gap_openings_blastn', 'd_sequence_start_blastn', 'd_sequence_end_blastn', 'd_germline_start_blastn', 'd_germline_end_blastn', 'd_support_blastn', 'd_score_blastn', 'd_sequence_alignment_blastn', 'd_germline_alignment_blastn', 'd_source', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id'\n",
" metadata: 'clone_id', 'clone_id_by_size', 'sample_id', 'locus_VDJ', 'locus_VJ', 'productive_VDJ', 'productive_VJ', 'v_call_genotyped_VDJ', 'v_call_genotyped_VJ', 'd_call_VDJ', 'j_call_VDJ', 'j_call_VJ', 'c_call_VDJ', 'c_call_VJ', 'duplicate_count_VDJ', 'duplicate_count_VJ', 'duplicate_count_VDJ_1', 'duplicate_count_VJ_1', 'duplicate_count_VDJ_2', 'junction_aa_VDJ', 'junction_aa_VJ', 'locus_status', 'locus_status_summary', 'productive', 'productive_summary', 'isotype', 'isotype_summary', 'vdj_status', 'vdj_status_summary', 'constant_status_summary', 'changeo_clone_id', 'fwr1_VDJ', 'fwr1_VJ', 'mu_count_VDJ', 'mu_count_VJ', 'mu_count', 'junction_length_VDJ', 'junction_length_VJ', 'junction_aa_length_VDJ', 'junction_aa_length_VJ', 'np1_length_VDJ', 'np1_length_VJ', 'np2_length_VDJ'\n",
" distance: None\n",
" edges: 'source', 'target', 'weight'\n",
- " layout: layout for 2472 vertices, layout for 1023 vertices\n",
- " graph: networkx graph of 2472 vertices, networkx graph of 1023 vertices "
+ " layout: layout for 2435 vertices, layout for 999 vertices\n",
+ " graph: networkx graph of 2435 vertices, networkx graph of 999 vertices "
]
},
"execution_count": 7,
@@ -1193,8 +1219,8 @@
{
"data": {
"text/plain": [
- "Dandelion class object with n_obs = 2472 and n_contigs = 14808\n",
- " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_support', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id', 'clone_id_heavy_only'\n",
+ "Dandelion class object with n_obs = 2435 and n_contigs = 14586\n",
+ " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'j_support_igblastn', 'j_score_igblastn', 'j_call_igblastn', 'j_call_blastn', 'j_identity_blastn', 'j_alignment_length_blastn', 'j_number_of_mismatches_blastn', 'j_number_of_gap_openings_blastn', 'j_sequence_start_blastn', 'j_sequence_end_blastn', 'j_germline_start_blastn', 'j_germline_end_blastn', 'j_support_blastn', 'j_score_blastn', 'j_sequence_alignment_blastn', 'j_germline_alignment_blastn', 'cell_id_blastn', 'j_source', 'd_support_igblastn', 'd_score_igblastn', 'd_call_igblastn', 'd_call_blastn', 'd_identity_blastn', 'd_alignment_length_blastn', 'd_number_of_mismatches_blastn', 'd_number_of_gap_openings_blastn', 'd_sequence_start_blastn', 'd_sequence_end_blastn', 'd_germline_start_blastn', 'd_germline_end_blastn', 'd_support_blastn', 'd_score_blastn', 'd_sequence_alignment_blastn', 'd_germline_alignment_blastn', 'd_source', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id'\n",
" metadata: 'clone_id', 'clone_id_by_size', 'sample_id', 'locus_VDJ', 'locus_VJ', 'productive_VDJ', 'productive_VJ', 'v_call_genotyped_VDJ', 'v_call_genotyped_VJ', 'd_call_VDJ', 'j_call_VDJ', 'j_call_VJ', 'c_call_VDJ', 'c_call_VJ', 'duplicate_count_VDJ', 'duplicate_count_VJ', 'duplicate_count_VDJ_1', 'duplicate_count_VDJ_2', 'duplicate_count_VDJ_3', 'duplicate_count_VJ_1', 'duplicate_count_VJ_2', 'duplicate_count_VJ_3', 'duplicate_count_VDJ_4', 'duplicate_count_VDJ_5', 'duplicate_count_VDJ_6', 'junction_aa_VDJ', 'junction_aa_VJ', 'locus_status', 'locus_status_summary', 'productive', 'productive_summary', 'isotype', 'isotype_summary', 'vdj_status', 'vdj_status_summary', 'constant_status_summary'\n",
" distance: None\n",
" edges: None\n",
@@ -1231,8 +1257,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "CPU times: user 5.81 s, sys: 196 ms, total: 6.01 s\n",
- "Wall time: 6.19 s\n"
+ "CPU times: user 10.8 s, sys: 294 ms, total: 11.1 s\n",
+ "Wall time: 22 s\n"
]
}
],
@@ -1256,20 +1282,20 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "CPU times: user 9.66 s, sys: 334 ms, total: 9.99 s\n",
- "Wall time: 12.1 s\n"
+ "CPU times: user 14.7 s, sys: 302 ms, total: 15 s\n",
+ "Wall time: 24.9 s\n"
]
},
{
"data": {
"text/plain": [
- "Dandelion class object with n_obs = 2472 and n_contigs = 4936\n",
- " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_support', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id', 'clone_id_heavy_only'\n",
+ "Dandelion class object with n_obs = 2435 and n_contigs = 4862\n",
+ " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'j_support_igblastn', 'j_score_igblastn', 'j_call_igblastn', 'j_call_blastn', 'j_identity_blastn', 'j_alignment_length_blastn', 'j_number_of_mismatches_blastn', 'j_number_of_gap_openings_blastn', 'j_sequence_start_blastn', 'j_sequence_end_blastn', 'j_germline_start_blastn', 'j_germline_end_blastn', 'j_support_blastn', 'j_score_blastn', 'j_sequence_alignment_blastn', 'j_germline_alignment_blastn', 'cell_id_blastn', 'j_source', 'd_support_igblastn', 'd_score_igblastn', 'd_call_igblastn', 'd_call_blastn', 'd_identity_blastn', 'd_alignment_length_blastn', 'd_number_of_mismatches_blastn', 'd_number_of_gap_openings_blastn', 'd_sequence_start_blastn', 'd_sequence_end_blastn', 'd_germline_start_blastn', 'd_germline_end_blastn', 'd_support_blastn', 'd_score_blastn', 'd_sequence_alignment_blastn', 'd_germline_alignment_blastn', 'd_source', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id'\n",
" metadata: 'clone_id', 'clone_id_by_size', 'sample_id', 'locus_VDJ', 'locus_VJ', 'productive_VDJ', 'productive_VJ', 'v_call_genotyped_VDJ', 'v_call_genotyped_VJ', 'd_call_VDJ', 'j_call_VDJ', 'j_call_VJ', 'c_call_VDJ', 'c_call_VJ', 'duplicate_count_VDJ', 'duplicate_count_VJ', 'duplicate_count_VDJ_1', 'duplicate_count_VJ_1', 'duplicate_count_VDJ_2', 'junction_aa_VDJ', 'junction_aa_VJ', 'locus_status', 'locus_status_summary', 'productive', 'productive_summary', 'isotype', 'isotype_summary', 'vdj_status', 'vdj_status_summary', 'constant_status_summary', 'changeo_clone_id', 'fwr1_VDJ', 'fwr1_VJ', 'mu_count_VDJ', 'mu_count_VJ', 'mu_count', 'junction_length_VDJ', 'junction_length_VJ', 'junction_aa_length_VDJ', 'junction_aa_length_VJ', 'np1_length_VDJ', 'np1_length_VJ', 'np2_length_VDJ'\n",
" distance: None\n",
" edges: 'source', 'target', 'weight'\n",
- " layout: layout for 2472 vertices, layout for 1023 vertices\n",
- " graph: networkx graph of 2472 vertices, networkx graph of 1023 vertices "
+ " layout: layout for 2435 vertices, layout for 999 vertices\n",
+ " graph: networkx graph of 2435 vertices, networkx graph of 999 vertices "
]
},
"execution_count": 10,
@@ -1298,8 +1324,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "CPU times: user 5.98 s, sys: 104 ms, total: 6.09 s\n",
- "Wall time: 8.15 s\n"
+ "CPU times: user 6.55 s, sys: 53.3 ms, total: 6.6 s\n",
+ "Wall time: 9.2 s\n"
]
}
],
@@ -1316,20 +1342,20 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "CPU times: user 699 ms, sys: 58.4 ms, total: 757 ms\n",
- "Wall time: 1.17 s\n"
+ "CPU times: user 835 ms, sys: 87 ms, total: 922 ms\n",
+ "Wall time: 1.27 s\n"
]
},
{
"data": {
"text/plain": [
- "Dandelion class object with n_obs = 2472 and n_contigs = 4936\n",
- " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_support', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id', 'clone_id_heavy_only'\n",
+ "Dandelion class object with n_obs = 2435 and n_contigs = 4862\n",
+ " data: 'sequence_id', 'sequence', 'rev_comp', 'productive', 'v_call', 'd_call', 'j_call', 'sequence_alignment', 'germline_alignment', 'junction', 'junction_aa', 'v_cigar', 'd_cigar', 'j_cigar', 'stop_codon', 'vj_in_frame', 'locus', 'junction_length', 'np1_length', 'np2_length', 'v_sequence_start', 'v_sequence_end', 'v_germline_start', 'v_germline_end', 'd_sequence_start', 'd_sequence_end', 'd_germline_start', 'd_germline_end', 'j_sequence_start', 'j_sequence_end', 'j_germline_start', 'j_germline_end', 'v_score', 'v_identity', 'v_support', 'd_score', 'd_identity', 'd_support', 'j_score', 'j_identity', 'j_support', 'fwr1', 'fwr2', 'fwr3', 'fwr4', 'cdr1', 'cdr2', 'cdr3', 'cell_id', 'c_call', 'consensus_count', 'umi_count', 'v_call_10x', 'd_call_10x', 'j_call_10x', 'junction_10x', 'junction_10x_aa', 'v_call_genotyped', 'germline_alignment_d_mask', 'sample_id', 'j_support_igblastn', 'j_score_igblastn', 'j_call_igblastn', 'j_call_blastn', 'j_identity_blastn', 'j_alignment_length_blastn', 'j_number_of_mismatches_blastn', 'j_number_of_gap_openings_blastn', 'j_sequence_start_blastn', 'j_sequence_end_blastn', 'j_germline_start_blastn', 'j_germline_end_blastn', 'j_support_blastn', 'j_score_blastn', 'j_sequence_alignment_blastn', 'j_germline_alignment_blastn', 'cell_id_blastn', 'j_source', 'd_support_igblastn', 'd_score_igblastn', 'd_call_igblastn', 'd_call_blastn', 'd_identity_blastn', 'd_alignment_length_blastn', 'd_number_of_mismatches_blastn', 'd_number_of_gap_openings_blastn', 'd_sequence_start_blastn', 'd_sequence_end_blastn', 'd_germline_start_blastn', 'd_germline_end_blastn', 'd_support_blastn', 'd_score_blastn', 'd_sequence_alignment_blastn', 'd_germline_alignment_blastn', 'd_source', 'c_sequence_alignment', 'c_germline_alignment', 'c_sequence_start', 'c_sequence_end', 'c_score', 'c_identity', 'c_call_10x', 'junction_aa_length', 'fwr1_aa', 'fwr2_aa', 'fwr3_aa', 'fwr4_aa', 'cdr1_aa', 'cdr2_aa', 'cdr3_aa', 'sequence_alignment_aa', 'v_sequence_alignment_aa', 'd_sequence_alignment_aa', 'j_sequence_alignment_aa', 'mu_count', 'duplicate_count', 'clone_id', 'changeo_clone_id'\n",
" metadata: 'clone_id', 'clone_id_by_size', 'sample_id', 'locus_VDJ', 'locus_VJ', 'productive_VDJ', 'productive_VJ', 'v_call_genotyped_VDJ', 'v_call_genotyped_VJ', 'd_call_VDJ', 'j_call_VDJ', 'j_call_VJ', 'c_call_VDJ', 'c_call_VJ', 'duplicate_count_VDJ', 'duplicate_count_VJ', 'duplicate_count_VDJ_1', 'duplicate_count_VJ_1', 'duplicate_count_VDJ_2', 'junction_aa_VDJ', 'junction_aa_VJ', 'locus_status', 'locus_status_summary', 'productive', 'productive_summary', 'isotype', 'isotype_summary', 'vdj_status', 'vdj_status_summary', 'constant_status_summary', 'changeo_clone_id', 'fwr1_VDJ', 'fwr1_VJ', 'mu_count_VDJ', 'mu_count_VJ', 'mu_count', 'junction_length_VDJ', 'junction_length_VJ', 'junction_aa_length_VDJ', 'junction_aa_length_VJ', 'np1_length_VDJ', 'np1_length_VJ', 'np2_length_VDJ'\n",
" distance: None\n",
" edges: 'source', 'target', 'weight'\n",
- " layout: layout for 2472 vertices, layout for 1023 vertices\n",
- " graph: networkx graph of 2472 vertices, networkx graph of 1023 vertices "
+ " layout: layout for 2435 vertices, layout for 999 vertices\n",
+ " graph: networkx graph of 2435 vertices, networkx graph of 999 vertices "
]
},
"execution_count": 12,
diff --git a/docs/notebooks/1_dandelion_preprocessing-10x_data.ipynb b/docs/notebooks/1_dandelion_preprocessing-10x_data.ipynb
index fae19e2d6..5a5e4b6a8 100644
--- a/docs/notebooks/1_dandelion_preprocessing-10x_data.ipynb
+++ b/docs/notebooks/1_dandelion_preprocessing-10x_data.ipynb
@@ -11,7 +11,7 @@
"\n",
"## Foreword\n",
"\n",
- "***dandelion*** is written in `python=3.7.6` and is primarily a single-cell BCR-seq analysis package. It makes use of some tools from the fantastic [*immcantation suite*](https://immcantation.readthedocs.io/) [[Gupta2015]](https://academic.oup.com/bioinformatics/article/31/20/3356/195677), implementing a workflow to streamline the pre-processing and exploratory stages for analyzing single-cell BCR-seq data from 10X Genomics. Post-processed data from ***dandelion*** can be smoothly transferred to [*scanpy*](https://scanpy.readthedocs.io/)/[*AnnData*](https://anndata.readthedocs.io/) [[Wolf18]](https://doi.org/10.1186/s13059-017-1382-0) object for integration and exploration of BCR-seq data and RNA-seq data. I hope to be able to introduce some new single-cell BCR-seq exploratory tools down the road through *dandelion*. \n",
+ "***dandelion*** is written in `python=3.7` (also compatible with `3.8`, `3.9` and `3.10`) and is primarily a single-cell BCR-seq analysis package. It makes use of some tools from the fantastic [*immcantation suite*](https://immcantation.readthedocs.io/) [[Gupta2015]](https://academic.oup.com/bioinformatics/article/31/20/3356/195677), implementing a workflow to streamline the pre-processing and exploratory stages for analyzing single-cell BCR-seq data from 10X Genomics. Post-processed data from ***dandelion*** can be smoothly transferred to [*scanpy*](https://scanpy.readthedocs.io/)/[*AnnData*](https://anndata.readthedocs.io/) [[Wolf18]](https://doi.org/10.1186/s13059-017-1382-0) object for integration and exploration of BCR-seq data and RNA-seq data. I hope to be able to introduce some new single-cell BCR-seq exploratory tools down the road through *dandelion*. \n",
"\n",
"This section will cover the initial pre-processing of files after 10X's `Cell Ranger vdj` immune profiling data analysis pipeline **manually**. As mentioned, there is now a [singularity container](https://sc-dandelion.readthedocs.io/en/latest/notebooks/singularity_preprocessing.html) that can automate the first few steps outlined below.\n",
"\n",
@@ -46,7 +46,7 @@
"wget -O filtered_contig.fasta https://cf.10xgenomics.com/samples/cell-vdj/4.0.0/sc5p_v2_hs_PBMC_1k/sc5p_v2_hs_PBMC_1k_b_filtered_contig.fasta;\n",
"```\n",
"\n",
- "***dandelion***'s reannotation workflow requires the Cell Ranger fasta files and annotation files to start, particularly either *all_contig.fasta* or *filtered_contig.fasta* and corresponding *all_contig_annotations.csv* and *filtered_contig_annotations.csv*.\n",
+ "***dandelion***'s reannotation workflow requires the Cellranger fasta files and annotation files to start, particularly either *all_contig.fasta* or *filtered_contig.fasta* and corresponding *all_contig_annotations.csv* and *filtered_contig_annotations.csv*.\n",
"\n",
"I'm running everything with the *filtered_contig* files as a standard analysis set up. I'm using a standard laptop for the analysis here: entry level 2017 Macbook Pro with 2.3 GHz Intel Core i5 processor and 16 GB 2133 MHz LPDDR3 ram.\n",
"\n",
@@ -63,18 +63,18 @@
"```\n",
"The databases for igblast are basically setup using [changeo's instructions](https://changeo.readthedocs.io/en/stable/examples/igblast.html). \n",
"\n",
- "If you are using a jupyter notebook initialized via jupyterhub instance, you might want to try the fix to a known issue where pathing requires some adjustments https://github.com/zktuong/dandelion/issues/66.\n",
+ "If you are using a jupyter notebook initialized via jupyterhub instance, you might want to try the fix to a known issue where pathing requires some adjustments https://github.com/zktuong/dandelion/discussions/146.\n",
"\n",
"For reannotation of constant genes, reference fasta files were downloaded from IMGT and only sequences corresponding to *CH1* region for each constant gene/allele were retained. The headers were trimmed to only keep the gene and allele information. Links to find the sequences can be found here : [***human***](http://www.imgt.org/genedb/GENElect?query=7.2+IGHC&species=Homo+sapiens) and [***mouse***](http://www.imgt.org/genedb/GENElect?query=7.2+IGHC&species=Mus).\n",
"\n",
- "The utility function `utl.makeblastdb` is a wrapper for:\n",
+ "The utility function `ddl.utl.makeblastdb` is a wrapper for:\n",
"\n",
"```bash\n",
"# bash/shell\n",
"makeblastdb -dbtype nucl -parse_seqids -in $BLASTDB/human/human_BCR_C.fasta\n",
"```\n",
"\n",
- "So effectively, this does the same thing:\n",
+ "This does the same thing:\n",
"```python\n",
"# python\n",
"ddl.utl.makeblastdb('/Users/kt16/Documents/Github/dandelion/database/blast/human/human_BCR_C.fasta')\n",
@@ -95,7 +95,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "dandelion==0.1.13.dev124 pandas==1.2.3 numpy==1.21.0 matplotlib==3.3.4 networkx==2.6 scipy==1.7.0 skbio==0.5.6\n"
+ "dandelion==0.2.1 pandas==1.2.3 numpy==1.21.0 matplotlib==3.3.4 networkx==2.6 scipy==1.7.0\n"
]
}
],
@@ -186,7 +186,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "Formating fasta(s) : 100%|██████████| 4/4 [00:02<00:00, 1.47it/s]\n"
+ "Formating fasta(s) : 100%|██████████| 4/4 [00:02<00:00, 1.84it/s]\n"
]
}
],
@@ -230,7 +230,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "Assigning genes : 100%|██████████| 4/4 [06:24<00:00, 96.02s/it]\n"
+ "Assigning genes : 100%|██████████| 4/4 [07:52<00:00, 118.06s/it]\n"
]
}
],
@@ -276,7 +276,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "Processing data file(s) : 100%|██████████| 2/2 [00:02<00:00, 1.18s/it]\n"
+ "Processing data file(s) : 100%|██████████| 2/2 [00:03<00:00, 1.75s/it]\n"
]
},
{
@@ -287,10 +287,6 @@
" Running tigger-genotype with novel allele discovery.\n",
" Reassigning alleles\n",
" Reconstructing heavy chain dmask germline sequences with v_call_genotyped.\n",
- " Novel allele discovery execution halted.\n",
- " Attempting to run tigger-genotype without novel allele discovery.\n",
- " Reassigning alleles\n",
- " Reconstructing heavy chain dmask germline sequences with v_call_genotyped.\n",
" Reconstructing light chain dmaskgermline sequences with v_call.\n",
" For convenience, entries for light chain `v_call` are copied to `v_call_genotyped`.\n",
"Returning summary plot\n"
@@ -318,14 +314,14 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "\n"
+ "\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
- "Writing out to individual folders : 100%|██████████| 2/2 [00:00<00:00, 6.68it/s]\n"
+ "Writing out to individual folders : 100%|██████████| 2/2 [00:02<00:00, 1.43s/it]\n"
]
}
],
@@ -370,7 +366,7 @@
},
{
"data": {
- "image/png": "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\n",
+ "image/png": "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zZs3AXy4l/D69etITU1Famoqjh49irt37yotgQKAlZUVXFxc4OLiAkdHxzzHQUREVFgkcwUNAOrVq4dp06ahTZs2YsLQt29fLFiwAD169ICZmRkaNGiAw4cP52u/Xbt2xY4dOzB69GjExcXB0NAQderUQfXq1TFnzhx4e3ujQoUKAID+/fvjjz/+wPz582FgYID27dtj3LhxSEtLw4gRI+Di4oI2bdpg8uTJSE9PR5s2baCrqysu17Vo0QIymQy//vorYmNjoaurix9++AG1a9fO1zHlJCkpCatWrUJUVBTkcjl++OEHtGvX7rPn1ahRA//++y8WL14MU1NTjBkzBvr6+uLxBg0aYOnSpYiIiEDZsmUxbNgwleJTV1fHhAkTsGLFCvFqpZOTE5ycnJCWloY1a9bg2bNnUFNTg42NDUaNGpXjE6hERETfGpnw8R3s36AePXogICAAVapUKexQspSQkICff/4Zq1evVulqklRs3rwZkZGRGDFiRGGHopIrV67A1dUVly9fhouLi9Lx+LnKV+BystB5Zn6FRhI0pkHTfGnnc/NuenDOn76RX3EQ0bdHMkucqnj9+jXevHmT7b1jheX8+fNITU1FUlISVq5cifLly3/TyRkRERF9XZJa4syLW7duYerUqfD29oalpSUCAwNx+/ZtpXr169dHv379vmpsx48fx/z58yGTyVC+fHkMHz483/t4+fIlBgwYkOWxKVOmiEuyeTFgwIAsH8Lo0KFDntsiIiIi1X2zCVqlSpWwZcsW8XVgYGDhBfOJjz8RoaCYmZlh+/bt+dpmYX6uKREREf3PN73ESURERPQ9YoJGREREJDFM0IiIiIgkhgkaERERkcQwQSMiIiKSGCZoRERERBLDBI2IiIhIYpigEREREUkMEzQiIiIiiWGCRkRERCQxTNCIiIiIJIYJGhEREZHEMEEjIiIikhgmaEREREQSwwSNiIiISGKYoBERERFJDBM0IiIiIolhgkZEREQkMUzQiIiIiCSGCRoRERGRxDBBIyIiIpIYJmhEREREEsMEjYiIiEhimKARERERSQwTNCIiIiKJYYJGREREJDFM0IiIiIgkhgkaERERkcQwQSMiIiKSGCZoRERERBLDBI2IiIhIYpigEREREUkMEzQiIiIiiWGCRkRERCQxTNCIiIiIJIYJGhEREZHEMEEjIiIikhgm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\n",
"text/plain": [
"