Skip to content

Commit 1401640

Browse files
authored
Internal Fragment Ion Funtionality (#2081)
* Add Internal fragment ions to SearchTask and MetaDraw * Have annotation spectrum tab always available * Remove doubling bug * unit test * fix minor bug * unit test * XL unit test * Fix debug code
1 parent e41d933 commit 1401640

29 files changed

+6527
-161
lines changed

CMD/CMD.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<PackageReference Include="Microsoft.ML" Version="1.3.1" />
2424
<PackageReference Include="Microsoft.ML.FastTree" Version="1.3.1" />
2525
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
26-
<PackageReference Include="mzLib" Version="1.0.499" />
26+
<PackageReference Include="mzLib" Version="1.0.500" />
2727
<PackageReference Include="Nett" Version="0.13.0" />
2828
</ItemGroup>
2929

@@ -32,4 +32,4 @@
3232
<ProjectReference Include="..\TaskLayer\TaskLayer.csproj" />
3333
</ItemGroup>
3434

35-
</Project>
35+
</Project>

EngineLayer/EngineLayer.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<PackageReference Include="Microsoft.ML" Version="1.3.1" />
2121
<PackageReference Include="Microsoft.ML.FastTree" Version="1.3.1" />
2222
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
23-
<PackageReference Include="mzLib" Version="1.0.499" />
23+
<PackageReference Include="mzLib" Version="1.0.500" />
2424
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
2525
<PackageReference Include="Nett" Version="0.13.0" />
2626
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
@@ -104,4 +104,4 @@
104104
</None>
105105
</ItemGroup>
106106

107-
</Project>
107+
</Project>

EngineLayer/PeptideSpectralMatch.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public PeptideSpectralMatch(PeptideWithSetModifications peptide, int notch, doub
7878

7979
public DigestionParams DigestionParams { get; }
8080
public Dictionary<PeptideWithSetModifications, List<MatchedFragmentIon>> PeptidesToMatchingFragments { get; private set; }
81-
81+
8282
public IEnumerable<(int Notch, PeptideWithSetModifications Peptide)> BestMatchingPeptides
8383
{
8484
get
@@ -131,6 +131,10 @@ public void AddOrReplace(PeptideWithSetModifications pwsm, double newScore, int
131131
public void RemoveThisAmbiguousPeptide(int notch, PeptideWithSetModifications pwsm)
132132
{
133133
_BestMatchingPeptides.Remove((notch, pwsm));
134+
if (!_BestMatchingPeptides.Any(x => x.Pwsm.Equals(pwsm)))
135+
{
136+
PeptidesToMatchingFragments.Remove(pwsm);
137+
}
134138
this.ResolveAllAmbiguities();
135139
}
136140

EngineLayer/PsmTsv/PsmFromTsv.cs

+88-51
Large diffs are not rendered by default.

EngineLayer/PsmTsv/PsmTsvHeader.cs

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ public static class PsmTsvHeader
7878
public const string BetaPeptideScoreLabel = "Beta Peptide Score";
7979
public const string BetaPeptideRankLabel = "Beta Peptide Rank";
8080
public const string BetaPeptideMatchedIonsLabel = "Beta Peptide Matched Ion Mass-To-Charge Ratios";
81+
public const string BetaPeptideMatchedIonIntensitiesLabel = "Beta Peptide Matched Ion Intensities";
8182
public const string XLTotalScoreLabel = "XL Total Score";
8283
public const string ParentIonsLabel = "Parent Ions";
8384
}

EngineLayer/PsmTsv/PsmTsvReader.cs

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ private static Dictionary<string, int> ParseHeader(string header)
9696
parsedHeader.Add(PsmTsvHeader.NextAminoAcid, Array.IndexOf(spl, PsmTsvHeader.NextAminoAcid));
9797
parsedHeader.Add(PsmTsvHeader.DecoyContaminantTarget, Array.IndexOf(spl, PsmTsvHeader.DecoyContaminantTarget));
9898
parsedHeader.Add(PsmTsvHeader.MatchedIonMzRatios, Array.IndexOf(spl, PsmTsvHeader.MatchedIonMzRatios));
99+
parsedHeader.Add(PsmTsvHeader.MatchedIonIntensities, Array.IndexOf(spl, PsmTsvHeader.MatchedIonIntensities));
99100
parsedHeader.Add(PsmTsvHeader.QValue, Array.IndexOf(spl, PsmTsvHeader.QValue));
100101
parsedHeader.Add(PsmTsvHeader.QValueNotch, Array.IndexOf(spl, PsmTsvHeader.QValueNotch));
101102
parsedHeader.Add(PsmTsvHeader.PEP, Array.IndexOf(spl, PsmTsvHeader.PEP));
@@ -113,6 +114,7 @@ private static Dictionary<string, int> ParseHeader(string header)
113114
parsedHeader.Add(PsmTsvHeader.BetaPeptideScoreLabel, Array.IndexOf(spl, PsmTsvHeader.BetaPeptideScoreLabel));
114115
parsedHeader.Add(PsmTsvHeader.BetaPeptideRankLabel, Array.IndexOf(spl, PsmTsvHeader.BetaPeptideRankLabel));
115116
parsedHeader.Add(PsmTsvHeader.BetaPeptideMatchedIonsLabel, Array.IndexOf(spl, PsmTsvHeader.BetaPeptideMatchedIonsLabel));
117+
parsedHeader.Add(PsmTsvHeader.BetaPeptideMatchedIonIntensitiesLabel, Array.IndexOf(spl, PsmTsvHeader.BetaPeptideMatchedIonIntensitiesLabel));
116118
parsedHeader.Add(PsmTsvHeader.XLTotalScoreLabel, Array.IndexOf(spl, PsmTsvHeader.XLTotalScoreLabel));
117119
parsedHeader.Add(PsmTsvHeader.ParentIonsLabel, Array.IndexOf(spl, PsmTsvHeader.ParentIonsLabel));
118120
parsedHeader.Add(PsmTsvHeader.Ms2ScanRetentionTime, Array.IndexOf(spl, PsmTsvHeader.Ms2ScanRetentionTime));

EngineLayer/PsmTsv/PsmTsvWriter.cs

+2-12
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ internal static void AddMatchedIonsData(Dictionary<string, string> s, List<Match
263263
// using ", " instead of "," improves human readability
264264
const string delimiter = ", ";
265265

266-
var matchedIonsGroupedByProductType = matchedIons.GroupBy(i => i.NeutralTheoreticalProduct.ProductType).OrderBy(i => i.Key).ToList();
266+
var matchedIonsGroupedByProductType = matchedIons.GroupBy(x => new { x.NeutralTheoreticalProduct.ProductType, x.NeutralTheoreticalProduct.SecondaryProductType }).ToList();
267267

268268
foreach (var productType in matchedIonsGroupedByProductType)
269269
{
@@ -280,17 +280,7 @@ internal static void AddMatchedIonsData(Dictionary<string, string> s, List<Match
280280
double massError = ion.Mz.ToMass(ion.Charge) - ion.NeutralTheoreticalProduct.NeutralMass;
281281
double ppmMassError = massError / ion.NeutralTheoreticalProduct.NeutralMass * 1e6;
282282

283-
if (ion.NeutralTheoreticalProduct.NeutralLoss == 0)
284-
{
285-
// no neutral loss
286-
ionLabel = ion.NeutralTheoreticalProduct.ProductType + "" + ion.NeutralTheoreticalProduct.FragmentNumber + "+" + ion.Charge;
287-
}
288-
else
289-
{
290-
// ion label with neutral loss
291-
ionLabel = "(" + ion.NeutralTheoreticalProduct.ProductType + "" + ion.NeutralTheoreticalProduct.FragmentNumber
292-
+ "-" + ion.NeutralTheoreticalProduct.NeutralLoss.ToString("F2") + ")" + "+" + ion.Charge;
293-
}
283+
ionLabel = ion.Annotation;
294284

295285
// append ion label
296286
seriesStringBuilder.Append(ionLabel);

GUI/App.xaml

+6-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<SolidColorBrush x:Key="TextColor1" Color="#2f3640" />
1717
<SolidColorBrush x:Key="TextColor2" Color="#f5f6fa" />
1818
<SolidColorBrush x:Key="TextColorDelete" Color="#c23616" />
19-
19+
2020
<!--Default button style for all of MetaMorpheus-->
2121
<!--<Style TargetType="Button">
2222
<Setter Property="BorderThickness" Value="0"/>
@@ -25,5 +25,10 @@
2525
<Setter Property="Foreground" Value="{StaticResource TextColor2}"/>
2626
<Setter Property="FontSize" Value="12"/>
2727
</Style>-->
28+
29+
<Style x:Key="InternalGridStyle" TargetType="Grid">
30+
<Setter Property="Background" Value="{StaticResource BackgroundColor}"/>
31+
<Setter Property="Margin" Value="0,0,0,0"/>
32+
</Style>
2833
</Application.Resources>
2934
</Application>

GUI/GUI.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
<PackageReference Include="Microsoft.ML.DataView" Version="1.3.1" />
5656
<PackageReference Include="Microsoft.ML.FastTree" Version="1.3.1" />
5757
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
58-
<PackageReference Include="mzLib" Version="1.0.499" />
58+
<PackageReference Include="mzLib" Version="1.0.500" />
5959
<PackageReference Include="Nett" Version="0.13.0" />
6060
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
6161
<PackageReference Include="OxyPlot.Core" Version="2.0.0" />

GUI/MetaDraw/MetaDraw.xaml

+30-1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
<RowDefinition Height="Auto" />
112112
</Grid.RowDefinitions>
113113
<TabControl Grid.Row="0">
114+
<!--MS2 Scan Annotations-->
114115
<TabItem Header="Parent Scan View" Name="ParentScanView">
115116
<Grid Name="PsmAnnotationGrid">
116117
<Grid.RowDefinitions>
@@ -177,6 +178,34 @@
177178

178179
</ItemsControl>
179180
</TabItem>
181+
<!--Sequence Coverage Annotation-->
182+
<TabItem Header="Sequence Coverage" Name="SequenceCoverageAnnotationView">
183+
<Grid Grid.Row="1" Name="SequenceAnnotationGrid" SizeChanged="AnnotationSizeChanged" Style="{StaticResource InternalGridStyle}">
184+
<Grid.RowDefinitions>
185+
<RowDefinition Height = "35"></RowDefinition>
186+
<RowDefinition Height = "*"></RowDefinition>
187+
<RowDefinition Height="5"></RowDefinition>
188+
<RowDefinition Height = "30"></RowDefinition>
189+
</Grid.RowDefinitions>
190+
191+
<!--Header label-->
192+
<Label Content="Sequence Coverage Map" Grid.Row="0" />
193+
<ScrollViewer Grid.Row="1" Name="sequenceCoverageHorizontalScroll" HorizontalAlignment="Center" VerticalAlignment="Center"
194+
CanContentScroll="True" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto" Width="Auto">
195+
<Grid Name="mapGrid" Background="White">
196+
<Grid.RowDefinitions>
197+
<RowDefinition Height="160" ></RowDefinition>
198+
<RowDefinition Height=" *"></RowDefinition>
199+
</Grid.RowDefinitions>
200+
<Canvas x:Name="sequenceText" Grid.Row="0" Background="White"></Canvas>
201+
<ScrollViewer Grid.Row="1" Name="mapViewer" HorizontalAlignment="Center" VerticalAlignment="Center" Width="Auto"
202+
CanContentScroll="True" VerticalScrollBarVisibility="Auto">
203+
<Canvas x:Name="map" Background="White"></Canvas>
204+
</ScrollViewer>
205+
</Grid>
206+
</ScrollViewer>
207+
</Grid>
208+
</TabItem>
180209
</TabControl>
181210

182211
<!--Detailed PSM properties-->
@@ -281,4 +310,4 @@
281310
</TabItem>
282311
</TabControl>
283312
</Grid>
284-
</Window>
313+
</Window>

GUI/MetaDraw/MetaDraw.xaml.cs

+16-7
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ public MetaDraw()
5757
base.Closing += this.OnClosing;
5858

5959
ParentChildScanView.Visibility = Visibility.Collapsed;
60-
ParentScanView.Visibility = Visibility.Collapsed;
6160

6261
PsmStatPlotFiles = new ObservableCollection<string>();
6362
selectSourceFileListBox.DataContext = PsmStatPlotFiles;
@@ -155,20 +154,24 @@ private void dataGridScanNums_SelectedCellsChanged(object sender, SelectedCellsC
155154

156155
PsmFromTsv psm = (PsmFromTsv)dataGridScanNums.SelectedItem;
157156

158-
// draw the PSM
157+
// draw the annotated spectrum
159158
MetaDrawLogic.DisplaySpectrumMatch(plotView, canvas, psm, itemsControlSampleViewModel, out var errors);
160159

161-
if (psm.ChildScanMatchedIons != null)
160+
//draw the sequence coverage if not crosslinked
161+
if (psm.ChildScanMatchedIons == null)
162162
{
163-
ParentChildScanView.Visibility = Visibility.Visible;
164-
ParentScanView.Visibility = Visibility.Visible;
163+
MetaDrawLogic.DrawSequenceCoverageMap(psm, sequenceText, map); //TODO: figure out how to show coverage on crosslinked peptides
164+
ParentChildScanView.Visibility = Visibility.Collapsed;
165+
SequenceCoverageAnnotationView.Visibility = Visibility.Visible;
165166
}
166167
else
167168
{
168-
ParentChildScanView.Visibility = Visibility.Collapsed;
169-
ParentScanView.Visibility = Visibility.Collapsed;
169+
ParentChildScanView.Visibility = Visibility.Visible;
170+
SequenceCoverageAnnotationView.Visibility = Visibility.Collapsed;
170171
}
171172

173+
mapViewer.Width = map.Width;
174+
172175
if (errors != null && errors.Any())
173176
{
174177
MessageBox.Show(errors.First());
@@ -540,5 +543,11 @@ private void PlotViewStat_SizeChanged(object sender, SizeChangedEventArgs e)
540543
}
541544
}
542545
}
546+
547+
private void AnnotationSizeChanged(object sender, SizeChangedEventArgs e)
548+
{
549+
mapViewer.Height = .8 * SequenceAnnotationGrid.ActualHeight;
550+
mapViewer.Width = .99 * SequenceAnnotationGrid.ActualWidth;
551+
}
543552
}
544553
}

GUI/MetaDraw/PlotModelStat.cs

+6-7
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class PlotModelStat : INotifyPropertyChanged, IPlotModel
3434
private static Dictionary<ProductType, OxyColor> productTypeDrawColors = new Dictionary<ProductType, OxyColor>
3535
{
3636
{ ProductType.b, OxyColors.Blue },
37-
{ ProductType.y, OxyColors.Purple },
37+
{ ProductType.y, OxyColors.Red },
3838
{ ProductType.c, OxyColors.Gold },
3939
{ ProductType.zPlusOne, OxyColors.Orange },
4040
{ ProductType.D, OxyColors.DodgerBlue },
@@ -292,7 +292,7 @@ private void linePlot(int plotType)
292292
TrackerFormatString = "{1}: {2:0.###}\n{3}: {4:0.###}\nFull sequence: {Tag}"
293293
};
294294
List<Tuple<double, double, string>> xy = new List<Tuple<double, double, string>>();
295-
List<Tuple<double, double, string>> variantxy = new List<Tuple<double, double, string>>();
295+
List<Tuple<double, double, string>> variantxy = new List<Tuple<double, double, string>>();
296296
var filteredList = allPsms.Where(p => !p.MassDiffDa.Contains("|") && Math.Round(double.Parse(p.MassDiffDa, CultureInfo.InvariantCulture), 0) == 0).ToList();
297297
var test = allPsms.SelectMany(p => p.MatchedIons.Select(v => v.MassErrorPpm));
298298
switch (plotType)
@@ -302,7 +302,7 @@ private void linePlot(int plotType)
302302
xAxisTitle = "Retention time";
303303
foreach (var psm in filteredList)
304304
{
305-
if(psm.IdentifiedSequenceVariations == null || psm.IdentifiedSequenceVariations.Equals(""))
305+
if (psm.IdentifiedSequenceVariations == null || psm.IdentifiedSequenceVariations.Equals(""))
306306
{
307307
xy.Add(new Tuple<double, double, string>(double.Parse(psm.MassDiffPpm, CultureInfo.InvariantCulture), (double)psm.RetentionTime, psm.FullSequence));
308308
}
@@ -329,9 +329,9 @@ private void linePlot(int plotType)
329329
SSRCalc3 sSRCalc3 = new SSRCalc3("A100", SSRCalc3.Column.A100);
330330
foreach (var psm in allPsms)
331331
{
332-
if(psm.IdentifiedSequenceVariations == null || psm.IdentifiedSequenceVariations.Equals(""))
332+
if (psm.IdentifiedSequenceVariations == null || psm.IdentifiedSequenceVariations.Equals(""))
333333
{
334-
xy.Add(new Tuple<double, double, string>(sSRCalc3.ScoreSequence(new PeptideWithSetModifications(psm.BaseSeq.Split('|')[0], null)),
334+
xy.Add(new Tuple<double, double, string>(sSRCalc3.ScoreSequence(new PeptideWithSetModifications(psm.BaseSeq.Split('|')[0], null)),
335335
(double)psm.RetentionTime, psm.FullSequence));
336336
}
337337
else
@@ -400,5 +400,4 @@ public void Update(bool updateData) { }
400400
public void Render(IRenderContext rc, double width, double height) { }
401401
public void AttachPlotView(IPlotView plotView) { }
402402
}
403-
}
404-
403+
}

GUI/TaskWindows/SearchTaskWindow.xaml

+19
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,25 @@
789789
</CheckBox.ToolTip>
790790
</CheckBox>
791791
</StackPanel>
792+
<StackPanel Orientation="Horizontal" Margin="5,0,0,5">
793+
<CheckBox x:Name="InternalIonsCheckBox" Content="Internal Ions" Margin="5,0,0,5" DockPanel.Dock="Top" ToolTipService.ShowDuration="999999" ToolTipService.InitialShowDelay="500" IsChecked="False">
794+
<CheckBox.ToolTip>
795+
<TextBlock>
796+
Search for theoretical internal fragment ions AFTER scoring. These ions are useful for localizing PTMs, but are not used during scoring.
797+
</TextBlock>
798+
</CheckBox.ToolTip>
799+
</CheckBox>
800+
<Label x:Name="minInternalFragmentLengthLabel" Content="Min Internal Length:" Margin="18,-6,0,0" />
801+
<TextBox x:Name="MinInternalFragmentLengthTextBox" PreviewTextInput="CheckIfNumber" Width="45" IsEnabled="{Binding IsChecked, ElementName=InternalIonsCheckBox}" ToolTipService.ShowDuration="999999" ToolTipService.InitialShowDelay="500">
802+
<TextBox.ToolTip>
803+
<TextBlock>
804+
Minimum length (number of amino acids) allowed for an internal fragment ion.
805+
<LineBreak/>
806+
Small internal fragments can be uninformative and computationally expensive.
807+
</TextBlock>
808+
</TextBox.ToolTip>
809+
</TextBox>
810+
</StackPanel>
792811
<StackPanel Orientation="Horizontal" Margin="5">
793812
<Label x:Name="maxFragmentSize" Content="Max Fragment Mass (Da):" Width="146" />
794813
<TextBox x:Name="MaxFragmentMassTextBox" PreviewTextInput="CheckIfNumber" Width="45" IsEnabled="{Binding IsChecked, ElementName=ClassicSearchRadioButton, Converter={StaticResource InvertedBooleanConverter}}" ToolTipService.ShowDuration="999999" ToolTipService.InitialShowDelay="500">

0 commit comments

Comments
 (0)