diff --git a/src/org/labkey/targetedms/TargetedMSController.java b/src/org/labkey/targetedms/TargetedMSController.java index 68e6cfd87..e9931da2d 100644 --- a/src/org/labkey/targetedms/TargetedMSController.java +++ b/src/org/labkey/targetedms/TargetedMSController.java @@ -249,6 +249,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; @@ -2384,6 +2385,8 @@ public static class ChromatogramForm extends AbstractChartForm private boolean _update; private Long _chromInfoId; private Long _highlightChromInfoId; + private long _replicateId; + private String _peptideForm; public ChromatogramForm() { @@ -2400,6 +2403,15 @@ public void setId(long id) _id = id; } + public long getReplicateId() + { + return _replicateId; + } + + public void setReplicateId(long replicateId) + { + _replicateId = replicateId; + } public String getReplicatesFilter() { @@ -2586,6 +2598,16 @@ public void setChromInfoId(Long chromInfoId) { _chromInfoId = chromInfoId; } + + public String getPeptideForm() + { + return _peptideForm; + } + + public void setPeptideForm(String peptideForm) + { + _peptideForm = Objects.requireNonNullElse(peptideForm, PeptideCharacteristic.COMBINED_PEPTIDE); + } } @@ -4746,7 +4768,8 @@ public ModelAndView getView(final ChromatogramForm form, BindException errors) // Peptide group details VBox result = new VBox(); - Integer peptideCount = addProteinSummaryViews(result, group, _run, getUser(), getContainer()); + var showStackedPeptides = form._peptideForm != null && form._peptideForm.equalsIgnoreCase("stacked"); + Integer peptideCount = addProteinSummaryViews(result, group, _run, form.getReplicateId(), showStackedPeptides); GroupChromatogramsTableInfo tableInfo = new GroupChromatogramsTableInfo(new TargetedMSSchema(getUser(), getContainer()), form); ChromatogramsDataRegion chromatogramRegion = new ChromatogramsDataRegion(getViewContext(), tableInfo, @@ -4879,7 +4902,7 @@ private QueryView createViewWithNoContainerFilterOptions(QuerySettings settings, return result; } - public static Integer addProteinSummaryViews(VBox box, PeptideGroup group, TargetedMSRun run, User user, Container container) + public static Integer addProteinSummaryViews(VBox box, PeptideGroup group, TargetedMSRun run, @Nullable Long replicateId, boolean showStackedPeptides) { Integer peptideCount = TargetedMSManager.getPeptideGroupPeptideCount(run, group.getId()); boolean proteomics = peptideCount != null && peptideCount.intValue() > 0; @@ -4893,10 +4916,20 @@ public static Integer addProteinSummaryViews(VBox box, PeptideGroup group, Targe if (group.getSequenceId() != null) { int seqId = group.getSequenceId().intValue(); - List peptideCharacteristics = new ArrayList<>(PeptideManager.getPeptideCharacteristic(group.getId())); + List combinedPeptideCharacteristics = new ArrayList<>(PeptideManager.getCombinedPeptideCharacteristics(group.getId(), replicateId)); + List modifiedPeptideCharacteristics = new ArrayList<>(PeptideManager.getModifiedPeptideCharacteristics(group.getId(), replicateId));; + + List replicates = ReplicateManager.getReplicatesForRun(run.getRunId()); + List msReplicates = new ArrayList<>(); + replicates.forEach(replicate -> { + var rep = new org.labkey.api.ms.Replicate(); + rep.setName(replicate.getName()); + rep.setId(replicate.getId()); + msReplicates.add(rep); + }); ProteinService proteinService = ProteinService.get(); - WebPartView sequenceView = proteinService.getProteinCoverageView(seqId, peptideCharacteristics, 100, true, group.getAccession()); + WebPartView sequenceView = proteinService.getProteinCoverageViewWithSettings(seqId, combinedPeptideCharacteristics, 100, true, group.getAccession(), msReplicates, modifiedPeptideCharacteristics, showStackedPeptides); sequenceView.setTitle("Sequence Coverage"); sequenceView.enableExpandCollapse("SequenceCoverage", false); diff --git a/src/org/labkey/targetedms/parser/Replicate.java b/src/org/labkey/targetedms/parser/Replicate.java index aa052f3a8..cc01feb67 100644 --- a/src/org/labkey/targetedms/parser/Replicate.java +++ b/src/org/labkey/targetedms/parser/Replicate.java @@ -23,6 +23,7 @@ */ public class Replicate extends AnnotatedEntity { + private long _id; private long _runId; private String _name; @@ -36,6 +37,17 @@ public class Replicate extends AnnotatedEntity private List _sampleFileList; + @Override + public long getId() + { + return _id; + } + + @Override + public void setId(long id) + { + _id = id; + } public long getRunId() { diff --git a/src/org/labkey/targetedms/passport/PassportController.java b/src/org/labkey/targetedms/passport/PassportController.java index 0c1a2e90f..c9b561a83 100644 --- a/src/org/labkey/targetedms/passport/PassportController.java +++ b/src/org/labkey/targetedms/passport/PassportController.java @@ -149,7 +149,7 @@ public ModelAndView getView(ProteinForm form, BindException errors) throws IOExc VBox result = new VBox(); PeptideGroup group = PeptideGroupManager.getPeptideGroup(getContainer(), _protein.getPepGroupId()); _run = TargetedMSManager.getRun(group.getRunId()); - TargetedMSController.addProteinSummaryViews(result, group, _run, getUser(), getContainer()); + TargetedMSController.addProteinSummaryViews(result, group, _run, null, false); if (beforeAfter) { diff --git a/src/org/labkey/targetedms/query/PeptideManager.java b/src/org/labkey/targetedms/query/PeptideManager.java index d4159d88c..274ebcf5e 100644 --- a/src/org/labkey/targetedms/query/PeptideManager.java +++ b/src/org/labkey/targetedms/query/PeptideManager.java @@ -15,12 +15,14 @@ package org.labkey.targetedms.query; +import org.jetbrains.annotations.Nullable; import org.labkey.api.cache.CacheLoader; import org.labkey.api.cache.CacheManager; import org.labkey.api.data.Container; import org.labkey.api.data.DatabaseCache; import org.labkey.api.data.SQLFragment; import org.labkey.api.data.SqlSelector; +import org.labkey.api.data.dialect.SqlDialect; import org.labkey.api.protein.PeptideCharacteristic; import org.labkey.targetedms.TargetedMSManager; import org.labkey.targetedms.parser.GeneralMoleculeChromInfo; @@ -28,6 +30,7 @@ import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Set; /** @@ -94,18 +97,31 @@ public static Collection getPeptidesForGroup(long peptideGroupId) return new SqlSelector(TargetedMSManager.getSchema(), sql).getArrayList(Peptide.class); } - public static List getPeptideCharacteristic(long peptideGroupId) + private static String appendLog10IntensitySql(SqlDialect sqlDialect) { - var sqlDialect = TargetedMSManager.getSqlDialect(); - var pgLog10Intensity = "LOG(" + sqlDialect.getNumericCast(new SQLFragment("MAX(X.Intensity)")).getSQL() + ")"; - var sqlServerLog10Intensity = "LOG10(MAX(X.Intensity))"; - var pgConfidenceValueToRound = "-LOG(" + sqlDialect.getNumericCast(new SQLFragment("MAX(X.Confidence)")).getSQL() + ")"; + var pgLog10Intensity = " CASE WHEN MAX(X.Intensity) IS NOT NULL AND MAX(X.Intensity) != 0 THEN LOG(" + sqlDialect.getNumericCast(new SQLFragment("MAX(X.Intensity)")).getSQL() + ") ELSE 0 END "; + var sqlServerLog10Intensity = " CASE WHEN MAX(X.Intensity) IS NOT NULL AND MAX(X.Intensity) != 0 THEN LOG10(MAX(X.Intensity)) ELSE 0 END "; + return sqlDialect.isPostgreSQL() ? pgLog10Intensity : sqlServerLog10Intensity; + } + + private static String appendLog10ConfidenceSql(SqlDialect sqlDialect) + { + var pgConfidenceValueToRound = " CASE WHEN MAX(X.Confidence) IS NOT NULL AND MAX(X.Confidence) != 0 THEN -LOG(" + sqlDialect.getNumericCast(new SQLFragment("MAX(X.Confidence)")).getSQL() + ") ELSE 0 END "; var pgLog10Confidence = "ROUND(" + sqlDialect.getNumericCast(new SQLFragment(pgConfidenceValueToRound)).getSQL() + ",4)"; - var sqlServerLog10Confidence = "ROUND(-LOG10(MAX(X.Confidence)),4)"; - var log10IntensitySql = sqlDialect.isPostgreSQL() ? pgLog10Intensity : sqlServerLog10Intensity; - var log10ConfidenceSql = sqlDialect.isPostgreSQL() ? pgLog10Confidence : sqlServerLog10Confidence; - SQLFragment sql = new SQLFragment("SELECT X.Sequence, " + log10IntensitySql + " AS Intensity, " + log10ConfidenceSql + " AS Confidence FROM "); - sql.append("(SELECT pep.Sequence, SUM(TotalArea) AS Intensity, MAX(qvalue) AS Confidence FROM "); + var sqlServerLog10Confidence = " CASE WHEN MAX(X.Confidence) IS NOT NULL AND MAX(X.Confidence) != 0 THEN ROUND(-LOG10(MAX(X.Confidence)),4) ELSE 0 END "; + return sqlDialect.isPostgreSQL() ? pgLog10Confidence : sqlServerLog10Confidence; + } + + public static List getCombinedPeptideCharacteristics(long peptideGroupId, @Nullable Long replicateId) + { + var shouldFilterAndGroupByReplicate = null != replicateId && !Objects.equals(replicateId, Long.valueOf(0)); + var sqlDialect = TargetedMSManager.getSqlDialect(); + + SQLFragment sql = new SQLFragment("SELECT X.Sequence, " + appendLog10IntensitySql(sqlDialect) + " AS Intensity, " + appendLog10ConfidenceSql(sqlDialect) + " AS Confidence, "); + sql.append(" MAX(X.Intensity) AS RawIntensity, MAX(X.Confidence) AS RawConfidence, X.StartIndex, X.EndIndex FROM "); + sql.append("(SELECT pep.Sequence, pep.StartIndex, pep.EndIndex, "); + sql.append(" CASE WHEN SUM(TotalArea) IS NULL OR SUM(TotalArea) < 1 THEN 1 ELSE SUM(TotalArea) END AS Intensity, "); + sql.append(" MAX(qvalue) AS Confidence FROM "); sql.append(TargetedMSManager.getTableInfoPrecursorChromInfo(), "pci"); sql.append(" INNER JOIN ").append(TargetedMSManager.getTableInfoGeneralPrecursor(), "p"); sql.append(" ON p.Id = pci.PrecursorId"); @@ -115,10 +131,58 @@ public static List getPeptideCharacteristic(long peptideG sql.append(" ON gm.id = pep.Id"); sql.append(" INNER JOIN ").append(TargetedMSManager.getTableInfoSampleFile(), "sf"); sql.append(" ON sf.Id = pci.SampleFileId"); + if (shouldFilterAndGroupByReplicate) + { + sql.append(" INNER JOIN ").append(TargetedMSManager.getTableInfoReplicate(), "rep"); + sql.append(" ON rep.Id = sf.ReplicateId"); + } sql.append(" WHERE gm.PeptideGroupId=? "); - sql.append(" GROUP BY pep.Sequence,pci.SampleFileId ) X "); - sql.append(" GROUP BY X.Sequence"); sql.add(peptideGroupId); + if (shouldFilterAndGroupByReplicate) + { + sql.append(" AND rep.Id=? "); + sql.add(replicateId); + } + sql.append(" GROUP BY pep.Sequence,pci.SampleFileId, pep.StartIndex, pep.EndIndex ) X "); + sql.append(" GROUP BY X.Sequence, X.StartIndex, X.EndIndex "); + return new SqlSelector(TargetedMSManager.getSchema(), sql).getArrayList(PeptideCharacteristic.class); + } + + public static List getModifiedPeptideCharacteristics(long peptideGroupId, @Nullable Long replicateId) + { + var shouldFilterAndGroupByReplicate = null != replicateId && !Objects.equals(replicateId, Long.valueOf(0)); + var sqlDialect = TargetedMSManager.getSqlDialect(); + + SQLFragment sql = new SQLFragment("SELECT X.Sequence, X.PeptideModifiedSequence AS ModifiedSequence, X.StartIndex, X.EndIndex ,"); + sql.append(appendLog10IntensitySql(sqlDialect) + " AS Intensity, " + appendLog10ConfidenceSql(sqlDialect) + " AS Confidence, "); + sql.append(" MAX(X.Intensity) AS RawIntensity, MAX(X.Confidence) AS RawConfidence FROM "); + sql.append("(SELECT pep.Sequence, pep.PeptideModifiedSequence, pep.StartIndex, pep.EndIndex, "); + sql.append(" CASE WHEN SUM(TotalArea) IS NULL OR SUM(TotalArea) < 1 THEN 1 ELSE SUM(TotalArea) END AS Intensity, "); + sql.append(" MAX(qvalue) AS Confidence FROM "); + sql.append(TargetedMSManager.getTableInfoPrecursorChromInfo(), "pci"); + sql.append(" INNER JOIN ").append(TargetedMSManager.getTableInfoGeneralPrecursor(), "p"); + sql.append(" ON p.Id = pci.PrecursorId"); + sql.append(" INNER JOIN ").append(TargetedMSManager.getTableInfoPeptide(),"pep"); + sql.append(" ON p.GeneralMoleculeId = pep.Id"); + sql.append(" INNER JOIN ").append(TargetedMSManager.getTableInfoGeneralMolecule(),"gm"); + sql.append(" ON gm.id = pep.Id"); + sql.append(" INNER JOIN ").append(TargetedMSManager.getTableInfoSampleFile(), "sf"); + sql.append(" ON sf.Id = pci.SampleFileId"); + if (shouldFilterAndGroupByReplicate) + { + sql.append(" INNER JOIN ").append(TargetedMSManager.getTableInfoReplicate(), "rep"); + sql.append(" ON rep.Id = sf.ReplicateId"); + } + sql.append(" WHERE gm.PeptideGroupId=? "); + sql.add(peptideGroupId); + if (shouldFilterAndGroupByReplicate) + { + sql.append(" AND rep.Id=? "); + sql.add(replicateId); + } + sql.append(" GROUP BY pep.Sequence,pci.SampleFileId, pep.PeptideModifiedSequence, pep.StartIndex, pep.EndIndex ) X "); + sql.append(" GROUP BY X.Sequence, X.PeptideModifiedSequence, X.StartIndex, X.EndIndex "); + return new SqlSelector(TargetedMSManager.getSchema(), sql).getArrayList(PeptideCharacteristic.class); }