Skip to content

Commit df4b54b

Browse files
committed
Add a TCR-specific seurat filter
1 parent 78d59f9 commit df4b54b

File tree

5 files changed

+95
-2
lines changed

5 files changed

+95
-2
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
totalPassed <- 0
2+
for (datasetId in names(seuratObjects)) {
3+
printName(datasetId)
4+
seuratObj <- readRDS(seuratObjects[[datasetId]])
5+
6+
cellsToKeep <- NULL
7+
for (locus in c('A', 'B', 'D', 'G')) {
8+
fieldName <- paste0('TR', locus)
9+
10+
cdr3ForLocus <- cdr3s[grepl(cdr3s, pattern = paste0(fieldName, ':'))]
11+
if (length(cdr3ForLocus) == 0) {
12+
next
13+
}
14+
15+
cdr3ForLocus <- gsub(cdr3ForLocus, pattern = paste0(fieldName, ':'), replacement = '')
16+
matchingCells <- sapply(seuratObj@meta.data[[fieldName]], function(x){
17+
values <- unlist(strsplit(x, split = ','))
18+
return(length(intersect(values, cdr3ForLocus)) > 0)
19+
})
20+
21+
if (sum(matchingCells) == 0) {
22+
next
23+
}
24+
25+
matchingCells <- colnames(seuratObj)[matchingCells]
26+
if (all(is.null(cellsToKeep))) {
27+
cellsToKeep <- matchingCells
28+
} else {
29+
cellsToKeep <- unique(c(cellsToKeep, matchingCells))
30+
}
31+
}
32+
33+
if (all(is.null(cellsToKeep))) {
34+
print('There were no matching cells')
35+
} else {
36+
seuratObj <- subset(seuratObj, cells = cellsToKeep)
37+
saveData(seuratObj, datasetId)
38+
totalPassed <- totalPassed + 1
39+
}
40+
41+
# Cleanup
42+
rm(seuratObj)
43+
gc()
44+
}
45+
46+
if (totalPassed == 0) {
47+
addErrorMessage('No cells remained in any seurat objects after subsetting')
48+
}

singlecell/resources/web/singlecell/panel/NimbleAlignPanel.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Ext4.define('SingleCell.panel.NimbleAlignPanel', {
5252
const store = this.up('singlecell-nimblealignpanel').genomeField.store
5353
if (val && store) {
5454
const recIdx = store.find('rowid', val);
55-
return store.getAt(recIdx).get('name');
55+
return recIdx === -1 ? '[' + val + ']' : store.getAt(recIdx).get('name');
5656
}
5757
else if (val) {
5858
return '[' + val + ']';

singlecell/resources/web/singlecell/panel/NimbleAppendPanel.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Ext4.define('SingleCell.panel.NimbleAppendPanel', {
5151
const store = this.up('singlecell-nimbleappendpanel').genomeField.store
5252
if (val && store) {
5353
const recIdx = store.find('rowid', val);
54-
return store.getAt(recIdx).get('name');
54+
return recIdx === -1 ? '[' + val + ']' : store.getAt(recIdx).get('name');
5555
}
5656
else if (val) {
5757
return '[' + val + ']';

singlecell/src/org/labkey/singlecell/SingleCellModule.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ public static void registerPipelineSteps()
190190
SequencePipelineService.get().registerPipelineStep(new RunVision.Provider());
191191
SequencePipelineService.get().registerPipelineStep(new NimbleAppend.Provider());
192192
SequencePipelineService.get().registerPipelineStep(new AppendTcr.Provider());
193+
SequencePipelineService.get().registerPipelineStep(new TcrFilter.Provider());
193194

194195
SequenceAnalysisService.get().registerFileHandler(new NimbleHandler());
195196
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.labkey.singlecell.pipeline.singlecell;
2+
3+
import org.json.JSONObject;
4+
import org.labkey.api.sequenceanalysis.pipeline.AbstractPipelineStepProvider;
5+
import org.labkey.api.sequenceanalysis.pipeline.PipelineContext;
6+
import org.labkey.api.singlecell.pipeline.SeuratToolParameter;
7+
import org.labkey.api.singlecell.pipeline.SingleCellStep;
8+
9+
import java.util.Arrays;
10+
11+
public class TcrFilter extends AbstractCellMembraneStep
12+
{
13+
public TcrFilter(PipelineContext ctx, TcrFilter.Provider provider)
14+
{
15+
super(provider, ctx);
16+
}
17+
18+
public static class Provider extends AbstractPipelineStepProvider<SingleCellStep>
19+
{
20+
public Provider()
21+
{
22+
super("TcrFilter", "TCR-Based Filter", "CellMembrane/Seurat", "This will run standard Seurat processing steps to normalize and scale the data.", Arrays.asList(
23+
SeuratToolParameter.create("cdr3s", "CDR3s To Keep", "A list of CDR3 sequences where locus prefixes the AA sequence (i.e. TRB:XXXXXX or TRA:YYYYYYY). These should not contain commas. Any cell matching any of these CDR3s will be kept. If that cell has multiple chains for a locus (i.e. 'CASSXXXXX,CASSYYYYY'), then only one of these needs to match for that cell to be kept.", "sequenceanalysis-trimmingtextarea", new JSONObject(){{
24+
put("height", 150);
25+
put("delimiter", ",");
26+
}}, null).delimiter(",")
27+
), Arrays.asList("/sequenceanalysis/field/TrimmingTextArea.js"), null);
28+
}
29+
30+
@Override
31+
public TcrFilter create(PipelineContext ctx)
32+
{
33+
return new TcrFilter(ctx, this);
34+
}
35+
}
36+
37+
@Override
38+
public String getFileSuffix()
39+
{
40+
return "tcrFilter";
41+
}
42+
}
43+
44+

0 commit comments

Comments
 (0)