Beispiel #1
0
        ///<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;
            }
        }
Beispiel #2
0
        ///<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;
                }
            }
        }
Beispiel #3
0
        ///<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
        }