Skip to content

Commit f564866

Browse files
committed
Merge remote-tracking branch 'origin/feat/msl-spectral-library-input' into feat/msl-metadraw-support
2 parents 8c8ad57 + 7a855e8 commit f564866

15 files changed

Lines changed: 1223 additions & 65 deletions

File tree

.github/workflows/Test.yml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,36 @@ jobs:
2727
run: dotnet add ./MetaMorpheus/Test/Test.csproj package coverlet.collector -v 6.0.2
2828

2929
- name: Run unit tests with coverage
30-
run: dotnet test .\MetaMorpheus\Test\Test.csproj --configuration Release --verbosity normal --collect:"XPlat Code Coverage"
31-
30+
# Exclude live external-service tests (UniProt, etc.) from the required run; they run in the
31+
# separate, non-blocking external-service-tests job below.
32+
run: dotnet test .\MetaMorpheus\Test\Test.csproj --configuration Release --verbosity normal --filter "Category!=ExternalService" --collect:"XPlat Code Coverage"
33+
3234
- name: Upload coverage to Codecov
3335
uses: codecov/codecov-action@v4
3436
with:
3537
token: ${{ secrets.CODECOV_TOKEN }}
3638
verbose: true
3739
flags: unittests
40+
41+
# Runs tests that depend on live external web services (UniProt, ...). Kept separate and
42+
# intentionally NOT a required status check, so a third-party outage never blocks a PR. The tests
43+
# self-classify: an outage is reported as Skipped (Assert.Ignore) and only a genuine contract
44+
# break fails this job. Do NOT add this job to branch-protection required checks.
45+
external-service-tests:
46+
name: External-service tests (non-blocking)
47+
runs-on: windows-latest
48+
49+
steps:
50+
- uses: actions/checkout@v4
51+
- name: Setup .NET
52+
uses: actions/setup-dotnet@v4
53+
with:
54+
dotnet-version: 8.0.204
55+
- name: Restore dependencies
56+
run: dotnet restore ./MetaMorpheus/MetaMorpheus.sln
57+
58+
- name: Build
59+
run: dotnet build --no-restore ./MetaMorpheus/MetaMorpheus.sln --configuration Release
60+
61+
- name: Run external-service tests
62+
run: dotnet test .\MetaMorpheus\Test\Test.csproj --configuration Release --no-build --verbosity normal --filter "Category=ExternalService"

MetaMorpheus/CMD/CMD.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<PackageReference Include="Microsoft.ML.CpuMath" Version="3.0.1" />
2525
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
2626
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
27-
<PackageReference Include="mzLib" Version="1.0.580" />
27+
<PackageReference Include="mzLib" Version="1.0.582" />
2828
<PackageReference Include="Nett" Version="0.15.0" />
2929
<PackageReference Include="SQLite.Interop.dll" Version="1.0.103" />
3030
<PackageReference Include="System.Data.SQLite" Version="1.0.118" />

MetaMorpheus/EngineLayer/DIA/DIAEngine.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
using EngineLayer.Util;
1313
using Omics;
1414
using FlashLFQ;
15-
using ThermoFisher.CommonCore.Data.Business;
1615
using Readers;
1716

1817
namespace EngineLayer.DIA

MetaMorpheus/EngineLayer/EngineLayer.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<PackageReference Include="Microsoft.ML.CpuMath" Version="3.0.1" />
3030
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
3131
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
32-
<PackageReference Include="mzLib" Version="1.0.580" />
32+
<PackageReference Include="mzLib" Version="1.0.582" />
3333
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
3434
<PackageReference Include="Nett" Version="0.15.0" />
3535
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

MetaMorpheus/GUI/GUI.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
<PackageReference Include="Microsoft.ML.CpuMath" Version="3.0.1" />
6464
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
6565
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
66-
<PackageReference Include="mzLib" Version="1.0.580" />
66+
<PackageReference Include="mzLib" Version="1.0.582" />
6767
<PackageReference Include="Nett" Version="0.15.0" />
6868
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
6969
<PackageReference Include="OxyPlot.Core" Version="2.0.0" />

MetaMorpheus/GuiFunctions/GuiFunctions.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<ItemGroup>
1717
<PackageReference Include="itext7" Version="8.0.5" />
1818
<PackageReference Include="itext7.bouncy-castle-adapter" Version="8.0.5" />
19-
<PackageReference Include="mzLib" Version="1.0.580" />
19+
<PackageReference Include="mzLib" Version="1.0.582" />
2020
<PackageReference Include="OxyPlot.Wpf" Version="2.0.0" />
2121
<PackageReference Include="Svg" Version="3.4.7" />
2222
</ItemGroup>

MetaMorpheus/GuiFunctions/MetaDraw/PlotModelStat.cs

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ public class PlotModelStat
4343
"Histogram of Missed Cleavages",
4444
"Histogram of Fragment Ion Types by Count",
4545
"Histogram of Fragment Ion Types by Intensity",
46-
"Histogram of Ids by Retention Time"
46+
"Histogram of Ids by Retention Time",
47+
"Histogram of Spectral Match Ambiguity Levels",
48+
"Histogram of Notch (Ambiguous PSMs Split Across Notches)"
4749
};
4850

4951
public PlotModel Model => privateModel;
@@ -124,6 +126,12 @@ private void createPlot(string plotType)
124126
case "Histogram of Ids by Retention Time":
125127
histogramPlot(12);
126128
break;
129+
case "Histogram of Spectral Match Ambiguity Levels":
130+
histogramPlot(13);
131+
break;
132+
case "Histogram of Notch (Ambiguous PSMs Split Across Notches)":
133+
histogramPlot(14);
134+
break;
127135
}
128136
}
129137

@@ -153,7 +161,7 @@ private void histogramPlot(int plotType)
153161
int[] totalCounts;
154162
int categoriesPerGroup = 0;
155163
List<string> allGroupKeys = null;
156-
bool isCategoryHistogram = plotType == 5 || plotType == 10 || plotType == 11;
164+
bool isCategoryHistogram = plotType == 5 || plotType == 10 || plotType == 11 || plotType == 13;
157165

158166
if (isCategoryHistogram)
159167
{
@@ -336,6 +344,34 @@ private HistogramRawData GetHistogramData(int plotType)
336344
dictsBySourceFile.Add(fileName, result);
337345
}
338346
break;
347+
case 13: // Histogram of Spectral Match Ambiguity Levels
348+
xAxisTitle = "Ambiguity Level";
349+
labelAngle = 0;
350+
foreach (var fileName in psmsBySourceFile.Keys)
351+
{
352+
var result = psmsBySourceFile[fileName]
353+
.GroupBy(p => NormalizeAmbiguityLevel(p.AmbiguityLevel))
354+
.ToDictionary(p => p.Key, p => p.Count());
355+
dictsBySourceFile.Add(fileName, result);
356+
}
357+
break;
358+
case 14: // Histogram of Notch (ambiguous PSMs contribute to each of their pipe-delimited notches)
359+
xAxisTitle = "Notch";
360+
binSize = 1;
361+
labelAngle = 0;
362+
foreach (var fileName in psmsBySourceFile.Keys)
363+
{
364+
var values = new List<double>();
365+
foreach (var psm in psmsBySourceFile[fileName])
366+
{
367+
foreach (double notch in ParseAmbiguousNotchValues(psm.Notch))
368+
values.Add(notch);
369+
}
370+
numbersBySourceFile.Add(fileName, values);
371+
var results = values.GroupBy(p => roundToBin(p, binSize)).OrderBy(p => p.Key).Select(p => p);
372+
dictsBySourceFile.Add(fileName, results.ToDictionary(p => p.Key.ToString(CultureInfo.InvariantCulture), v => v.Count()));
373+
}
374+
break;
339375
}
340376

341377
return new HistogramRawData(xAxisTitle, yAxisTitle, binSize, labelAngle, numbersBySourceFile, dictsBySourceFile);
@@ -515,6 +551,13 @@ private Dictionary<string, int> GetCategoryDictForGroup(int plotType, Observable
515551
return mods.GroupBy(p => p.IdWithMotif).ToDictionary(p => p.Key, v => v.Count());
516552
}
517553

554+
if (plotType == 13)
555+
{
556+
return groupPsms
557+
.GroupBy(p => NormalizeAmbiguityLevel(p.AmbiguityLevel))
558+
.ToDictionary(p => p.Key, p => p.Count());
559+
}
560+
518561
var allMatchedIons = groupPsms.SelectMany(p => p.MatchedIons).ToList();
519562
if (plotType == 10)
520563
{
@@ -1013,6 +1056,7 @@ private IEnumerable<double> GetNumbersFromPsms(ObservableCollection<SpectrumMatc
10131056
8 => GetHydrophobicityScores(psms),
10141057
9 => psms.Where(p => !p.MissedCleavage.Contains("|")).Select(p => double.Parse(p.MissedCleavage)),
10151058
12 => psms.Select(p => (double)(int)Math.Round(p.RetentionTime, 0)),
1059+
14 => psms.SelectMany(p => ParseAmbiguousNotchValues(p.Notch)),
10161060
_ => Enumerable.Empty<double>()
10171061
};
10181062
}
@@ -1042,6 +1086,37 @@ public HistItem(double value, int categoryIndex, string bin, int total, string g
10421086
}
10431087
}
10441088

1089+
private static IEnumerable<string> SplitAmbiguousNotch(string notch)
1090+
{
1091+
if (string.IsNullOrWhiteSpace(notch))
1092+
return new[] { "0" };
1093+
1094+
return notch.Split('|')
1095+
.Select(p => p.Trim())
1096+
.Where(p => p.Length > 0)
1097+
.DefaultIfEmpty("0");
1098+
}
1099+
1100+
private static IEnumerable<double> ParseAmbiguousNotchValues(string notch)
1101+
{
1102+
foreach (var part in SplitAmbiguousNotch(notch))
1103+
{
1104+
if (double.TryParse(part, NumberStyles.Float, CultureInfo.InvariantCulture, out double value))
1105+
yield return value;
1106+
else
1107+
yield return 0.0;
1108+
}
1109+
}
1110+
1111+
private static string NormalizeAmbiguityLevel(string ambiguityLevel)
1112+
{
1113+
if (string.IsNullOrWhiteSpace(ambiguityLevel))
1114+
return "1";
1115+
1116+
var first = ambiguityLevel.Split('|')[0].Trim();
1117+
return string.IsNullOrEmpty(first) ? "1" : first;
1118+
}
1119+
10451120
/// <summary>
10461121
/// Orders strings numerically if all values are numeric, otherwise alphabetically.
10471122
/// </summary>

MetaMorpheus/TaskLayer/TaskLayer.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<PackageReference Include="Microsoft.ML.CpuMath" Version="3.0.1" />
2222
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
2323
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
24-
<PackageReference Include="mzLib" Version="1.0.580" />
24+
<PackageReference Include="mzLib" Version="1.0.582" />
2525
<PackageReference Include="NetSerializer" Version="4.1.2" />
2626
<PackageReference Include="Nett" Version="0.15.0" />
2727
<PackageReference Include="SQLite.Interop.dll" Version="1.0.103" />
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
>sp|P03680|MCP_BPPH2 Major capsid protein OS=Bacillus phage phi29 OX=10756 GN=8 PE=1 SV=1
2+
MAGKKQNIVLESAWRELVGK
3+
>sp|P03681|PORT_BPPH2 Head-tail connector protein OS=Bacillus phage phi29 OX=10756 GN=10 PE=1 SV=1
4+
MSKTLNEVLGQVADSFRTKGWK
5+
>sp|P03682|DPOL_BPPH2 DNA polymerase OS=Bacillus phage phi29 OX=10756 GN=2 PE=1 SV=1
6+
MPRKMYSCDFETTTKLDDCRVWAY
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<uniprot xmlns="http://uniprot.org/uniprot" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://uniprot.org/uniprot http://www.uniprot.org/support/docs/uniprot.xsd">
3+
<!--
4+
Local, offline mock of a UniProtKB XML "stream" response.
5+
Stands in for a live download of Bacillus phage phi29 (proteome UP000001207)
6+
so GuiFunctionsTest can exercise the ProteinDbLoader.LoadProteinXML path without
7+
reaching rest.uniprot.org. Sequences are truncated/synthetic; only the file
8+
structure and the number of entries (3) matter for the test.
9+
-->
10+
<entry dataset="Swiss-Prot" created="1986-07-21" modified="2021-09-29" version="1">
11+
<accession>P03680</accession>
12+
<name>MCP_BPPH2</name>
13+
<protein>
14+
<recommendedName>
15+
<fullName>Major capsid protein</fullName>
16+
</recommendedName>
17+
</protein>
18+
<gene>
19+
<name type="primary">8</name>
20+
</gene>
21+
<organism>
22+
<name type="scientific">Bacillus phage phi29</name>
23+
<dbReference type="NCBI Taxonomy" id="10756"/>
24+
</organism>
25+
<sequence length="20" mass="2100" checksum="0000000000000000" modified="1986-07-21" version="1">MAGKKQNIVLESAWRELVGK</sequence>
26+
</entry>
27+
<entry dataset="Swiss-Prot" created="1986-07-21" modified="2021-09-29" version="1">
28+
<accession>P03681</accession>
29+
<name>PORT_BPPH2</name>
30+
<protein>
31+
<recommendedName>
32+
<fullName>Head-tail connector protein</fullName>
33+
</recommendedName>
34+
</protein>
35+
<gene>
36+
<name type="primary">10</name>
37+
</gene>
38+
<organism>
39+
<name type="scientific">Bacillus phage phi29</name>
40+
<dbReference type="NCBI Taxonomy" id="10756"/>
41+
</organism>
42+
<sequence length="22" mass="2300" checksum="1111111111111111" modified="1986-07-21" version="1">MSKTLNEVLGQVADSFRTKGWK</sequence>
43+
</entry>
44+
<entry dataset="Swiss-Prot" created="1986-07-21" modified="2021-09-29" version="1">
45+
<accession>P03682</accession>
46+
<name>DPOL_BPPH2</name>
47+
<protein>
48+
<recommendedName>
49+
<fullName>DNA polymerase</fullName>
50+
</recommendedName>
51+
</protein>
52+
<gene>
53+
<name type="primary">2</name>
54+
</gene>
55+
<organism>
56+
<name type="scientific">Bacillus phage phi29</name>
57+
<dbReference type="NCBI Taxonomy" id="10756"/>
58+
</organism>
59+
<sequence length="24" mass="2600" checksum="2222222222222222" modified="1986-07-21" version="1">MPRKMYSCDFETTTKLDDCRVWAY</sequence>
60+
</entry>
61+
</uniprot>

0 commit comments

Comments
 (0)