Skip to content

Commit

Permalink
MetaDraw Fragmentation Reanalysis (#2361)
Browse files Browse the repository at this point in the history
* Started MetaDraw Researching with different fragment ions. Got the functional code of the new controls finished, just need to integtrate with the existing MetaDraw structure

* Implemented the full refragmentation system. Only issueis that I had to open up the set methods for the fragment ions in each PsmFromTsv

* Expanded test coverage

* Expanded test coverage

* Rerun Appveyor

* fixed unit test

* fixed unit test?

* maybe fixed test?

* fixed test?

* Prayed to a higher power and removed message box popup

* Broke out the meta draw fragment ion renalysis into its own control

* adjusted union operation

* Fixed ion annotaiton spacing

* fixed broken unit test

* Made the spectral library spit out new ion types

* changed ion spacing

---------

Co-authored-by: trishorts <mshort@chem.wisc.edu>
  • Loading branch information
nbollis and trishorts authored Jun 19, 2024
1 parent efa9b9d commit 9b3118c
Show file tree
Hide file tree
Showing 15 changed files with 9,272 additions and 47 deletions.
2 changes: 1 addition & 1 deletion MetaMorpheus/EngineLayer/PsmTsv/PsmFromTsv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class PsmFromTsv
public double Score { get; }
public string ProteinAccession { get; }
public double? SpectralAngle { get; }
public List<MatchedFragmentIon> MatchedIons { get; }
public List<MatchedFragmentIon> MatchedIons { get; set; }
public Dictionary<int, List<MatchedFragmentIon>> ChildScanMatchedIons { get; } // this is only used in crosslink for now, but in the future will be used for other experiment types
public double QValue { get; }

Expand Down
13 changes: 11 additions & 2 deletions MetaMorpheus/GUI/MetaDraw/MetaDraw.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@
</TabItem.Header>
<Grid Name="PsmAnnotationGrid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<!--Spectrum annotation-->
Expand Down Expand Up @@ -248,8 +249,16 @@
<!-- actual ptm legend -->
<local:PtmLegendControl x:Name="ChildScanPtmLegendControl" DataContext="{Binding}" />
</StackPanel>

</Grid>

<!-- Refragment analysis -->
<Expander Grid.Row="1" VerticalAlignment="Bottom" IsExpanded="False" x:Name="AdditionalFragmentIonDisplay"
DataContext="{x:Type guiFunctions:FragmentationReanalysisViewModel}" Header="Fragment Reanalysis">
<Expander.ToolTip>
Research the spectra file against the sequence with different fragment ions.
</Expander.ToolTip>
<local:FragmentReanalysisControl x:Name="AdditionalFragmentIonControl" DataContext="{Binding }" />
</Expander>
</Grid>
</TabItem>

Expand Down
103 changes: 87 additions & 16 deletions MetaMorpheus/GUI/MetaDraw/MetaDraw.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Easy.Common.Extensions;
using EngineLayer;
using GuiFunctions;
using MassSpectrometry;
using OxyPlot;
using System;
using System.Collections.Generic;
Expand All @@ -16,6 +17,7 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Omics.Fragmentation;

namespace MetaMorpheusGUI
{
Expand All @@ -36,6 +38,7 @@ public partial class MetaDraw : Window
private static List<string> AcceptedResultsFormats = new List<string> { ".psmtsv", ".tsv" };
private static List<string> AcceptedSpectralLibraryFormats = new List<string> { ".msp" };
private MetaDrawSettingsViewModel SettingsView;
private FragmentationReanalysisViewModel FragmentationReanalysisViewModel;

public MetaDraw()
{
Expand All @@ -52,6 +55,8 @@ public MetaDraw()

itemsControlSampleViewModel = new ParentChildScanPlotsView();
ParentChildScanViewPlots.DataContext = itemsControlSampleViewModel;
AdditionalFragmentIonControl.DataContext = FragmentationReanalysisViewModel ??= new FragmentationReanalysisViewModel();
AdditionalFragmentIonControl.LinkMetaDraw(this);

propertyView = new DataTable();
propertyView.Columns.Add("Name", typeof(string));
Expand All @@ -60,6 +65,7 @@ public MetaDraw()

dataGridScanNums.DataContext = MetaDrawLogic.PeptideSpectralMatchesView;


Title = "MetaDraw: version " + GlobalVariables.MetaMorpheusVersion;
base.Closing += this.OnClosing;

Expand All @@ -71,7 +77,7 @@ public MetaDraw()
SetUpPlots();
plotsListBox.ItemsSource = plotTypes;

exportPdfs.Content = MetaDrawSettings.ExportType; ;
exportPdfs.Content = MetaDrawSettings.ExportType;
}

private void Window_Drop(object sender, DragEventArgs e)
Expand Down Expand Up @@ -156,6 +162,9 @@ private void AddFile(string filePath)

/// <summary>
/// Event triggers when a different cell is selected in the PSM data grid
/// <remarks>
/// if sender is FragmentationReanalysisViewModel, then this method was run by clicking the search button on the FragmentationReanalysisViewModel
/// </remarks>
/// </summary>
private void dataGridScanNums_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
Expand All @@ -172,6 +181,13 @@ private void dataGridScanNums_SelectedCellsChanged(object sender, SelectedCellsC
plotView.Visibility = Visibility.Visible;
PsmFromTsv psm = (PsmFromTsv)dataGridScanNums.SelectedItem;

List<MatchedFragmentIon> oldMatchedIons = null;
if (FragmentationReanalysisViewModel.Persist && sender is DataGrid)
{
oldMatchedIons = psm.MatchedIons;
ReplaceFragmentIonsOnPsmFromFragmentReanalysisViewModel(psm);
}

// Chimera plotter
if (MetaDrawTabControl.SelectedContent is Grid { Name: "chimeraPlotGrid" })
{
Expand All @@ -197,8 +213,19 @@ private void dataGridScanNums_SelectedCellsChanged(object sender, SelectedCellsC
}

SetSequenceDrawingPositionSettings(true);
// Psm selected from ambiguous dropdown => adjust the psm to be drawn
// Clicking the research button on an ambiguous psm => research with new ions
if (psm.FullSequence.Contains('|') && (sender.ToString() == "System.Object" || sender is FragmentationReanalysisViewModel))
{
psm = (PsmFromTsv)AmbiguousSequenceOptionBox.SelectedItem;
if (FragmentationReanalysisViewModel.Persist || sender is FragmentationReanalysisViewModel)
{
oldMatchedIons = psm.MatchedIons;
ReplaceFragmentIonsOnPsmFromFragmentReanalysisViewModel(psm);
}
}
// Selection of ambiguous psm => clean up the canvases and show the option box
if (psm.FullSequence.Contains('|') && sender.ToString() != "System.Object")
else if(psm.FullSequence.Contains('|') && sender.ToString() != "System.Object")
{
// clear all drawings of the previous non-ambiguous psm
ClearPresentationArea();
Expand All @@ -215,12 +242,8 @@ private void dataGridScanNums_SelectedCellsChanged(object sender, SelectedCellsC
}
return;
}
// Psm selected from ambiguous dropdown => adjust the psm to be drawn
else if (psm.FullSequence.Contains('|') && sender.ToString() == "System.Object")
{
psm = (PsmFromTsv)AmbiguousSequenceOptionBox.SelectedItem;
}
// Selection of non-ambiguous psm => clear items in the drop down

// Selection of non-ambiguous psm => clear psms in the drop down
else if (!psm.FullSequence.Contains('|'))
{
AmbiguousSequenceOptionBox.Items.Clear();
Expand Down Expand Up @@ -307,6 +330,10 @@ private void dataGridScanNums_SelectedCellsChanged(object sender, SelectedCellsC
propertyView.Rows.Add(temp[i].Name, temp[i].GetValue(psm, null));
}
}

// put the original ions back in place if they were altered
if (oldMatchedIons != null && !psm.MatchedIons.SequenceEqual(oldMatchedIons))
psm.MatchedIons = oldMatchedIons;
}

private void selectSpectraFileButton_Click(object sender, RoutedEventArgs e)
Expand Down Expand Up @@ -587,12 +614,12 @@ private void ExportSpectrumLibraryButton_Click(object sender, RoutedEventArgs e)
return;
}

List<PsmFromTsv> items = new List<PsmFromTsv>();
List<PsmFromTsv> psms = new List<PsmFromTsv>();

foreach (var cell in dataGridScanNums.SelectedItems)
{
var psm = (PsmFromTsv)cell;
items.Add(psm);
psms.Add(psm);
}

string directoryPath = Path.Combine(Path.GetDirectoryName(MetaDrawLogic.PsmResultFilePaths.First()),
Expand All @@ -604,12 +631,21 @@ private void ExportSpectrumLibraryButton_Click(object sender, RoutedEventArgs e)
Directory.CreateDirectory(directoryPath);
}

directoryPath = Path.Combine(directoryPath, "spectrumLibrary.msp");

File.WriteAllLines(directoryPath, items.Select(i => i.ToLibrarySpectrum().ToString()).ToArray());

MessageBox.Show(MetaDrawSettings.ExportType + "(s) exported to: " + directoryPath);
var libraryPath = Path.Combine(directoryPath, "spectrumLibrary.msp");

// research all identifications with the newly matched ion types
using (var sw = new StreamWriter(File.Create(libraryPath)))
{
foreach (var psm in psms)
{
var oldIons = psm.MatchedIons;
ReplaceFragmentIonsOnPsmFromFragmentReanalysisViewModel(psm);
sw.WriteLine(psm.ToLibrarySpectrum().ToString());
psm.MatchedIons = oldIons;
}
}

MessageBox.Show("Spectral Library exported to: " + libraryPath);
}

private void SequenceCoverageExportButton_Click(object sender, RoutedEventArgs e)
Expand Down Expand Up @@ -990,6 +1026,9 @@ private void MetaDrawTabControl_OnSelectionChanged(object sender, SelectionChang
{
PsmFromTsv selectedPsm = (PsmFromTsv)dataGridScanNums.SelectedItem;

if (e.OriginalSource is not TabControl) // only clicking on different MetaDrawTabs will trigger this event
return;

// switch from chimera to other views
if (e.RemovedItems.Count > 0 && ((TabItem)e.RemovedItems[0]).Name == "ChimeraScanPlot")
{
Expand Down Expand Up @@ -1056,6 +1095,38 @@ private void ToggleButtonsEnabled(bool value)
exportSpectrumLibrary.IsEnabled = value;
}


/// <summary>
/// Method to fire the plotting method with new fragment ions
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
internal void SearchWithNewIons_OnClick(object sender, RoutedEventArgs e)
{
// find currently selected psm
var psm = dataGridScanNums.SelectedItem as PsmFromTsv;
if (psm is null)
return;

// replace the ions and replot
var oldIons = psm.MatchedIons;
ReplaceFragmentIonsOnPsmFromFragmentReanalysisViewModel(psm);
dataGridScanNums.SelectedItem = psm;
dataGridScanNums_SelectedCellsChanged(FragmentationReanalysisViewModel, null);

// put the old ions back
psm.MatchedIons = oldIons;
}

/// <summary>
/// Replaces matched fragment ions on a psm with new ion types after a quick search
/// </summary>
/// <param name="psm"></param>
private void ReplaceFragmentIonsOnPsmFromFragmentReanalysisViewModel(PsmFromTsv psm)
{
var scan = MetaDrawLogic.GetMs2ScanFromPsm(psm);
var newIons = FragmentationReanalysisViewModel.MatchIonsWithNewTypes(scan, psm);
psm.MatchedIons = newIons;
}
}
}
70 changes: 70 additions & 0 deletions MetaMorpheus/GUI/Views/FragmentReanalysisControl.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<UserControl x:Class="MetaMorpheusGUI.FragmentReanalysisControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MetaMorpheusGUI"
xmlns:guiFunctions="clr-namespace:GuiFunctions;assembly=GuiFunctions"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid d:DataContext="{x:Type guiFunctions:FragmentationReanalysisViewModel}" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<!-- All options in the header -->
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<Button Grid.Row="0" Grid.Column="0" x:Name="SearchButton" Grid.RowSpan="2" Content="Search" VerticalAlignment="Center" Margin="5 3"
VerticalContentAlignment="Center" Click="SearchWithNewIons_OnClick"/>
<CheckBox Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Content="Persist?" VerticalAlignment="Center"
IsChecked="{Binding Persist}"
Margin="5 3" ToolTip="Research each identification as they are selected"/>

<StackPanel Grid.Row="0" Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="Set Dissociation Type: " VerticalAlignment="Center"/>
<ComboBox x:Name="DissociationTypeComboBox" ItemsSource="{Binding DissociationTypes}"
SelectedItem="{Binding SelectedDissociationType}"
Margin="5 3" VerticalContentAlignment="Center" Width="80" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Center">
<CheckBox Content="Use internal ions of minimum length " IsChecked="{Binding UseInternalIons}"
HorizontalContentAlignment="Right" VerticalAlignment="Center" />
<local:IntegerTexBoxControl Text="{Binding MinInternalIonLength, FallbackValue=10}"
HorizontalAlignment="Center" HorizontalContentAlignment="Center" IsEnabled="{Binding UseInternalIons}"
VerticalAlignment="Center" VerticalContentAlignment="Center" BorderThickness="1" />
</StackPanel>
</Grid>

<!-- Fragment ion type display -->
<ListView Grid.Row="1" Grid.Column="0" Background="{StaticResource BackgroundColor}"
ItemsSource="{Binding PossibleProducts}" BorderThickness="0">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Use}" />
<TextBlock Text="{Binding TypeString}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="6"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</Grid>
</UserControl>
39 changes: 39 additions & 0 deletions MetaMorpheus/GUI/Views/FragmentReanalysisControl.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace MetaMorpheusGUI
{
/// <summary>
/// Interaction logic for FragmentReanalysisControl.xaml
/// </summary>
public partial class FragmentReanalysisControl : UserControl
{
private MetaDraw parent;
public FragmentReanalysisControl()
{
InitializeComponent();
}

internal void LinkMetaDraw(MetaDraw metaDraw)
{
parent = metaDraw;
}

private void SearchWithNewIons_OnClick(object sender, RoutedEventArgs e)
{
parent.SearchWithNewIons_OnClick(sender, e);
}
}
}
2 changes: 1 addition & 1 deletion MetaMorpheus/GuiFunctions/MetaDraw/DrawnSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public void AnnotateBaseSequence(string baseSequence, string fullSequence, int y
residue = ion.NeutralTheoreticalProduct.AminoAcidPosition;
}

double x = residue * MetaDrawSettings.AnnotatedSequenceTextSpacing + 11;
double x = residue * MetaDrawSettings.AnnotatedSequenceTextSpacing + 11 + MetaDrawSettings.ProductTypeToXOffset[ion.NeutralTheoreticalProduct.ProductType];
double y = yLoc + MetaDrawSettings.ProductTypeToYOffset[ion.NeutralTheoreticalProduct.ProductType];

if (ion.NeutralTheoreticalProduct.Terminus == FragmentationTerminus.C)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Omics.Fragmentation;

namespace GuiFunctions
{
public class FragmentViewModel : BaseViewModel
{
public ProductType ProductType { get; }
public string TypeString => ProductType.ToString();
private bool use;

public bool Use
{
get => use;
set { use = value; OnPropertyChanged(nameof(Use)); }
}

public FragmentViewModel(bool use, ProductType type)
{
Use = use;
ProductType = type;
}
}
}
Loading

0 comments on commit 9b3118c

Please sign in to comment.