Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7befff4
sort precursor in combined qc plots legend by precursor row ID
ankurjuneja Apr 14, 2026
2ca7e4f
Let users toggle a precursor's series by clicking on its color swatch
ankurjuneja Apr 15, 2026
4998b33
Switch the legend to a tree that shows the protein/molecule list as a…
ankurjuneja Apr 15, 2026
d361873
persist the top level peptide checkbox state
ankurjuneja Apr 15, 2026
bcca729
update comment
ankurjuneja Apr 15, 2026
35203d7
fix gaps bw peptides
ankurjuneja Apr 24, 2026
14d6349
highlight/dim peptide series and tree on hover over peptide group/name
ankurjuneja Apr 26, 2026
44424b6
highlight/dim peptide series and tree on hover over qc plot series
ankurjuneja Apr 26, 2026
c9c2aae
change the color rectangle to a colored checkbox to indicate that the…
ankurjuneja Apr 26, 2026
435f72d
Change the group-level checkbox to grey
ankurjuneja Apr 26, 2026
d6a1803
indent grouped items more so they line up with the group name text
ankurjuneja Apr 26, 2026
22b9cbe
remove the gray background in tree legend on hover
ankurjuneja Apr 26, 2026
04cfa45
ident nicely
ankurjuneja Apr 29, 2026
748c9a9
code review comments
ankurjuneja Apr 29, 2026
7e2811d
make square shape consistent
ankurjuneja Apr 29, 2026
f696c65
fix exp range values for combined plots due to adjust for the new sor…
ankurjuneja Apr 29, 2026
2460484
fix more test values for plots due to adjust for the new sort order -…
ankurjuneja Apr 29, 2026
e75820f
fix more test values for plots due to adjust for the new sort order -…
ankurjuneja Apr 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/org/labkey/targetedms/TargetedMSController.java
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,7 @@ public static class LeveyJenningsPlotOptions
private Integer _trailingRuns;
private Integer _calendarMonthsToShow;
private String _heatmapDataSource;
private String _hiddenSeries;

public Map<String, String> getAsMapOfStrings()
{
Expand Down Expand Up @@ -906,6 +907,8 @@ public Map<String, String> getAsMapOfStrings()
valueMap.put("calendarMonthsToShow", Integer.toString(_calendarMonthsToShow));
if (_heatmapDataSource != null)
valueMap.put("heatMapDataSource", _heatmapDataSource);
if (_hiddenSeries != null)
valueMap.put("hiddenSeries", _hiddenSeries);
// note: start and end date handled separately since they can be null and we want to persist that
return valueMap;
}
Expand Down Expand Up @@ -1034,6 +1037,16 @@ public void setHeatmapDataSource(String heatmapDataSource)
{
_heatmapDataSource = heatmapDataSource;
}

public String getHiddenSeries()
{
return _hiddenSeries;
}

public void setHiddenSeries(String hiddenSeries)
{
_hiddenSeries = hiddenSeries;
}
}

@RequiresPermission(ReadPermission.class)
Expand Down
44 changes: 44 additions & 0 deletions src/org/labkey/targetedms/model/QCPlotFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ public class QCPlotFragment
private List<GuideSetStats> guideSetStats;
@Nullable
private Color _seriesColor;
@Nullable
private Long precursorRowId;
@Nullable
private Long peptideGroupId;
@Nullable
private String peptideGroupLabel;

public String getSeriesLabel()
{
Expand Down Expand Up @@ -77,6 +83,11 @@ public JSONObject toJSON(boolean includeLJ, boolean includeMR, boolean includeMe
JSONObject jsonObject = new JSONObject();
jsonObject.put("DataType", getDataType());
jsonObject.put("SeriesLabel", getSeriesLabel());
if (peptideGroupId != null)
{
jsonObject.put("PeptideGroupId", peptideGroupId);
jsonObject.put("PeptideGroupLabel", peptideGroupLabel != null ? peptideGroupLabel : "");
}
if (_seriesColor != null)
{
jsonObject.put("SeriesColor", "#" + Integer.toHexString(_seriesColor.getRGB()).substring(2).toUpperCase());
Expand Down Expand Up @@ -205,4 +216,37 @@ public Color getSeriesColor()
{
return _seriesColor;
}

@Nullable
public Long getPrecursorRowId()
{
return precursorRowId;
}

public void setPrecursorRowId(Long precursorRowId)
{
this.precursorRowId = precursorRowId;
}

@Nullable
public Long getPeptideGroupId()
{
return peptideGroupId;
}

public void setPeptideGroupId(Long peptideGroupId)
{
this.peptideGroupId = peptideGroupId;
}

@Nullable
public String getPeptideGroupLabel()
{
return peptideGroupLabel;
}

public void setPeptideGroupLabel(String peptideGroupLabel)
{
this.peptideGroupLabel = peptideGroupLabel;
}
}
22 changes: 20 additions & 2 deletions src/org/labkey/targetedms/outliers/OutlierGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@
import org.labkey.targetedms.model.SampleFileQCMetadata;
import org.labkey.targetedms.parser.GeneralMolecule;
import org.labkey.targetedms.parser.GeneralPrecursor;
import org.labkey.targetedms.parser.PeptideGroup;
import org.labkey.targetedms.parser.SampleFile;
import org.labkey.targetedms.query.MoleculeManager;
import org.labkey.targetedms.query.MoleculePrecursorManager;
import org.labkey.targetedms.query.PeptideGroupManager;
import org.labkey.targetedms.query.PeptideManager;
import org.labkey.targetedms.query.PrecursorManager;

Expand Down Expand Up @@ -539,7 +541,11 @@ public List<QCPlotFragment> getQCPlotFragment(List<RawMetricDataSet> rawMetricDa
Optional<RawMetricDataSet> bestPrecursorIdRow = entry.getValue().stream().filter(x -> x.getPrecursorId() != null).min(Comparator.comparing(RawMetricDataSet::getPrecursorId));

// Remember the precursor ID so that we can assign a series color based on Skyline's algorithm
bestPrecursorIdRow.ifPresent(rawMetricDataSet -> fragmentsByPrecursorId.put(rawMetricDataSet.getPrecursorId(), qcPlotFragment));
// and to sort by Skyline document order (row ID) instead of alphabetically
bestPrecursorIdRow.ifPresent(rawMetricDataSet -> {
fragmentsByPrecursorId.put(rawMetricDataSet.getPrecursorId(), qcPlotFragment);
qcPlotFragment.setPrecursorRowId(rawMetricDataSet.getPrecursorId());
});

qcPlotFragment.setSeriesLabel(entry.getKey());
qcPlotFragment.setQcPlotData(entry.getValue());
Expand All @@ -559,6 +565,7 @@ public List<QCPlotFragment> getQCPlotFragment(List<RawMetricDataSet> rawMetricDa
// Now that we have all the precursor IDs, in order (important so that we de-dupe the colors in a stable order),
// run through them and choose a color
Set<Color> seriesColors = new HashSet<>();
Map<Long, PeptideGroup> peptideGroupCache = new HashMap<>();
for (Map.Entry<Long, QCPlotFragment> entry : fragmentsByPrecursorId.entrySet())
{
long precursorId = entry.getKey();
Expand Down Expand Up @@ -588,10 +595,21 @@ public List<QCPlotFragment> getQCPlotFragment(List<RawMetricDataSet> rawMetricDa
Color color = ColorGenerator.getColor(molecule.getTextId(), seriesColors);
entry.getValue().setSeriesColor(color);
seriesColors.add(color);

// set the peptide group (protein / molecule list) for the combined plot tree legend
PeptideGroup peptideGroup = peptideGroupCache.computeIfAbsent(molecule.getPeptideGroupId(), id -> PeptideGroupManager.getPeptideGroup(c, id));
if (peptideGroup != null)
{
entry.getValue().setPeptideGroupId(peptideGroup.getId());
entry.getValue().setPeptideGroupLabel(peptideGroup.getLabel());
}
}
}

qcPlotFragments.sort(Comparator.comparing(QCPlotFragment::getSeriesLabel));
// Sort by precursor row ID to preserve Skyline document order. Fragments with no precursor ID
// (e.g. trace metrics) fall back to alphabetical order after all precursor-scoped series.
qcPlotFragments.sort(Comparator.comparing(QCPlotFragment::getPrecursorRowId, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(QCPlotFragment::getSeriesLabel));
return qcPlotFragments;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ public void testLinkExperimentalQC()
String expRange = "Skyline File: " + SProCoP_FILE + ", " +
"Start: 2013-08-09 11:39:00, " +
"End: 2013-08-27 14:45:49, " +
"Mean: 14.669, Std Dev: 0.501, " +
"%CV: 3.415";
"Mean: 28.764, Std Dev: 0.666, " +
"%CV: 2.315";

goToProjectHome(QC_FOLDER_1);
PanoramaDashboard qcDashboard = new PanoramaDashboard(this);
Expand All @@ -114,16 +114,16 @@ public void testLinkExperimentalQC()
"Start: 2013-08-03 00:00:00, " +
"End: 2013-08-09 23:59:00, " +
"# Runs: 5, " +
"Mean: 15.427, " +
"Std Dev: 0.973, " +
"%CV: 6.307",
"Mean: 32.798, " +
"Std Dev: 7.613, " +
"%CV: 23.212",
"Guide Set ID: " + getGuideSetRowId("Second") + ", " +
"Start: 2013-08-19 00:00:00, " +
"End: 2013-08-21 23:59:00, " +
"# Runs: 17, " +
"Mean: 14.687, " +
"Std Dev: 0.588, " +
"%CV: 4.004");
"Mean: 28.854, " +
"Std Dev: 0.675, " +
"%CV: 2.339");

goToProjectHome();
DataRegionTable table = new DataRegionTable("TargetedMSRuns", getDriver());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ public void testTrailingMeanPlotType()
Metric:
Retention Time
Peptide:
ATEEQLK ++, 409.7163
VYVEELKPTPEGDLEILLQK ++, 1,157.1330
Value:
15.652
35.156
Replicate:
3 runs average
Acquired:
Expand All @@ -117,9 +117,9 @@ public void testTrailingMeanPlotType()
Metric:
Retention Time
Peptide:
ATEEQLK ++, 409.7163
VYVEELKPTPEGDLEILLQK ++, 1,157.1330
Value:
15.684
35.102
Replicate:
3 runs average
Acquired:
Expand Down Expand Up @@ -160,9 +160,9 @@ public void testTrailingCVPlotType()
Metric:
Retention Time
Peptide:
ATEEQLK ++, 409.7163
VYVEELKPTPEGDLEILLQK ++, 1,157.1330
Value:
6.831
22.645
Replicate:
3 runs average
Acquired:
Expand All @@ -183,9 +183,9 @@ public void testTrailingCVPlotType()
Metric:
Retention Time
Peptide:
ATEEQLK ++, 409.7163
VYVEELKPTPEGDLEILLQK ++, 1,157.1330
Value:
3.704
2.225
Replicate:
3 runs average
Acquired:
Expand Down
13 changes: 13 additions & 0 deletions webapp/TargetedMS/css/qcTrendPlotReport.css
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,17 @@

.x4-panel-header-text-container-default {
font-weight: normal;
}

.qc-combined-tree-legend {
background: white;
line-height: 1.4;
}

.qc-combined-tree-legend .qc-tree-group label:hover {
background-color: #f0f0f0;
}

.qc-combined-tree-legend .qc-tree-precursor:hover {
background-color: #f0f0f0;
}
21 changes: 16 additions & 5 deletions webapp/TargetedMS/js/QCPlotHelperBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ Ext4.define("LABKEY.targetedms.QCPlotHelperBase", {
statics: {
qcPlotTypes : ['Metric Value', 'Moving Range', 'CUSUMm', 'CUSUMv', 'Trailing CV', 'Trailing Mean'],
maxPointsPerSeries : 300,
shapeDomain: ['Include', 'Exclude', 'Include-Outlier', 'Exclude-Outlier']
shapeDomain: ['Include', 'Exclude', 'Include-Outlier', 'Exclude-Outlier'],
// Separates fragment from series name in legend item names (e.g. "PEPTIDE|Left"). Fragments are peptide
// sequences or molecule names and are not expected to contain this character.
SERIES_NAME_SEP: '|',
// Square 12x12 shape for combined plot legend swatches, matching the tree legend checkbox size.
SQUARE_LEGEND_SHAPE: function() { return 'M-6,-6 L6,-6 6,6 -6,6 Z'; }
},

showMetricValuePlot: function() {
Expand Down Expand Up @@ -412,9 +417,11 @@ Ext4.define("LABKEY.targetedms.QCPlotHelperBase", {
}

if (this.singlePlot && this.getMetricPropsById(this.metric).precursorScoped) {
this.peptideGroups = this.buildPeptideGroups();
addedPlot = this.addCombinedPeptideSinglePlot(metricProps);
}
else {
this.peptideGroups = null;
addedPlot = this.addIndividualPrecursorPlots(metricProps);
}

Expand Down Expand Up @@ -602,10 +609,11 @@ Ext4.define("LABKEY.targetedms.QCPlotHelperBase", {
const series1Legend = precursorInfo.dataType === 'Peptide' ? proteomicsLegend : ionLegend;

series1Legend.push({
name: precursorInfo.fragment + (this.isMultiSeries() ? '|' + legendSeries[0] : ''),
name: precursorInfo.fragment + (this.isMultiSeries() ? LABKEY.targetedms.QCPlotHelperBase.SERIES_NAME_SEP + legendSeries[0] : ''),
text: this.legendHelper.getLegendItemText(precursorInfo),
hoverText: precursorInfo.fragment,
color: groupColors[i % groupColors.length]
color: groupColors[i % groupColors.length],
shape: LABKEY.targetedms.QCPlotHelperBase.SQUARE_LEGEND_SHAPE
});
}
}
Expand All @@ -628,10 +636,11 @@ Ext4.define("LABKEY.targetedms.QCPlotHelperBase", {

precursorInfo = this.fragmentPlotData[this.precursors[i]];
series2Legend.push({
name: precursorInfo.fragment + '|' + legendSeries[1],
name: precursorInfo.fragment + LABKEY.targetedms.QCPlotHelperBase.SERIES_NAME_SEP + legendSeries[1],
text: this.legendHelper.getLegendItemText(precursorInfo),
hoverText: precursorInfo.fragment,
color: groupColors[(this.precursors.length + i) % groupColors.length]
color: groupColors[(this.precursors.length + i) % groupColors.length],
shape: LABKEY.targetedms.QCPlotHelperBase.SQUARE_LEGEND_SHAPE
});
}
}
Expand Down Expand Up @@ -822,6 +831,8 @@ Ext4.define("LABKEY.targetedms.QCPlotHelperBase", {
const plot = LABKEY.vis.TrendingLinePlot(plotConfig);
plot.render();

this.attachCombinedLegendClickHandlers();

this.addAnnotationsToPlot(plot, combinePlotData);

this.addGuideSetTrainingRangeToPlot(plot, combinePlotData);
Expand Down
11 changes: 11 additions & 0 deletions webapp/TargetedMS/js/QCPlotHelperWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,11 @@ Ext4.define("LABKEY.targetedms.QCPlotHelperWrapper", {
}

this.setPlotBrushingDisplayStyle();

if (this.hasPeptideGroupTree()) {
this.renderCombinedTreeLegend(id, legendMargin);
}

return true;
},

Expand Down Expand Up @@ -295,6 +300,12 @@ Ext4.define("LABKEY.targetedms.QCPlotHelperWrapper", {
this.fragmentPlotData[fragment] = this.getInitFragmentPlotData(fragment, dataType, mz, color);
}

// Store peptide group info (protein / molecule list) for the combined plot tree legend
if (this.fragmentPlotData[fragment].peptideGroupId == null && plotDataRow['PeptideGroupId'] != null) {
this.fragmentPlotData[fragment].peptideGroupId = plotDataRow['PeptideGroupId'];
this.fragmentPlotData[fragment].peptideGroupLabel = plotDataRow['PeptideGroupLabel'];
}

var metricId = row['MetricId'];
const metricProp = metricProps[metricId];

Expand Down
Loading
Loading