mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-08 12:18:12 +08:00
Add back in /expression and /diffexp endpoints
This commit is contained in:
@@ -210,10 +210,230 @@ class CellsAPI(Resource):
|
|||||||
return make_payload(payload)
|
return make_payload(payload)
|
||||||
|
|
||||||
|
|
||||||
|
class ExpressionAPI(Resource):
|
||||||
|
@swagger.doc({
|
||||||
|
'summary': 'Json with gene list and expression data by cell, limited to first 40 cells',
|
||||||
|
'tags': ['expression'],
|
||||||
|
'parameters': [
|
||||||
|
{
|
||||||
|
'name': 'include_unexpressed_genes',
|
||||||
|
'description': "Include genes that have 0 expression across all cells in set",
|
||||||
|
'in': 'path',
|
||||||
|
'type': 'bool',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'responses': {
|
||||||
|
'200': {
|
||||||
|
'description': 'Json for heatmap',
|
||||||
|
'examples': {
|
||||||
|
'application/json': {
|
||||||
|
"data": {
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cellname": "1/2-SBSRNA4",
|
||||||
|
"e": [0, 0, 214, 0, 0]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"genes": [
|
||||||
|
"1001000173.G8",
|
||||||
|
"1001000173.D4",
|
||||||
|
"1001000173.B4",
|
||||||
|
"1001000173.A2",
|
||||||
|
"1001000173.E2"
|
||||||
|
],
|
||||||
|
"nonzero_gene_count": 2857
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"error": False,
|
||||||
|
"errormessage": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
def get(self):
|
||||||
|
from app import data
|
||||||
|
expression_data = data.expression()
|
||||||
|
return make_payload(expression_data)
|
||||||
|
|
||||||
|
@swagger.doc({
|
||||||
|
'summary': 'Json with gene list and expression data by cell',
|
||||||
|
'tags': ['expression'],
|
||||||
|
'parameters': [
|
||||||
|
{
|
||||||
|
'name': 'body',
|
||||||
|
'in': 'body',
|
||||||
|
"schema": {
|
||||||
|
"example": {
|
||||||
|
"celllist": ["1001000173.G8", "1001000173.D4"],
|
||||||
|
"genelist": ["1/2-SBSRNA4", "A1BG", "A1BG-AS1", "A1CF", "A2LD1", "A2M", "A2ML1", "A2MP1",
|
||||||
|
"A4GALT"],
|
||||||
|
"include_unexpressed_genes": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'responses': {
|
||||||
|
'200': {
|
||||||
|
'description': 'Json for expressiondata',
|
||||||
|
'examples': {
|
||||||
|
'application/json': {
|
||||||
|
"data": {
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cellname": "1001000173.D4",
|
||||||
|
"e": [0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cellname": "1001000173.G8",
|
||||||
|
"e": [0, 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"genes": [
|
||||||
|
"ABCD4",
|
||||||
|
"ZWINT"
|
||||||
|
],
|
||||||
|
"nonzero_gene_count": 2857
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"error": False,
|
||||||
|
"errormessage": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'400': {
|
||||||
|
'description': 'Required parameter missing/incorrect',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
def post(self):
|
||||||
|
from app import data
|
||||||
|
args = request.get_json()
|
||||||
|
cell_list = args.get('celllist', [])
|
||||||
|
gene_list = args.get('genelist', [])
|
||||||
|
if not (cell_list) and not (gene_list):
|
||||||
|
return make_payload([], "must include celllist and/or genelist parameter", 400)
|
||||||
|
|
||||||
|
expression_data = data.expression(cell_list, gene_list)
|
||||||
|
|
||||||
|
if cell_list and len(expression_data['cells']) < len(cell_list):
|
||||||
|
return make_payload([], "Some cell ids not available", 400)
|
||||||
|
if gene_list and len(expression_data['genes']) < len(gene_list):
|
||||||
|
return make_payload([], "Some genes not available", 400)
|
||||||
|
|
||||||
|
return make_payload(expression_data)
|
||||||
|
|
||||||
|
class DifferentialExpressionAPI(Resource):
|
||||||
|
@swagger.doc({
|
||||||
|
'summary': 'Get the top expressed genes for two cell sets. Calculated using t-test',
|
||||||
|
'tags': ['expression'],
|
||||||
|
'parameters': [
|
||||||
|
{
|
||||||
|
'name': 'body',
|
||||||
|
'in': 'body',
|
||||||
|
'schema': {
|
||||||
|
"example": {
|
||||||
|
"celllist1": ["1001000176.C12", "1001000176.C7", "1001000177.F11"],
|
||||||
|
"celllist2": ["1001000012.D2", "1001000017.F10", "1001000033.C3", "1001000229.D4"],
|
||||||
|
"num_genes": 5,
|
||||||
|
"pval": 0.000001,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
'200': {
|
||||||
|
'description': 'top expressed genes for cellset1, cellset2',
|
||||||
|
'examples': {
|
||||||
|
'application/json': {
|
||||||
|
"data": {
|
||||||
|
"celllist1": {
|
||||||
|
"ave_diff": [
|
||||||
|
432.0132935431362,
|
||||||
|
12470.5623982637,
|
||||||
|
957.0246880086814
|
||||||
|
],
|
||||||
|
"mean_expression_cellset1": [
|
||||||
|
438.6185567010309,
|
||||||
|
13315.536082474227,
|
||||||
|
1076.5773195876288
|
||||||
|
],
|
||||||
|
"mean_expression_cellset2": [
|
||||||
|
6.605263157894737,
|
||||||
|
844.9736842105264,
|
||||||
|
119.55263157894737
|
||||||
|
],
|
||||||
|
"pval": [
|
||||||
|
3.8906598089944563e-35,
|
||||||
|
1.9086226376018916e-25,
|
||||||
|
7.847480544069826e-21
|
||||||
|
],
|
||||||
|
"topgenes": [
|
||||||
|
"TMSB10",
|
||||||
|
"FTL",
|
||||||
|
"TMSB4X"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"celllist2": {
|
||||||
|
"ave_diff": [
|
||||||
|
-6860.599158979924,
|
||||||
|
-519.1314432989691,
|
||||||
|
-10278.328269126423
|
||||||
|
],
|
||||||
|
"mean_expression_cellset1": [
|
||||||
|
2.8350515463917527,
|
||||||
|
0.6185567010309279,
|
||||||
|
23.09278350515464
|
||||||
|
],
|
||||||
|
"mean_expression_cellset2": [
|
||||||
|
6863.434210526316,
|
||||||
|
519.75,
|
||||||
|
10301.421052631578
|
||||||
|
],
|
||||||
|
"pval": [
|
||||||
|
4.662891833748732e-44,
|
||||||
|
3.6278087029927103e-37,
|
||||||
|
8.396825170618402e-35
|
||||||
|
],
|
||||||
|
"topgenes": [
|
||||||
|
"SPARCL1",
|
||||||
|
"C1orf61",
|
||||||
|
"CLU"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"error": False,
|
||||||
|
"errormessage": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
def post(self):
|
||||||
|
from app import data
|
||||||
|
args = request.get_json()
|
||||||
|
cell_list_1 = args.get('celllist1', [])
|
||||||
|
cell_list_2 = args.get('celllist2', [])
|
||||||
|
num_genes = args.get("num_genes", 7)
|
||||||
|
pval = args.get('pval', 0.5)
|
||||||
|
if not (cell_list_1 and cell_list_2):
|
||||||
|
return make_payload([],
|
||||||
|
"must include celllist1 and celllist2 parameters",
|
||||||
|
400)
|
||||||
|
data = data.diffexp(cell_list_1, cell_list_2, pval, num_genes)
|
||||||
|
return make_payload(data)
|
||||||
|
|
||||||
def get_api_resources():
|
def get_api_resources():
|
||||||
bp = Blueprint('api', __name__, url_prefix='/api/v2.0')
|
bp = Blueprint('api', __name__, url_prefix='/api/v2.0')
|
||||||
api = Api(bp, add_api_spec_resource=False)
|
api = Api(bp, add_api_spec_resource=False)
|
||||||
api.add_resource(InitializeAPI, "/initialize")
|
api.add_resource(InitializeAPI, "/initialize")
|
||||||
api.add_resource(CellsAPI, "/cells")
|
api.add_resource(CellsAPI, "/cells")
|
||||||
|
api.add_resource(ExpressionAPI, "/expression")
|
||||||
|
api.add_resource(DifferentialExpressionAPI, "/diffexp")
|
||||||
return api
|
return api
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import scanpy.api as sc
|
import scanpy.api as sc
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from scipy import stats
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ..util.schema_parse import parse_schema
|
from ..util.schema_parse import parse_schema
|
||||||
@@ -112,11 +113,80 @@ class ScanpyEngine(CXGDriver):
|
|||||||
return np.hstack((df.obs["cell_name"].values.reshape(len(df.obs.index), 1), normalized_graph)).tolist()
|
return np.hstack((df.obs["cell_name"].values.reshape(len(df.obs.index), 1), normalized_graph)).tolist()
|
||||||
|
|
||||||
|
|
||||||
def diffexp(self, cells_iterator_1, cells_iterator_2):
|
def diffexp(self, cell_list_1, cell_list_2, pval, num_genes):
|
||||||
pass
|
cells_idx_1 = np.in1d(self.data.obs["cell_name"], cell_list_1)
|
||||||
|
cells_idx_2 = np.in1d(self.data.obs["cell_name"], cell_list_2)
|
||||||
|
expression_1 = self.data.X[cells_idx_1,:]
|
||||||
|
expression_2 = self.data.X[cells_idx_2,:]
|
||||||
|
diff_exp = stats.ttest_ind(expression_1, expression_2)
|
||||||
|
set1 = np.logical_and(diff_exp.pvalue < pval, diff_exp.statistic > 0)
|
||||||
|
set2 = np.logical_and(diff_exp.pvalue < pval, diff_exp.statistic < 0)
|
||||||
|
stat1 = diff_exp.statistic[set1]
|
||||||
|
stat2 = diff_exp.statistic[set2]
|
||||||
|
sort_set1 = np.argsort(stat1)[::-1]
|
||||||
|
sort_set2 = np.argsort(stat2)
|
||||||
|
pval1 = diff_exp.pvalue[set1][sort_set1]
|
||||||
|
pval2 = diff_exp.pvalue[set2][sort_set2]
|
||||||
|
mean_ex1_set1 = np.mean(expression_1[:, set1], axis=0)[sort_set1]
|
||||||
|
mean_ex2_set1 = np.mean(expression_2[:, set1], axis=0)[sort_set1]
|
||||||
|
mean_ex1_set2 = np.mean(expression_1[:, set2], axis=0)[sort_set2]
|
||||||
|
mean_ex2_set2 = np.mean(expression_2[:, set2], axis=0)[sort_set2]
|
||||||
|
mean_diff1 = mean_ex1_set1 - mean_ex2_set1
|
||||||
|
mean_diff2 = mean_ex1_set2 - mean_ex2_set2
|
||||||
|
genes_cellset_1 = self.data.var_names[set1][sort_set1]
|
||||||
|
genes_cellset_2 = self.data.var_names[set2][sort_set2]
|
||||||
|
return {
|
||||||
|
"celllist1": {
|
||||||
|
"topgenes": genes_cellset_1.tolist()[:num_genes],
|
||||||
|
"mean_expression_cellset1": mean_ex1_set1.tolist()[:num_genes],
|
||||||
|
"mean_expression_cellset2": mean_ex2_set1.tolist()[:num_genes],
|
||||||
|
"pval": pval1.tolist()[:num_genes],
|
||||||
|
"ave_diff": mean_diff1.tolist()[:num_genes]
|
||||||
|
},
|
||||||
|
"celllist2": {
|
||||||
|
"topgenes": genes_cellset_2.tolist()[:num_genes],
|
||||||
|
"mean_expression_cellset1": mean_ex1_set2.tolist()[:num_genes],
|
||||||
|
"mean_expression_cellset2": mean_ex2_set2.tolist()[:num_genes],
|
||||||
|
"pval": pval2.tolist()[:num_genes],
|
||||||
|
"ave_diff": mean_diff2.tolist()[:num_genes]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def expression(self, cells=None, genes=None):
|
||||||
|
"""
|
||||||
|
:param df:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if cells:
|
||||||
|
cells_idx = np.in1d(self.data.obs["cell_name"], cells)
|
||||||
|
else:
|
||||||
|
cells_idx = np.ones((self.cell_count,), dtype=bool)
|
||||||
|
if genes:
|
||||||
|
genes_idx = np.in1d(self.data.var_names, genes)
|
||||||
|
else:
|
||||||
|
genes_idx = np.ones((self.gene_count,), dtype=bool)
|
||||||
|
index = np.ix_(cells_idx, genes_idx)
|
||||||
|
expression = self.data.X[index]
|
||||||
|
|
||||||
|
if not genes:
|
||||||
|
genes = self.data.var.index.tolist()
|
||||||
|
if not cells:
|
||||||
|
cells = self.data.obs["cell_name"].tolist()
|
||||||
|
|
||||||
|
cell_data = []
|
||||||
|
for idx, cell in enumerate(cells):
|
||||||
|
cell_data.append({
|
||||||
|
"cellname": cell,
|
||||||
|
"e": list(expression[idx]),
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
"genes": genes,
|
||||||
|
"cells": cell_data,
|
||||||
|
"nonzero_gene_count": int(np.sum(expression.any(axis=0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def expression(self, ):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user