public void DisplaySpectrumMatch(PlotView plotView, Canvas canvas, PsmFromTsv psm, ParentChildScanPlotsView parentChildScanPlotsView, out List <string> errors) { errors = null; // clear old parent/child scans parentChildScanPlotsView.Plots.Clear(); CurrentlyDisplayedPlots.Clear(); // get the scan if (!MsDataFiles.TryGetValue(psm.FileNameWithoutExtension, out DynamicDataConnection spectraFile)) { errors = new List <string>(); errors.Add("The spectra file could not be found for this PSM: " + psm.FileNameWithoutExtension); return; } MsDataScan scan = spectraFile.GetOneBasedScanFromDynamicConnection(psm.Ms2ScanNumber); LibrarySpectrum librarySpectrum = null; // plot the annotated spectrum match PeptideSpectrumMatchPlot plot; //if not crosslinked if (psm.BetaPeptideBaseSequence == null) { // get the library spectrum if relevant if (SpectralLibrary != null) { SpectralLibrary.TryGetSpectrum(psm.FullSequence, psm.PrecursorCharge, out var librarySpectrum1); librarySpectrum = librarySpectrum1; } plot = new PeptideSpectrumMatchPlot(plotView, canvas, psm, scan, psm.MatchedIons, librarySpectrum: librarySpectrum); } else //crosslinked { plot = new CrosslinkSpectrumMatchPlot(plotView, canvas, psm, scan); } CurrentlyDisplayedPlots.Add(plot); // plot parent/child scans if (psm.ChildScanMatchedIons != null) { // draw parent scan string parentAnnotation = "Scan: " + scan.OneBasedScanNumber + " Dissociation Type: " + scan.DissociationType + " MsOrder: " + scan.MsnOrder + " Selected Mz: " + scan.SelectedIonMZ.Value.ToString("0.##") + " Retention Time: " + scan.RetentionTime.ToString("0.##"); var parentPlotView = new PlotView(); // placeholder var parentCanvas = new Canvas(); var item = new ParentChildScanPlotTemplate() { Plot = new PeptideSpectrumMatchPlot(parentPlotView, parentCanvas, psm, scan, psm.MatchedIons), SpectrumLabel = parentAnnotation, TheCanvas = parentCanvas }; parentChildScanPlotsView.Plots.Add(item); // remove model from placeholder (the model can only be referenced by 1 plotview at a time) parentPlotView.Model = null; // draw child scans HashSet <int> scansDrawn = new HashSet <int>(); var allChildScanMatchedIons = psm.ChildScanMatchedIons; if (psm.BetaPeptideChildScanMatchedIons != null) { allChildScanMatchedIons = allChildScanMatchedIons.Concat(psm.BetaPeptideChildScanMatchedIons) .GroupBy(p => p.Key) .ToDictionary(p => p.Key, q => q.SelectMany(p => p.Value).ToList()); } foreach (var childScanMatchedIons in allChildScanMatchedIons) { int childScanNumber = childScanMatchedIons.Key; if (scansDrawn.Contains(childScanNumber)) { continue; } scansDrawn.Add(childScanNumber); List <MatchedFragmentIon> matchedIons = childScanMatchedIons.Value; MsDataScan childScan = spectraFile.GetOneBasedScanFromDynamicConnection(childScanNumber); string childAnnotation = "Scan: " + childScan.OneBasedScanNumber + " Dissociation Type: " + childScan.DissociationType + " MsOrder: " + childScan.MsnOrder + " Selected Mz: " + childScan.SelectedIonMZ.Value.ToString("0.##") + " RetentionTime: " + childScan.RetentionTime.ToString("0.##"); Canvas childCanvas = new Canvas(); PlotView childPlotView = new PlotView(); // placeholder // make the plot var childPlot = new PeptideSpectrumMatchPlot(childPlotView, childCanvas, psm, childScan, matchedIons, annotateProperties: false); childPlot.Model.Title = null; childPlot.Model.Subtitle = null; item = new ParentChildScanPlotTemplate() { Plot = childPlot, SpectrumLabel = childAnnotation, TheCanvas = childCanvas }; // remove model from placeholder (the model can only be referenced by 1 plotview at a time) childPlotView.Model = null; parentChildScanPlotsView.Plots.Add(item); CurrentlyDisplayedPlots.Add(childPlot); } } }
//draw the sequence coverage map: write out the sequence, overlay modifications, and display matched fragments public void DrawSequenceCoverageMap(PsmFromTsv psm, Canvas sequenceText, Canvas map) { map.Children.Clear(); sequenceText.Children.Clear(); int spacing = 20; const int textHeight = 140; const int heightIncrement = 5; const int xShift = 10; int peptideLength = psm.BaseSeq.Length; //intensity arrays for each ion type double[] nIntensityArray = new double[peptideLength - 1]; double[] cIntensityArray = new double[peptideLength - 1]; double[] internalIntensityArray = new double[peptideLength - 1]; //colors for annotation Color nColor = Colors.Blue; Color cColor = Colors.Red; Color internalColor = Colors.Purple; //draw sequence text for (int r = 0; r < psm.BaseSeq.Length; r++) { TextDrawing(sequenceText, new Point(r * spacing + xShift, textHeight - 30), (r + 1).ToString(), Brushes.Black, 8); TextDrawing(sequenceText, new Point(r * spacing + xShift, textHeight - 15), (psm.BaseSeq.Length - r).ToString(), Brushes.Black, 8); TextDrawing(sequenceText, new Point(r * spacing + xShift, textHeight), psm.BaseSeq[r].ToString(), Brushes.Black, 16); } //create circles for mods, if needed and able if (!psm.FullSequence.Contains("|")) //can't draw mods if not localized/identified { PeptideSpectrumMatchPlot.AnnotateModifications(psm, sequenceText, psm.FullSequence, textHeight - 4, spacing, xShift + 5); } //draw lines for each matched fragment List <bool[]> index = new List <bool[]>(); //N-terminal List <MatchedFragmentIon> nTermFragments = psm.MatchedIons.Where(x => x.NeutralTheoreticalProduct.Terminus == FragmentationTerminus.N).ToList(); //C-terminal in reverse order List <MatchedFragmentIon> cTermFragments = psm.MatchedIons.Where(x => x.NeutralTheoreticalProduct.Terminus == FragmentationTerminus.C).OrderByDescending(x => x.NeutralTheoreticalProduct.FragmentNumber).ToList(); //add internal fragments List <MatchedFragmentIon> internalFragments = psm.MatchedIons.Where(x => x.NeutralTheoreticalProduct.SecondaryProductType != null).OrderBy(x => x.NeutralTheoreticalProduct.FragmentNumber).ToList(); //indexes to navigate terminal ions int n = 0; int c = 0; int heightForThisFragment = 70; //location to draw a fragment //line up terminal fragments so that complementary ions are paired on the same line while (n < nTermFragments.Count && c < cTermFragments.Count) { MatchedFragmentIon nProduct = nTermFragments[n]; MatchedFragmentIon cProduct = cTermFragments[c]; int expectedComplementary = peptideLength - nProduct.NeutralTheoreticalProduct.FragmentNumber; //if complementary pair if (cProduct.NeutralTheoreticalProduct.FragmentNumber == expectedComplementary) { //plot sequences DrawHorizontalLine(0, nProduct.NeutralTheoreticalProduct.FragmentNumber, map, heightForThisFragment, nColor, spacing); DrawHorizontalLine(peptideLength - cProduct.NeutralTheoreticalProduct.FragmentNumber, peptideLength, map, heightForThisFragment, cColor, spacing); //record intensities nIntensityArray[nProduct.NeutralTheoreticalProduct.FragmentNumber - 1] += nProduct.Intensity; cIntensityArray[peptideLength - cProduct.NeutralTheoreticalProduct.FragmentNumber - 1] += cProduct.Intensity; //increment indexes n++; c++; } //if n-terminal ion is present without complementary else if (cProduct.NeutralTheoreticalProduct.FragmentNumber < expectedComplementary) { DrawHorizontalLine(0, nProduct.NeutralTheoreticalProduct.FragmentNumber, map, heightForThisFragment, nColor, spacing); nIntensityArray[nProduct.NeutralTheoreticalProduct.FragmentNumber - 1] += nProduct.Intensity; n++; } //if c-terminal ion is present without complementary else { DrawHorizontalLine(peptideLength - cProduct.NeutralTheoreticalProduct.FragmentNumber, peptideLength, map, heightForThisFragment, cColor, spacing); cIntensityArray[peptideLength - cProduct.NeutralTheoreticalProduct.FragmentNumber - 1] += cProduct.Intensity; c++; } heightForThisFragment += heightIncrement; } //wrap up leftover fragments without complementary pairs for (; n < nTermFragments.Count; n++) { MatchedFragmentIon nProduct = nTermFragments[n]; DrawHorizontalLine(0, nProduct.NeutralTheoreticalProduct.FragmentNumber, map, heightForThisFragment, nColor, spacing); nIntensityArray[nProduct.NeutralTheoreticalProduct.FragmentNumber - 1] += nProduct.Intensity; heightForThisFragment += heightIncrement; } for (; c < cTermFragments.Count; c++) { MatchedFragmentIon cProduct = cTermFragments[c]; DrawHorizontalLine(peptideLength - cProduct.NeutralTheoreticalProduct.FragmentNumber, peptideLength, map, heightForThisFragment, cColor, spacing); cIntensityArray[peptideLength - cProduct.NeutralTheoreticalProduct.FragmentNumber - 1] += cProduct.Intensity; heightForThisFragment += heightIncrement; } //internal fragments foreach (MatchedFragmentIon fragment in internalFragments) { DrawHorizontalLine(fragment.NeutralTheoreticalProduct.FragmentNumber, fragment.NeutralTheoreticalProduct.SecondaryFragmentNumber, map, heightForThisFragment, internalColor, spacing); internalIntensityArray[fragment.NeutralTheoreticalProduct.FragmentNumber - 1] += fragment.Intensity; internalIntensityArray[fragment.NeutralTheoreticalProduct.SecondaryFragmentNumber - 1] += fragment.Intensity; heightForThisFragment += heightIncrement; } map.Height = heightForThisFragment + 100; map.Width = spacing * psm.BaseSeq.Length + 100; sequenceText.Width = spacing * psm.BaseSeq.Length + 100; ////PLOT INTENSITY HISTOGRAM//// double[] intensityArray = new double[peptideLength - 1]; for (int i = 0; i < intensityArray.Length; i++) { intensityArray[i] = nIntensityArray[i] + cIntensityArray[i] + internalIntensityArray[i]; } double maxIntensity = intensityArray.Max(); //foreach cleavage site for (int i = 0; i < intensityArray.Length; i++) { //if anything if (intensityArray[i] > 0) { int x = (i + 1) * spacing + 7; //n-terminal int nY = 100 - (int)Math.Round(nIntensityArray[i] * 100 / maxIntensity, 0); if (nY != 100) { DrawVerticalLine(104, nY + 4, sequenceText, (i + 1) * spacing + 5, nColor); } //c-terminal int cY = nY - (int)Math.Round(cIntensityArray[i] * 100 / maxIntensity, 0); if (nY != cY) { DrawVerticalLine(nY + 2, cY + 2, sequenceText, (i + 1) * spacing + 5, cColor); } //internal int iY = cY - (int)Math.Round(internalIntensityArray[i] * 100 / maxIntensity, 0); if (cY != iY) { DrawVerticalLine(cY, iY, sequenceText, (i + 1) * spacing + 5, internalColor); } } } }