///<summary>Adds user requested ion series to the fragmentation summary.</summary> private void addFragmentationSummary (GraphObjList list, pwiz.MSGraph.MSPointList points, Peptide peptide, Fragmentation fragmentation, string topSeries, string bottomSeries) { int ionSeriesChargeState = min; string sequence = peptide.sequence; ModificationMap modifications = peptide.modifications(); // Select the color for the ion series. Color topSeriesColor; Color bottomSeriesColor; switch (topSeries) { default: topSeriesColor = Color.Gray; break; case "a": topSeriesColor = Color.YellowGreen; break; case "b": topSeriesColor = Color.BlueViolet; break; case "c": topSeriesColor = Color.Orange; break; } switch (bottomSeries) { default: bottomSeriesColor = Color.Gray; break; case "x": bottomSeriesColor = Color.Green; break; case "y": bottomSeriesColor = Color.Blue; break; case "z": bottomSeriesColor = Color.OrangeRed; break; case "z*": bottomSeriesColor = Color.Crimson; break; } // Ion series offsets. These offsets control where on the chart a particular ion series get displayed double seriesTopLeftOffset = 0.2; // Set the constants for starting the label paint double topSeriesLeftPoint = 0.025; double residueWidth = 0.5 / ((double) sequence.Length); double topSeriesRightPoint = topSeriesLeftPoint + 0.5 - residueWidth; double tickStart = residueWidth / 2.0; // Process all the series except c and x for (int i = 1; i <= sequence.Length; ++i) { double topSeriesFragmentMZ = 0.0; double bottomSeriesFragmentMZ = 0.0; switch (topSeries) { case "a": topSeriesFragmentMZ = fragmentation.a(i, ionSeriesChargeState); break; case "b": topSeriesFragmentMZ = fragmentation.b(i, ionSeriesChargeState); break; case "c": if (i < sequence.Length) topSeriesFragmentMZ = fragmentation.c(i, ionSeriesChargeState); break; default: continue; } switch (bottomSeries) { case "x": if (i < sequence.Length) bottomSeriesFragmentMZ = fragmentation.x(i, ionSeriesChargeState); break; case "y": bottomSeriesFragmentMZ = fragmentation.y(i, ionSeriesChargeState); break; case "z": bottomSeriesFragmentMZ = fragmentation.z(i, ionSeriesChargeState); break; case "z*": bottomSeriesFragmentMZ = fragmentation.zRadical(i, ionSeriesChargeState); break; default: continue; } // Check if the top and bottom fragments have evidence bool topSeriesHasMatch = false; bool bottomSeriesHasMatch = false; if (points != null) { topSeriesHasMatch = topSeriesFragmentMZ > 0 && findPointWithTolerance(points, topSeriesFragmentMZ, tolerance) > -1; bottomSeriesHasMatch = bottomSeriesFragmentMZ > 0 && findPointWithTolerance(points, bottomSeriesFragmentMZ, tolerance) > -1; } // Build the label for the amino acid // Add a text box in the middle of the left and right mz boundaries StringBuilder label = new StringBuilder(sequence[i - 1].ToString()); // Figure out if any mods are there on this amino acid double deltaMass = modifications[i - 1].monoisotopicDeltaMass(); // Round the mod mass and append it to the amino acid as a string if (deltaMass > 0.0) { label.Append("+" + Math.Round(deltaMass)); } else if (deltaMass < 0.0) { label.Append(Math.Round(deltaMass)); } TextObj text = new TextObj(label.ToString(), topSeriesLeftPoint, seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Center, AlignV.Center); text.ZOrder = ZOrder.A_InFront; text.FontSpec = new FontSpec("Arial", 13, Color.Black, true, false, false); text.FontSpec.Border.IsVisible = false; text.FontSpec.Fill.Color = Color.White; text.IsClippedToChartRect = false; list.Add(text); if (topSeriesHasMatch) { // Paint the tick in the middle LineObj tick = new LineObj(topSeriesColor, topSeriesLeftPoint + tickStart, (seriesTopLeftOffset - 0.05), topSeriesLeftPoint + tickStart, seriesTopLeftOffset); tick.Location.CoordinateFrame = CoordType.ChartFraction; tick.Line.Width = 2; tick.IsClippedToChartRect = true; list.Add(tick); // Paint the hook LineObj hook = new LineObj(topSeriesColor, topSeriesLeftPoint, (seriesTopLeftOffset - 0.08), topSeriesLeftPoint + tickStart, seriesTopLeftOffset - 0.05); hook.Location.CoordinateFrame = CoordType.ChartFraction; hook.Line.Width = 2; hook.IsClippedToChartRect = true; list.Add(hook); } if (bottomSeriesHasMatch) { // Paint the tick in the middle LineObj tick = new LineObj(bottomSeriesColor, topSeriesRightPoint + tickStart, seriesTopLeftOffset, topSeriesRightPoint + tickStart, seriesTopLeftOffset + 0.05); tick.Location.CoordinateFrame = CoordType.ChartFraction; tick.Line.Width = 2; tick.IsClippedToChartRect = true; list.Add(tick); // Paint the hook LineObj hook = new LineObj(bottomSeriesColor, topSeriesRightPoint + tickStart, seriesTopLeftOffset + 0.05, topSeriesRightPoint + 2.0 * tickStart, seriesTopLeftOffset + 0.08); hook.Location.CoordinateFrame = CoordType.ChartFraction; hook.Line.Width = 2; hook.IsClippedToChartRect = true; list.Add(hook); } // Update the next paint point topSeriesLeftPoint += residueWidth; topSeriesRightPoint -= residueWidth; } }
///<summary>Adds user requested ion series on top of the chart.</summary> private void addIonSeries (GraphObjList list, pwiz.MSGraph.MSPointList points, Peptide peptide, Fragmentation fragmentation, string topSeries, string bottomSeries) { int ionSeriesChargeState = min; string sequence = peptide.sequence; ModificationMap modifications = peptide.modifications(); // Select the color for the ion series. Color topSeriesColor; Color bottomSeriesColor; switch (topSeries) { default: topSeriesColor = Color.Gray; break; case "a": topSeriesColor = Color.YellowGreen; break; case "b": topSeriesColor = Color.BlueViolet; break; case "c": topSeriesColor = Color.Orange; break; } switch (bottomSeries) { default: bottomSeriesColor = Color.Gray; break; case "x": bottomSeriesColor = Color.Green; break; case "y": bottomSeriesColor = Color.Blue; break; case "z": bottomSeriesColor = Color.OrangeRed; break; case "z*": bottomSeriesColor = Color.Crimson; break; } // Ion series offsets. These offsets control where on the chart a particular ion series // get displayed double topSeriesOffset = 0.025; double bottomSeriesOffset = 0.1; if (topSeries.Length == 0) bottomSeriesOffset = topSeriesOffset; double topSeriesLeftPoint = 0.0; double bottomSeriesLeftPoint = 0.0; // Step through each fragmentation site for (int i = 1; i <= sequence.Length; ++i) { // Paint the top series first double rightPoint = 0.0; // Figure out the right mz for this fragmentaion site switch (topSeries) { case "a": rightPoint = fragmentation.a(i, ionSeriesChargeState); break; case "b": rightPoint = fragmentation.b(i, ionSeriesChargeState); break; case "c": if (i < sequence.Length) rightPoint = fragmentation.c(i, ionSeriesChargeState); break; default: continue; } // If the left mz and right mz are different if (rightPoint > 0 && topSeriesLeftPoint != rightPoint) { LineObj line; // Use a dashed line format if there are fragment ions supporting this // amino acid if (!aminoAcidHasFragmentEvidence(points, topSeriesLeftPoint, rightPoint)) { // Draw the line from previous mz to site to this mz in trasparent color. line = new LineObj(Color.FromArgb(115, topSeriesColor), topSeriesLeftPoint, topSeriesOffset, rightPoint, topSeriesOffset); line.Line.Style = System.Drawing.Drawing2D.DashStyle.Dash; } else { // Draw the line from previous mz to site to this mz in solid color. line = new LineObj(topSeriesColor, topSeriesLeftPoint, topSeriesOffset, rightPoint, topSeriesOffset); } line.Location.CoordinateFrame = CoordType.XScaleYChartFraction; line.Line.Width = 2; line.ZOrder = ZOrder.F_BehindGrid; line.IsClippedToChartRect = true; list.Add(line); // Add a tick demarking the fragmentation site. LineObj tick = new LineObj(topSeriesColor, rightPoint, (topSeriesOffset - 0.015), rightPoint, (topSeriesOffset + 0.015)); tick.Location.CoordinateFrame = CoordType.XScaleYChartFraction; tick.Line.Width = 2; tick.IsClippedToChartRect = true; list.Add(tick); // Add a text box in the middle of the left and right mz boundaries StringBuilder label = new StringBuilder(sequence[i - 1].ToString()); // Figure out if any mods are there on this amino acid double deltaMass = modifications[i - 1].monoisotopicDeltaMass(); // Round the mod mass and append it to the amino acid as a string if (deltaMass > 0.0) { label.Append("+" + Math.Round(deltaMass)); } else if (deltaMass < 0.0) { label.Append(Math.Round(deltaMass)); } TextObj text = new TextObj(label.ToString(), (topSeriesLeftPoint + rightPoint) / 2.0, topSeriesOffset, CoordType.XScaleYChartFraction, AlignH.Center, AlignV.Center); text.ZOrder = ZOrder.A_InFront; text.FontSpec = new FontSpec("Arial", 13, Color.Black, true, false, false); text.FontSpec.Border.IsVisible = false; text.FontSpec.Fill.Color = Color.White; text.IsClippedToChartRect = true; list.Add(text); topSeriesLeftPoint = rightPoint; } // Time to paint the bottom series // Get the right mz for this series switch (bottomSeries) { case "x": if (i < sequence.Length) rightPoint = fragmentation.x(i, ionSeriesChargeState); break; case "y": rightPoint = fragmentation.y(i, ionSeriesChargeState); break; case "z": rightPoint = fragmentation.z(i, ionSeriesChargeState); break; case "z*": rightPoint = fragmentation.zRadical(i, ionSeriesChargeState); break; default: rightPoint = 0.0; break; } // If the left and right mz are different if (rightPoint > 0 && bottomSeriesLeftPoint != rightPoint) { LineObj line; // Use a dashed line format if there are fragment ions supporting this // amino acid if (!aminoAcidHasFragmentEvidence(points, bottomSeriesLeftPoint, rightPoint)) { // Draw the line from previous mz to site to this mz in trasparent color. line = new LineObj(Color.FromArgb(115, bottomSeriesColor), bottomSeriesLeftPoint, bottomSeriesOffset, rightPoint, bottomSeriesOffset); line.Line.Style = System.Drawing.Drawing2D.DashStyle.Dash; } else { // Draw the line from previous mz to site to this mz in solid color. line = new LineObj(bottomSeriesColor, bottomSeriesLeftPoint, bottomSeriesOffset, rightPoint, bottomSeriesOffset); } line.Location.CoordinateFrame = CoordType.XScaleYChartFraction; line.Line.Width = 2; line.ZOrder = ZOrder.F_BehindGrid; line.IsClippedToChartRect = true; list.Add(line); // Draw a tick mark demarking the fragmentation site LineObj tick = new LineObj(bottomSeriesColor, rightPoint, (bottomSeriesOffset - 0.015), rightPoint, (bottomSeriesOffset + 0.015)); tick.Location.CoordinateFrame = CoordType.XScaleYChartFraction; tick.Line.Width = 2; tick.IsClippedToChartRect = true; list.Add(tick); // Add the text label containing the amino acid StringBuilder label = new StringBuilder(sequence[sequence.Length - i].ToString()); // Figure out if any mods are there on this amino acid double deltaMass = modifications[sequence.Length - i].monoisotopicDeltaMass(); // Round the mod mass and append it to the amino acid as a string if (deltaMass > 0.0) { label.Append("+" + Math.Round(deltaMass)); } else if (deltaMass < 0.0) { label.Append(Math.Round(deltaMass)); } TextObj text = new TextObj(label.ToString(), (bottomSeriesLeftPoint + rightPoint) / 2.0, bottomSeriesOffset, CoordType.XScaleYChartFraction, AlignH.Center, AlignV.Center); text.ZOrder = ZOrder.A_InFront; text.FontSpec = new FontSpec("Arial", 13, Color.Black, true, false, false); text.FontSpec.Border.IsVisible = false; text.FontSpec.Fill.Color = Color.White; text.IsClippedToChartRect = true; list.Add(text); bottomSeriesLeftPoint = rightPoint; } } }
///<summary>Adds user requested ion series to the fragmentation summary.</summary> private void addFragmentationSummary(GraphObjList list, pwiz.MSGraph.MSPointList points, Peptide peptide, Fragmentation fragmentation, string topSeries, string bottomSeries) { ///cutoff definition for neutral loss double basePeakIntensity = 0; double cutoff = 0; foreach (var pointlist in points) { if (basePeakIntensity < pointlist.Y) basePeakIntensity = pointlist.Y; } cutoff = basePeakIntensity * basePeakPercentage * 0.01; /// int ionSeriesChargeState = min; string sequence = peptide.sequence; int sequenceLength = peptide.sequence.Length; ModificationMap modifications = peptide.modifications(); // Select the color for the ion series. Color topSeriesColor; Color bottomSeriesColor; switch (topSeries) { default: topSeriesColor = Color.Gray; break; case "a": topSeriesColor = Color.YellowGreen; break; case "b": topSeriesColor = Color.Red; break; case "c": topSeriesColor = Color.Orange; break; } switch (bottomSeries) { default: bottomSeriesColor = Color.Gray; break; case "x": bottomSeriesColor = Color.Green; break; case "y": bottomSeriesColor = Color.Blue; break; case "z": bottomSeriesColor = Color.OrangeRed; break; case "z*": bottomSeriesColor = Color.Crimson; break; } // Ion series offsets. These offsets control where on the chart a particular ion series // get displayed //change the seriesTopLeftOffset value to 0.1 to make the label higher in the image. //original is 0.031 double seriesTopLeftOffset = 0.05; // Set the constants for starting the label paint double topSeriesLeftPoint = 0.025; //test and looks reasonalbe double residueWidth = 0.031; //double residueWidth = 0.25 / ((double)sequence.Length); // Process all the series except c and x //small block modified //here is a big bug: if go like orignal code, then the y ions is just the like the order of b ions, which are not right. //My modification is to seperate a/b/c and x/y/z ions, and then it will solve this problem. //it seems works well. /// #region Process a/b ions //first we are going to touch only a/b ions /// for (int i = 1; i <= sequence.Length; ++i) { double tickStart = residueWidth * 4 / 5.0; double topSeriesFragmentMZ = 0.0; //test neutral loss //this block is to give clear clue for phospate loss //exact number of phosphated amino acids are counted. string Nseq = peptide.sequence.Substring(0, i); char[] Nseqchars = Nseq.ToCharArray(); int Nphosmodi = 0; for (int k = 0; k < i; k++) { if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (Nseqchars[k] == 'S' || Nseqchars[k] == 'T' || Nseqchars[k] == 'Y')) { Nphosmodi++; } } //correct the bug: //when multiple charges allowed for fragmentation, then there is no tick thing showing the existance of the fragment //what I did is: make top/bottomSeriesHasMatch true if there is fragment of any charges matched. //bug fixed bool topSeriesHasMatch = false; for (int z = min; z <= max; z++) { switch (topSeries) { case "a": topSeriesFragmentMZ = fragmentation.a(i, z); break; case "b": topSeriesFragmentMZ = fragmentation.b(i, z); break; default: topSeriesFragmentMZ = 0.0; break; } // Check if the top and bottom fragments have evidence if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(topSeriesFragmentMZ - 0.5); if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ + 0.5)) { topSeriesHasMatch = true; break; } } //test neutral loss #region water loss a/b top series if (waterLoss == true) { if (Nseq.Contains("S") || Nseq.Contains("T") || Nseq.Contains("E") || Nseq.Contains("D")) { // Check if the top and bottom fragments have evidence if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(topSeriesFragmentMZ - WATERMONOMASS/z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - WATERMONOMASS / z + 0.5)) { topSeriesHasMatch = true; break; } } else { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - WATERMONOMASS / z + 0.5) && points.FullList[index].Y >= cutoff) { topSeriesHasMatch = true; break; } } } } } #endregion //test neutral loss #region ammonium loss a/b top series if (ammoniumLoss == true) { if (Nseq.Contains("R") || Nseq.Contains("K") || Nseq.Contains("Q") || Nseq.Contains("N")) { if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(topSeriesFragmentMZ - AMMONIUMMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5)) { topSeriesHasMatch = true; break; } } else { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) { topSeriesHasMatch = true; break; } } } } } #endregion //test neutral loss #region phosphate loss a/b top series if (phosphateLoss == true) { //need to judge qualified number of AAs; int minPhosphate = Math.Min(Nphosmodi, numPhosphate); if (minPhosphate > 0) { for (int k = 1; k <= minPhosphate; k++) { //first need to judge if there are as many as phos AAs //then if AA <= phos, then deal with AA; //if AA > phos, then deal with phos. if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5)) { topSeriesHasMatch = true; break; } } else { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) { topSeriesHasMatch = true; break; } } } } } } #endregion } // Build the label for the amino acid // Add a text box in the middle of the left and right mz boundaries StringBuilder label = new StringBuilder(sequence[i - 1].ToString()); // Figure out if any mods are there on this amino acid double deltaMass = modifications[i - 1].monoisotopicDeltaMass(); string deltaMassString = deltaMass.ToString(); TextObj text = new TextObj(label.ToString(), topSeriesLeftPoint, seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center); text.ZOrder = ZOrder.E_BehindCurves; text.FontSpec = new FontSpec("Arial", 13, Color.Black, true, false, false); text.FontSpec.Border.IsVisible = false; text.FontSpec.Fill.IsVisible = false; text.IsClippedToChartRect = true; list.Add(text); SizeF size = text.LayoutArea; float width = size.Width; if (deltaMass > 0.0) { deltaMassString = "+" + Math.Round(deltaMass).ToString(); TextObj textModi = new TextObj(deltaMassString, topSeriesLeftPoint + 0.011, seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center); textModi.ZOrder = ZOrder.A_InFront; textModi.FontSpec = new FontSpec("Arial", 8, Color.Black, true, false, false); textModi.FontSpec.Border.IsVisible = false; textModi.FontSpec.Fill.IsVisible = false ; textModi.IsClippedToChartRect = true; list.Add(textModi); } else if (deltaMass < 0.0) { deltaMassString = Math.Round(deltaMass).ToString(); TextObj textModi = new TextObj(deltaMassString, topSeriesLeftPoint + 0.01, seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center); textModi.ZOrder = ZOrder.B_BehindLegend; textModi.FontSpec = new FontSpec("Arial", 8, Color.Black, true, false, false); textModi.FontSpec.Border.IsVisible = false; textModi.FontSpec.Fill.IsVisible = false ; textModi.IsClippedToChartRect = true; list.Add(textModi); } if (topSeriesHasMatch) { // Paint the tick in the middle LineObj tick = new LineObj(topSeriesColor, topSeriesLeftPoint + tickStart, (seriesTopLeftOffset - 0.03), topSeriesLeftPoint + tickStart, seriesTopLeftOffset); tick.Location.CoordinateFrame = CoordType.ChartFraction; tick.Line.Width = 2; tick.IsClippedToChartRect = true; list.Add(tick); // Paint the hook LineObj hook = new LineObj(topSeriesColor, topSeriesLeftPoint, (seriesTopLeftOffset - 0.05), topSeriesLeftPoint + tickStart, seriesTopLeftOffset - 0.03); hook.Location.CoordinateFrame = CoordType.ChartFraction; hook.Line.Width = 2; hook.IsClippedToChartRect = true; list.Add(hook); } // Update the next paint point topSeriesLeftPoint += residueWidth; } // Reset the series starting point topSeriesLeftPoint = 0.025; #endregion /// #region Process y/z ions //then for y/z ions: //note: since the fragmentsummary starts the ticking/lining from left to right, //so we need to adjust the starting point of bottoms series from the highest to lowest. /// for (int i = sequence.Length; i >= 1; --i) { double tickStart = residueWidth / 5.0; double bottomSeriesFragmentMZ = 0.0; bool bottomSeriesHasMatch = false; //test neutral string Cseq = peptide.sequence.Substring(sequenceLength - i, i); char[] seqchars = peptide.sequence.ToCharArray(); int Cphosmodi = 0; for (int k = sequenceLength - i; k < sequenceLength; k++) { if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (seqchars[k] == 'S' || seqchars[k] == 'T' || seqchars[k] == 'Y')) { Cphosmodi++; } } for (int z = min; z <= max; z++) { switch (bottomSeries) { case "y": bottomSeriesFragmentMZ = fragmentation.y(i, z); break; case "z": bottomSeriesFragmentMZ = fragmentation.z(i, z); break; case "z*": bottomSeriesFragmentMZ = fragmentation.zRadical(i, z); break; default: bottomSeriesFragmentMZ = 0.0; break; } // Check if the top and bottom fragments have evidence if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(bottomSeriesFragmentMZ - 0.5); if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ + 0.5)) { bottomSeriesHasMatch = true; break; } } //test neutral loss #region water loss y/z bottom series if (waterLoss == true) { if (Cseq.Contains("S") || Cseq.Contains("T") || Cseq.Contains("E") || Cseq.Contains("D")) { if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(bottomSeriesFragmentMZ - WATERMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - WATERMONOMASS / z + 0.5)) { bottomSeriesHasMatch = true; break; } } else { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - WATERMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) { bottomSeriesHasMatch = true; break; } } } } } #endregion //test neutral loss #region ammonium loss y/z bottom series if (ammoniumLoss == true) { if (Cseq.Contains("R") || Cseq.Contains("K") || Cseq.Contains("Q") || Cseq.Contains("N")) if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5)) { bottomSeriesHasMatch = true; break; } } else { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) { bottomSeriesHasMatch = true; break; } } } } #endregion //test neutral loss #region phosphate loss y/z bottom series if (phosphateLoss == true) { int minPhosphate = Math.Min(Cphosmodi, numPhosphate); if (minPhosphate > 0) { for (int k = 1; k <= minPhosphate; k++) { if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5)) { bottomSeriesHasMatch = true; break; } } else { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) { bottomSeriesHasMatch = true; break; } } } } } } #endregion } if (bottomSeriesHasMatch) { // Paint the tick in the middle LineObj tick = new LineObj(bottomSeriesColor, topSeriesLeftPoint - tickStart, seriesTopLeftOffset, topSeriesLeftPoint - tickStart, seriesTopLeftOffset + 0.03); tick.Location.CoordinateFrame = CoordType.ChartFraction; tick.Line.Width = 2; tick.IsClippedToChartRect = true; list.Add(tick); // Paint the hook LineObj hook = new LineObj(bottomSeriesColor, topSeriesLeftPoint - tickStart, seriesTopLeftOffset + 0.03, topSeriesLeftPoint + 2.0 * tickStart, seriesTopLeftOffset + 0.05); hook.Location.CoordinateFrame = CoordType.ChartFraction; hook.Line.Width = 2; hook.IsClippedToChartRect = true; list.Add(hook); } // Update the next paint point topSeriesLeftPoint += residueWidth; } // Reset the series starting point topSeriesLeftPoint = 0.025; #endregion /// #region Process x/c series /// //the reason that I didn't split c/x as ab/yz, is that c/x doesn't have to deal with the termini. so good to go. //disable the function of neutral losses for (int i = 1; i < sequence.Length; ++i) { double tickStart = residueWidth *4 / 5.0; double topSeriesFragmentMZ = 0.0; double bottomSeriesFragmentMZ = 0.0; // Check if the top and bottom fragments have evidence bool topSeriesHasMatch = false; bool bottomSeriesHasMatch = false; /// //test neutral loss //test neutral //adjust the "i" accordingly, must let the C ions be left=>right. //if it goes from left to right, then N series is i; //C series is more tricky. Get a NTempSeq from 0 to sequenceLength-i; then get C from total. /// string Nseq = peptide.sequence.Substring(0, i); string NTempSeq = peptide.sequence.Substring(0, sequenceLength - i); string Cseq = peptide.sequence.Substring(i, sequenceLength-i); char[] Nseqchars = Nseq.ToCharArray(); char[] seqchars = peptide.sequence.ToCharArray(); char[] NTempSeqChars = NTempSeq.ToCharArray(); int Nphosmodi = 0; int NTempPhosmodi = 0; int Cphosmodi = 0; int phosmodi = 0; for (int k = 0; k < i; k++) { if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (Nseqchars[k] == 'S' || Nseqchars[k] == 'T' || Nseqchars[k] == 'Y')) { Nphosmodi++; } } for (int k = 0; k < sequenceLength - i; k++) { if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (NTempSeqChars[k] == 'S' || NTempSeqChars[k] == 'T' || NTempSeqChars[k] == 'Y')) { NTempPhosmodi++; } } for (int k = 0; k < sequenceLength; k++) { if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (seqchars[k] == 'S' || seqchars[k] == 'T' || seqchars[k] == 'Y')) { phosmodi++; } } Cphosmodi = phosmodi - NTempPhosmodi; for (int z = min; z <= max; z++) { switch (topSeries) { case "c": topSeriesFragmentMZ = fragmentation.c(i, z); break; default: topSeriesFragmentMZ = 0.0; break; } switch (bottomSeries) { case "x": bottomSeriesFragmentMZ = fragmentation.x(sequence.Length - i, z); break; default: bottomSeriesFragmentMZ = 0.0; break; } if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(topSeriesFragmentMZ - 0.5); if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ + 0.5)) topSeriesHasMatch = true; // Reset the search index index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(bottomSeriesFragmentMZ - 0.5); if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ + 0.5)) bottomSeriesHasMatch = true; } //disable neutral losses for c/x series //test neutral loss #region water loss c/x if (waterLoss == true) { if (Nseq.Contains("S") || Nseq.Contains("T") || Nseq.Contains("E") || Nseq.Contains("D")) { if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(topSeriesFragmentMZ - WATERMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - WATERMONOMASS / z + 0.5)) topSeriesHasMatch = true; } else { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - WATERMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) topSeriesHasMatch = true; } } } if (Cseq.Contains("S") || Cseq.Contains("T") || Cseq.Contains("E") || Cseq.Contains("D")) { if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(bottomSeriesFragmentMZ - WATERMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - WATERMONOMASS / z + 0.5)) bottomSeriesHasMatch = true; } else { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - WATERMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) bottomSeriesHasMatch = true; } } } } #endregion ////test neutral loss #region ammonium loss c/x if (ammoniumLoss == true) { if (points != null) { if (Nseq.Contains("R") || Nseq.Contains("K") || Nseq.Contains("Q") || Nseq.Contains("N")) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(topSeriesFragmentMZ - AMMONIUMMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5)) topSeriesHasMatch = true; } else { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) topSeriesHasMatch = true; } } if (Cseq.Contains("R") || Cseq.Contains("K") || Cseq.Contains("Q") || Cseq.Contains("N")) { // Reset the search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5)) bottomSeriesHasMatch = true; } else { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) bottomSeriesHasMatch = true; } } } } #endregion ////test neutral loss #region phosphate loss c/x if (phosphateLoss == true) { int minPhosphate = Math.Min(Nphosmodi, numPhosphate); if (minPhosphate > 0) { for (int k = 1; k <= minPhosphate; k++) { if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5)) { topSeriesHasMatch = true; break; } } else { if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) { topSeriesHasMatch = true; break; } } } } } minPhosphate = Math.Min(Cphosmodi, numPhosphate); { if (minPhosphate > 0) { for (int k = 1; k <= minPhosphate; k++) { if (points != null) { // Search index int index = -1; // Find the left mz value using a mass tolerance of 0.5 da. index = points.FullLowerBound(bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z - 0.5); if (basePeakThresholding == false) { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5)) { bottomSeriesHasMatch = true; break; } } else { if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff) { bottomSeriesHasMatch = true; break; } } } } } } } #endregion } // Build the label for the amino acid // Add a text box in the middle of the left and right mz boundaries StringBuilder label = new StringBuilder(sequence[i - 1].ToString()); // Figure out if any mods are there on this amino acid double deltaMass = modifications[i - 1].monoisotopicDeltaMass(); string deltaMassString = deltaMass.ToString(); // Round the mod mass and append it to the amino acid as a string //if (deltaMass > 0.0) //{ // label.Append("+" + Math.Round(deltaMass)); //} //else if (deltaMass < 0.0) //{ // label.Append(Math.Round(deltaMass)); //} TextObj text = new TextObj(label.ToString(), topSeriesLeftPoint, seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center); text.ZOrder = ZOrder.B_BehindLegend; text.FontSpec = new FontSpec("Arial", 13, Color.Black, true, false, false); text.FontSpec.Border.IsVisible = false; text.FontSpec.Fill.IsVisible = false; text.IsClippedToChartRect = true; list.Add(text); SizeF size = text.LayoutArea; float width = size.Width; if (deltaMass > 0.0) { deltaMassString = "+" + Math.Round(deltaMass).ToString(); TextObj textModi = new TextObj(deltaMassString, topSeriesLeftPoint + 0.01, seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center); textModi.ZOrder = ZOrder.B_BehindLegend; textModi.FontSpec = new FontSpec("Arial", 8, Color.Black, true, false, false); textModi.FontSpec.Border.IsVisible = false; textModi.FontSpec.Fill.IsVisible = false; textModi.IsClippedToChartRect = true; list.Add(textModi); } else if (deltaMass < 0.0) { deltaMassString = Math.Round(deltaMass).ToString(); TextObj textModi = new TextObj(deltaMassString, topSeriesLeftPoint + 0.01, seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center); textModi.ZOrder = ZOrder.B_BehindLegend; textModi.FontSpec = new FontSpec("Arial", 8, Color.Black, true, false, false); textModi.FontSpec.Border.IsVisible = false; textModi.FontSpec.Fill.IsVisible = false; textModi.IsClippedToChartRect = true; list.Add(textModi); } if (topSeriesHasMatch) { // Paint the tick in the middle LineObj tick = new LineObj(topSeriesColor, topSeriesLeftPoint + tickStart, (seriesTopLeftOffset - 0.03), topSeriesLeftPoint + tickStart, seriesTopLeftOffset); tick.Location.CoordinateFrame = CoordType.ChartFraction; tick.Line.Width = 2; tick.IsClippedToChartRect = true; list.Add(tick); // Paint the hook LineObj hook = new LineObj(topSeriesColor, topSeriesLeftPoint, (seriesTopLeftOffset - 0.05), topSeriesLeftPoint + tickStart, seriesTopLeftOffset - 0.03); hook.Location.CoordinateFrame = CoordType.ChartFraction; hook.Line.Width = 2; hook.IsClippedToChartRect = true; list.Add(hook); } if (bottomSeriesHasMatch) { // Paint the tick in the middle LineObj tick = new LineObj(bottomSeriesColor, topSeriesLeftPoint + tickStart, seriesTopLeftOffset, topSeriesLeftPoint + tickStart, seriesTopLeftOffset + 0.03); tick.Location.CoordinateFrame = CoordType.ChartFraction; tick.Line.Width = 2; tick.IsClippedToChartRect = true; list.Add(tick); // Paint the hook LineObj hook = new LineObj(bottomSeriesColor, topSeriesLeftPoint + tickStart, seriesTopLeftOffset + 0.03, topSeriesLeftPoint + 2.0 * tickStart, seriesTopLeftOffset + 0.05); hook.Location.CoordinateFrame = CoordType.ChartFraction; hook.Line.Width = 2; hook.IsClippedToChartRect = true; list.Add(hook); } // Update the next paint point topSeriesLeftPoint += residueWidth; } #endregion }