Skip to content

Commit 8c7dea6

Browse files
committed
Add action to update description field on existing seurat prototypes
1 parent 78a9da3 commit 8c7dea6

File tree

3 files changed

+109
-11
lines changed

3 files changed

+109
-11
lines changed

singlecell/src/org/labkey/singlecell/SingleCellController.java

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
import org.apache.commons.lang3.StringUtils;
2222
import org.apache.logging.log4j.LogManager;
2323
import org.apache.logging.log4j.Logger;
24+
import org.jetbrains.annotations.NotNull;
2425
import org.json.JSONArray;
26+
import org.json.JSONObject;
2527
import org.labkey.api.action.ApiResponse;
2628
import org.labkey.api.action.ApiSimpleResponse;
2729
import org.labkey.api.action.ApiUsageException;
30+
import org.labkey.api.action.ConfirmAction;
2831
import org.labkey.api.action.ExportAction;
2932
import org.labkey.api.action.MutatingApiAction;
3033
import org.labkey.api.action.ReadOnlyApiAction;
@@ -45,6 +48,7 @@
4548
import org.labkey.api.module.Module;
4649
import org.labkey.api.module.ModuleHtmlView;
4750
import org.labkey.api.module.ModuleLoader;
51+
import org.labkey.api.pipeline.PipelineJobException;
4852
import org.labkey.api.query.BatchValidationException;
4953
import org.labkey.api.query.FieldKey;
5054
import org.labkey.api.query.QueryService;
@@ -58,14 +62,18 @@
5862
import org.labkey.api.sequenceanalysis.pipeline.PipelineStepProvider;
5963
import org.labkey.api.sequenceanalysis.pipeline.SequencePipelineService;
6064
import org.labkey.api.util.FileUtil;
65+
import org.labkey.api.util.HtmlString;
6166
import org.labkey.api.util.JsonUtil;
6267
import org.labkey.api.util.PageFlowUtil;
6368
import org.labkey.api.util.Path;
6469
import org.labkey.api.util.URLHelper;
70+
import org.labkey.api.view.HtmlView;
6571
import org.labkey.api.view.NavTree;
6672
import org.labkey.api.view.template.ClientDependency;
73+
import org.labkey.singlecell.analysis.AbstractSingleCellHandler;
6774
import org.labkey.singlecell.run.CellRangerWrapper;
6875
import org.springframework.validation.BindException;
76+
import org.springframework.validation.Errors;
6977
import org.springframework.web.servlet.ModelAndView;
7078

7179
import java.io.File;
@@ -558,4 +566,94 @@ public void setCombineHashingCite(boolean combineHashingCite)
558566
_combineHashingCite = combineHashingCite;
559567
}
560568
}
569+
570+
@RequiresPermission(AdminPermission.class)
571+
public static class UpdatePrototypeDescriptionsAction extends ConfirmAction<Object>
572+
{
573+
@Override
574+
public void validateCommand(Object form, Errors errors)
575+
{
576+
577+
}
578+
579+
@Override
580+
public @NotNull URLHelper getSuccessURL(Object form)
581+
{
582+
return getContainer().getStartURL(getUser());
583+
}
584+
585+
@Override
586+
public ModelAndView getConfirmView(Object form, BindException errors) throws Exception
587+
{
588+
return new HtmlView(HtmlString.unsafe("This will update the description field for all seurat prototypes. Do you want to continue?"));
589+
}
590+
591+
@Override
592+
public boolean handlePost(Object form, BindException errors) throws Exception
593+
{
594+
UserSchema sa = QueryService.get().getUserSchema(getUser(), getContainer(), SingleCellSchema.SEQUENCE_SCHEMA_NAME);
595+
new TableSelector(sa.getTable("outputfiles"), PageFlowUtil.set("rowid"), new SimpleFilter(FieldKey.fromString("category"), "Seurat Object Prototype"), null).forEach(Integer.class, rowId -> {
596+
SequenceOutputFile so = SequenceOutputFile.getForId(rowId);
597+
if (so == null)
598+
{
599+
throw new IllegalStateException("Unable to create SequenceOutputFile for: " + rowId);
600+
}
601+
602+
try
603+
{
604+
JSONObject params = new JSONObject();
605+
606+
String oldDescription = so.getDescription();
607+
if (oldDescription.contains("SoupX: true"))
608+
{
609+
params.put("singleCellRawData.PrepareRawCounts.useSoupX", true);
610+
}
611+
612+
if (oldDescription.contains("Hashing: "))
613+
{
614+
List<String> matching = Arrays.stream(oldDescription.split("\n")).filter(x -> x.contains("Hashing: ")).toList();
615+
if (!matching.isEmpty())
616+
{
617+
if (matching.size() == 1)
618+
{
619+
params.put("singleCell.RunCellHashing.consensusMethods", matching.get(0).replaceFirst("Hashing: ", ""));
620+
}
621+
else
622+
{
623+
_log.error("Expected single match for Hashing on rowId: "+ rowId);
624+
}
625+
}
626+
}
627+
628+
if (oldDescription.contains("Cite-seq Normalization: "))
629+
{
630+
List<String> matching = Arrays.stream(oldDescription.split("\n")).filter(x -> x.contains("Cite-seq Normalization: ")).toList();
631+
if (!matching.isEmpty())
632+
{
633+
if (matching.size() == 1)
634+
{
635+
params.put("singleCell.AppendCiteSeq.normalizeMethod", matching.get(0).replaceFirst("Cite-seq Normalization: ", ""));
636+
}
637+
else
638+
{
639+
_log.error("Expected single match for Cite-seq Normalization on rowId: "+ rowId);
640+
}
641+
}
642+
}
643+
644+
String description = AbstractSingleCellHandler.getOutputDescription(params, _log, so.getFile(), null);
645+
so.setDescription(description);
646+
647+
_log.info(rowId);
648+
_log.info(description);
649+
}
650+
catch (PipelineJobException e)
651+
{
652+
_log.error("Error generating description for: " + rowId, e);
653+
}
654+
});
655+
656+
return true;
657+
}
658+
}
561659
}

singlecell/src/org/labkey/singlecell/analysis/AbstractSingleCellHandler.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ else if (step.createsSeuratObjects())
616616
so.setName(output.getDatasetName() == null ? output.getDatasetId() : output.getDatasetName());
617617
so.setCategory("Seurat Object");
618618
so.setFile(output.getFile());
619-
String description = getOutputDescription(ctx, output.getFile(), List.of("Steps: " + steps.stream().map(x -> x.getProvider().getName()).collect(Collectors.joining("; "))));
619+
String description = getOutputDescription(ctx.getParams(), ctx.getLogger(), output.getFile(), List.of("Steps: " + steps.stream().map(x -> x.getProvider().getName()).collect(Collectors.joining("; "))));
620620
if (jobDescription != null)
621621
{
622622
description = jobDescription + "\n" + description;
@@ -986,7 +986,7 @@ public void serializeTest() throws Exception
986986
}
987987
}
988988

989-
public static String getOutputDescription(JobContext ctx, File seuratObj, @Nullable List<String> descriptions) throws PipelineJobException
989+
public static String getOutputDescription(JSONObject jsonParams, Logger log, File seuratObj, @Nullable List<String> descriptions) throws PipelineJobException
990990
{
991991
if (descriptions == null)
992992
{
@@ -1034,7 +1034,7 @@ public static String getOutputDescription(JobContext ctx, File seuratObj, @Nulla
10341034
hashingIdx = Arrays.asList(line).indexOf("HTO.Classification");
10351035
if (hashingIdx == -1)
10361036
{
1037-
ctx.getLogger().debug("HTO.Classification field not present, skipping");
1037+
log.debug("HTO.Classification field not present, skipping");
10381038
hashingUsed = false;
10391039
hashingIdx = -2;
10401040
}
@@ -1088,7 +1088,7 @@ else if ("NotUsed".equals(val))
10881088
if (traIdx >= 0)
10891089
{
10901090
String tra = StringUtils.trimToNull(line[traIdx]);
1091-
if (tra != null)
1091+
if (tra != null && !"NA".equals(tra))
10921092
{
10931093
cellsWithTRA++;
10941094
}
@@ -1097,7 +1097,7 @@ else if ("NotUsed".equals(val))
10971097
if (trbIdx >= 0)
10981098
{
10991099
String trb = StringUtils.trimToNull(line[trbIdx]);
1100-
if (trb != null)
1100+
if (trb != null && !"NA".equals(trb))
11011101
{
11021102
cellsWithTRB++;
11031103
}
@@ -1106,7 +1106,7 @@ else if ("NotUsed".equals(val))
11061106
if (trdIdx >= 0)
11071107
{
11081108
String trd = StringUtils.trimToNull(line[trdIdx]);
1109-
if (trd != null)
1109+
if (trd != null && !"NA".equals(trd))
11101110
{
11111111
cellsWithTRD++;
11121112
}
@@ -1115,7 +1115,7 @@ else if ("NotUsed".equals(val))
11151115
if (trgIdx >= 0)
11161116
{
11171117
String trg = StringUtils.trimToNull(line[trgIdx]);
1118-
if (trg != null)
1118+
if (trg != null && !"NA".equals(trg))
11191119
{
11201120
cellsWithTRG++;
11211121
}
@@ -1169,18 +1169,18 @@ else if (riraIdx == -1 || traIdx == -1)
11691169
}
11701170
}
11711171

1172-
if (ctx.getParams().optBoolean("singleCellRawData.PrepareRawCounts.useSoupX", false))
1172+
if (jsonParams.optBoolean("singleCellRawData.PrepareRawCounts.useSoupX", false))
11731173
{
11741174
descriptions.add("SoupX: true");
11751175
}
11761176

1177-
String hashingMethods = ctx.getParams().optString("singleCell.RunCellHashing.consensusMethods");
1177+
String hashingMethods = jsonParams.optString("singleCell.RunCellHashing.consensusMethods");
11781178
if (StringUtils.trimToNull(hashingMethods) != null)
11791179
{
11801180
descriptions.add("Hashing: " + hashingMethods);
11811181
}
11821182

1183-
String citeNormalize = ctx.getParams().optString("singleCell.AppendCiteSeq.normalizeMethod");
1183+
String citeNormalize = jsonParams.optString("singleCell.AppendCiteSeq.normalizeMethod");
11841184
if (StringUtils.trimToNull(citeNormalize) != null)
11851185
{
11861186
descriptions.add("Cite-seq Normalization: " + citeNormalize);

singlecell/src/org/labkey/singlecell/pipeline/singlecell/SeuratPrototype.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public Output execute(SequenceOutputHandler.JobContext ctx, List<SeuratObjectWra
145145
String readsetName = ctx.getSequenceSupport().getCachedReadset(wrapper.getReadsetId()).getName();
146146
so.setReadset(wrapper.getReadsetId());
147147
so.setName(readsetName + ": Prototype Seurat Object");
148-
so.setDescription(AbstractSingleCellHandler.getOutputDescription(ctx, so.getFile(), null));
148+
so.setDescription(AbstractSingleCellHandler.getOutputDescription(ctx.getParams(), ctx.getLogger(), so.getFile(), null));
149149

150150
ctx.getFileManager().addSequenceOutput(so);
151151
}

0 commit comments

Comments
 (0)