예제 #1
0
        /// <summary>
        /// Creates a bitmap of the specified cluster
        /// </summary>
        public Bitmap CreateBitmap(int width, int height, StylisedCluster cluster)
        {
            if (cluster.Cluster.Assignments.Count == 0)
            {
                return(null);
            }

            this.Plot(cluster);
            return(this.CreateBitmap(width, height));
        }
예제 #2
0
        internal StylisedCluster CreateStylisedCluster(Core core, Visualisable toHighlight)
        {
            Cluster fakeCluster = new Cluster(this.DisplayName, null);

            fakeCluster.Assignments.Add(this);

            StylisedCluster c = new StylisedCluster(fakeCluster, this, null);

            c.IsFake        = true;
            c.CaptionFormat = "Plot of {0}.";

            return(c);
        }
예제 #3
0
        /// <summary>
        /// Creates a StylisedCluster (for plotting)
        /// </summary>
        /// <param name="core">Core</param>
        /// <param name="toHighlight">Which peak to highlight</param>
        /// <returns>The StylisedCluster</returns>
        public StylisedCluster CreateStylisedCluster(Core core, Associational toHighlight)
        {
            // Cluster: Peaks in cluster
            // Peak: Handled by selection - take no action
            // Compound: Peaks in compound

            StylisedCluster.HighlightElement[] highlight = null;
            string caption = "Peaks assigned to {0}.";

            if (toHighlight != null)
            {
                switch (toHighlight.AssociationalClass)
                {
                case EVisualClass.Compound:
                    Compound highlightCompound = (Compound)toHighlight;
                    highlight = highlightCompound.Annotations.Select(StylisedCluster.HighlightElement.FromAnnotation).ToArray();
                    caption  += " Peaks potentially representing {1} are {HIGHLIGHTED}.";
                    break;

                case EVisualClass.Pathway:
                    highlight = toHighlight.FindAssociations(core, EVisualClass.Peak).Results.Cast <Association <Peak> >().Select(z => StylisedCluster.HighlightElement.FromPeak(z.Associated)).ToArray();
                    caption  += " Peaks potentially representing compounds in {1} are {HIGHLIGHTED}.";
                    break;

                case EVisualClass.Peak:
                    Peak peak = (Peak)toHighlight;
                    highlight = new StylisedCluster.HighlightElement[] { new StylisedCluster.HighlightElement(peak, null) };
                    caption  += " {1} is {HIGHLIGHTED}.";
                    break;

                case EVisualClass.Assignment:
                    Assignment assignment = (Assignment)toHighlight;
                    highlight = new StylisedCluster.HighlightElement[] { new StylisedCluster.HighlightElement(assignment.Vector.Peak, assignment.Vector.Group) };
                    caption  += " {1} is {HIGHLIGHTED}.";
                    break;
                }
            }

            StylisedCluster r = new StylisedCluster(this);

            r.Highlight         = highlight;
            r.CaptionFormat     = caption;
            r.WhatIsHighlighted = toHighlight;
            return(r);
        }
예제 #4
0
        /// <summary>
        /// Creates a StylisedCluster for plotting from this cluster.
        /// </summary>
        /// <param name="core">Core</param>
        /// <param name="highlight">What to highlight in the result</param>
        /// <returns>A StylisedCluster</returns>
        internal StylisedCluster CreateStylisedCluster(Core core, IntensityMatrix source, Associational highlight)
        {
            Cluster fakeCluster = new Cluster(this.DefaultDisplayName, null);
            Dictionary <Peak, LineInfo> colourInfo = new Dictionary <Peak, LineInfo>();
            string caption = "Plot of peaks potentially representing {0}.";

            // Compound --> Peaks in compound
            // Adduct: NA
            // Peak: Peak
            // Cluster: Peaks in cluster
            // Pathway: None

            StylisedCluster.HighlightElement[] toHighlight = null;

            if (highlight != null)
            {
                switch (highlight.AssociationalClass)
                {
                case EVisualClass.Peak:
                    toHighlight = new StylisedCluster.HighlightElement[] { new StylisedCluster.HighlightElement((Peak)highlight, null) };
                    caption    += " {1} is shown in red.";
                    break;

                case EVisualClass.Cluster:
                    Cluster highlightCluster = (Cluster)highlight;
                    toHighlight = highlightCluster.Assignments.Vectors.Select(StylisedCluster.HighlightElement.FromVector).ToArray();
                    caption    += " Peaks in {1} are shown in red.";
                    break;
                }
            }

            HashSet <Peak> peaks = this.Annotations.Select(z => z.Peak).Unique();

            IntensityMatrix vm = source.Subset(z => peaks.Contains(z), null, ESubsetFlags.None);

            for (int index = 0; index < vm.NumVectors; index++)
            {
                Vector vec  = vm.Vectors[index];
                Peak   peak = vec.Peak;

                fakeCluster.Assignments.Add(new Assignment(vec, fakeCluster, double.NaN));

                StringBuilder sb = new StringBuilder();

                if (peak.Annotations.Count > 5)
                {
                    sb.Append(this.DefaultDisplayName + " OR " + (peak.Annotations.Count - 1) + " others");
                }
                else
                {
                    sb.Append(this.DefaultDisplayName);

                    foreach (Annotation c2 in peak.Annotations)
                    {
                        if (c2.Compound != this)
                        {
                            sb.Append(" OR ");
                            sb.Append(c2.Compound.DefaultDisplayName + " (" + c2.Adduct.DefaultDisplayName + ")");
                        }
                    }
                }

                colourInfo.Add(peak, new LineInfo(peak.DisplayName + ": " + sb.ToString(), Color.Black, DashStyle.Solid));
            }

            StylisedCluster r = new StylisedCluster(fakeCluster, this, colourInfo);

            r.IsFake            = true;
            r.CaptionFormat     = caption;
            r.WhatIsHighlighted = highlight;
            r.Highlight         = toHighlight;
            return(r);
        }
예제 #5
0
        /// <summary>
        /// Returns the series for a group and vector, creating one if it doesn't already exist
        /// </summary>
        /// <param name="plot">Plot to create series in</param>
        /// <param name="existingSeries">Existing series</param>
        /// <param name="group">Group to create series for</param>
        /// <param name="vector">Vector to create series for</param>
        /// <param name="style">Styles (colours and highlights)</param>
        /// <param name="groupLegends">Where to add legends to</param>
        /// <param name="lineLegend">Where to add legends to</param>
        /// <returns>Series (new or existing)</returns>
        private MCharting.Series GetOrCreateSeries(
            MCharting.Plot plot,
            Dictionary <GroupInfo, MCharting.Series> existingSeries,
            GroupInfo group,
            Vector vector,
            StylisedCluster style,
            Dictionary <GroupInfoBase, MCharting.Series> groupLegends,
            MCharting.Series lineLegend,
            HashSet <MCharting.Series> toBringToFront,
            bool bandw)
        {
            MCharting.Series series;

            if (existingSeries.TryGetValue(group, out series))
            {
                return(series);
            }

            Peak peak = vector.Peak;
            Dictionary <Peak, LineInfo> colours = style?.Colours;

            // Each peak + condition gets its own series (yes we end up with lots of series)
            series = new MCharting.Series();
            series.Style.StrictOrder = SeriesStyle.EOrder.X;
            series.Name = vector.ToString() + " : " + group.DisplayName;
            series.ApplicableLegends.Add(groupLegends[group]);
            series.ApplicableLegends.Add(lineLegend);
            plot.Series.Add(series);

            // If the parameters specify a colour for this peak use that, else use the default
            if (colours != null && colours.ContainsKey(peak))
            {
                series.Style.DrawLines           = new Pen(colours[peak].Colour, this._core.Options.LineWidth);
                series.Style.DrawLines.DashStyle = colours[peak].DashStyle;
                series.Name = colours[peak].SeriesName + " : " + group.DisplayName;
            }
            else
            {
                series.Style.DrawLines = new Pen(group.Colour, this._core.Options.LineWidth);
            }

            if (bandw)
            {
                series.Style.DrawLines = new Pen(this._core.Options.Colours.InputVectorJoiners, this._core.Options.LineWidth);
            }

            series.Style.DrawLines.Width = this._core.Options.LineWidth;
            series.Tag = peak;

            if (style.Highlight != null && !bandw)
            {
                foreach (StylisedCluster.HighlightElement highlight in style.Highlight)
                {
                    if (highlight.Peak == vector.Peak &&
                        (highlight.Group == null || highlight.Group == group))
                    {
                        series.Style.DrawLines.Color = this._core.Options.Colours.NotableHighlight;
                        series.Style.DrawLines.Width = this._core.Options.LineWidth * 2;
                        toBringToFront.Add(series);
                        break;
                    }
                }
            }

            existingSeries.Add(group, series);

            return(series);
        }
예제 #6
0
        /// <summary>
        /// Actual plotting.
        /// </summary>
        public void Plot(StylisedCluster stylisedCluster)
        {
            Debug.WriteLine("ClusterPlot: " + stylisedCluster);

            // Reset the chart
            bool    isPreview = stylisedCluster != null && stylisedCluster.IsPreview;
            Cluster p         = stylisedCluster != null ? stylisedCluster.Cluster : null;
            Plot    plot      = this.PrepareNewPlot(!isPreview, (stylisedCluster != null) ? stylisedCluster.Cluster : null, p?.Assignments.Vectors.FirstOrDefault()?.Source);

            // Set the selected cluster
            Dictionary <Peak, LineInfo> colours = stylisedCluster != null ? stylisedCluster.Colours : null;

            this.SelectedCluster = stylisedCluster;

            if (stylisedCluster != null)
            {
                this.SetCaption(stylisedCluster.CaptionFormat, stylisedCluster.ActualElement, stylisedCluster.WhatIsHighlighted);
            }
            else
            {
                this.SetCaption("No plot displayed.");
            }

            Core core = this._core;
            CoreColourSettings colourSettings = core.Options.Colours;

            // If there is nothing to plot then exit
            if (p == null)
            {
                this.CompleteNewPlot(plot);
                return;
            }

            // Sort the variables exemplars top-most
            List <Assignment> toPlot = new List <Assignment>(p.Assignments.List);

            // Too much to plot
            while (toPlot.Count > core.Options.MaxPlotVariables)
            {
                //toPlot = toPlot.OrderBy(z => z.Peak.Index).ToList();
                toPlot.RemoveRange(core.Options.MaxPlotVariables, toPlot.Count - core.Options.MaxPlotVariables);
            }

            int numClusterCentres            = 0;
            HashSet <GroupInfo> groupsInPlot = p.Assignments.Vectors.First().ColHeaders.Unique(z => z.Observation.Group);

            if (!this._core.Options.DisplayAllGroupsInClusterPlot)
            {
                groupsInPlot.RemoveWhere(z => !this._core.Options.ViewTypes.Contains(z));
            }

            GroupInfo[] groupOrder = groupsInPlot.OrderBy(GroupInfoBase.GroupOrderBy).ToArray();

            MCharting.Series legendEntry = new MCharting.Series();
            legendEntry.Name            = "Input vector";
            legendEntry.Style.DrawLines = new Pen(Color.Black, this._core.Options.LineWidth * 2);
            plot.LegendEntries.Add(legendEntry);

            // --- LEGEND ---
            var groupLegends = this.DrawLegend(plot, groupOrder);

            HashSet <MCharting.Series> toBringToFront = new HashSet <MCharting.Series>();

            // --- PLOT CLUSTER ASSIGNMENTS ---
            // Iterate variables in cluster
            for (int assignmentIndex = 0; assignmentIndex < toPlot.Count; assignmentIndex++)
            {
                Assignment assignment = toPlot[assignmentIndex];
                Vector     vec        = assignment.Vector;
                Peak       peak       = vec.Peak;
                Dictionary <GroupInfo, MCharting.Series> vecSeries  = new Dictionary <GroupInfo, MCharting.Series>();
                Dictionary <GroupInfo, MCharting.Series> vec2Series = new Dictionary <GroupInfo, MCharting.Series>();
                MCharting.DataPoint lastPoint  = null;
                MCharting.Series    lastSeries = null;

                ///////////////////
                // PLOT THE POINT
                // Okay! Now plot the values pertinent to this peak & type
                for (int i = 0; i < vec.Count; ++i)
                {
                    // Peak, by observation
                    ObservationInfo obs   = vec.Observations[i];
                    GroupInfo       group = obs.Group;

                    if (!groupOrder.Contains(group))
                    {
                        continue;
                    }

                    MCharting.Series series = this.GetOrCreateSeries(plot, vecSeries, group, vec, stylisedCluster, groupLegends, legendEntry, toBringToFront, false);

                    // When the series changes we create an intermediate series to join the two together
                    //MCharting.Series seriesb = null;

                    //if (series != lastSeries && lastSeries != null)
                    //{
                    //    seriesb = GetOrCreateSeries(plot, vec2Series, group, vec, stylisedCluster, groupLegends, legendEntry, toBringToFront, true);
                    //}

                    lastSeries = series;

                    int typeOffset = this.GetTypeOffset(groupOrder, group);

                    int    x = typeOffset + obs.Time;
                    double v = vec.Values[i];
                    MCharting.DataPoint dataPoint = new MCharting.DataPoint(x, v);
                    dataPoint.Tag = new IntensityInfo(obs.Time, obs.Rep, obs.Group, v);
                    series.Points.Add(dataPoint);

                    //if (seriesb != null)
                    //{
                    //    seriesb.Points.Add(lastPoint);
                    //    seriesb.Points.Add(dataPoint);
                    //}

                    lastPoint = dataPoint;
                }
            }

            // --- PLOT CLUSTER CENTRES ---
            if (!isPreview && core.Options.ShowCentres && p.Centres.Count != 0 && p.Centres.Count < 100)
            {
                MCharting.Series legendEntry2 = new MCharting.Series();
                legendEntry2.Name                      = (p.Centres.Count == 1) ? "Cluster centre" : "Cluster centres";
                legendEntry2.Style.DrawLines           = new Pen(colourSettings.ClusterCentre, this._core.Options.LineWidth * 2);
                legendEntry2.Style.DrawLines.DashStyle = DashStyle.Dash;
                legendEntry2.Style.DrawPoints          = new SolidBrush(colourSettings.ClusterCentre);
                legendEntry2.Style.DrawPointsSize      = 8; // MarkerStyle.Diamond;
                plot.LegendEntries.Add(legendEntry2);

                var templateAssignment = p.Assignments.List.First();

                foreach (double[] centre in p.Centres)
                {
                    MCharting.Series series = new MCharting.Series();
                    series.Style.StrictOrder = SeriesStyle.EOrder.X;
                    series.ApplicableLegends.Add(legendEntry2);
                    plot.Series.Add(series);
                    series.Name                      = "Cluster centre #" + (++numClusterCentres);
                    series.Style.DrawLines           = new Pen(colourSettings.ClusterCentre, this._core.Options.LineWidth * 2);
                    series.Style.DrawLines.DashStyle = DashStyle.Dash;
                    series.Style.DrawPoints          = new SolidBrush(colourSettings.ClusterCentre);
                    series.Style.DrawPointsSize      = 8; // MarkerStyle.Diamond;

                    IEnumerable <int> order = templateAssignment.Vector.Observations.WhichOrder(ObservationInfo.GroupTimeReplicateDisplayOrder);

                    foreach (int index in order)
                    {
                        // Centre, by observation
                        ObservationInfo cond = templateAssignment.Vector.Observations[index];

                        if (!groupOrder.Contains(cond.Group))
                        {
                            continue;
                        }

                        double dp = centre[index];
                        int    x  = this.GetTypeOffset(groupOrder, cond.Group) + cond.Time;
                        MCharting.DataPoint cdp = new MCharting.DataPoint(x, dp);
                        cdp.Tag = new IntensityInfo(cond.Time, cond.Rep, cond.Group, dp);
                        series.Points.Add(cdp);
                    }
                }
            }

            // Bring highlighted series to the front
            foreach (MCharting.Series series in toBringToFront)
            {
                plot.Series.Remove(series);
                plot.Series.Add(series);
            }

            // --- LABELS ---
            this.DrawLabels(plot, true, groupOrder, true);

            // --- COMPLETE ---
            this.CompleteNewPlot(plot);
        }
예제 #7
0
        /// <summary>
        /// Creates a StylisedCluster for plotting from this pathway.
        /// </summary>
        /// <param name="core">Core</param>
        /// <param name="highlightContents">What to highlight in the plot</param>
        /// <returns>A StylisedCluster</returns>
        internal StylisedCluster CreateStylisedCluster(Core core, IntensityMatrix source, Associational highlightContents)
        {
            var colours = new Dictionary <Peak, LineInfo>();

            // Adduct: NA
            // Peak: Pathways for peak -> Peaks (THIS PEAK)
            // Cluster: Pathways for cluster -> Peaks (PEAKS IN CLUSTER)
            // Compound: Pathway for compound -> Peaks (PEAKS IN COMPOUND)
            // Pathway: NA
            const string caption1 = "Plot of peaks potentially representing compounds implicated in {0}.";
            string       caption2 = " Colours represent peaks that share the same cluster(s).";
            string       caption3;

            // Find out the peaks that we are supposed to highlight
            StylisedCluster.HighlightElement[] toHighlight = null;

            if (highlightContents != null)
            {
                switch (highlightContents.AssociationalClass)
                {
                case EVisualClass.Compound:
                    Compound highlightCompound = (Compound)highlightContents;
                    toHighlight = highlightCompound.Annotations.Select(z => new StylisedCluster.HighlightElement(z, null)).ToArray();
                    caption3    = " Peaks potentially representing {1} are {HIGHLIGHTED}.";
                    break;

                case EVisualClass.Cluster:
                    Cluster highlightCluster = (Cluster)highlightContents;
                    toHighlight = highlightCluster.Assignments.Vectors.Select(StylisedCluster.HighlightElement.FromVector).ToArray();
                    caption3    = " Peaks potentially representing compounds in {1} are {HIGHLIGHTED}.";

                    break;

                case EVisualClass.Peak:
                    toHighlight = new StylisedCluster.HighlightElement[] { new StylisedCluster.HighlightElement((Peak)highlightContents, null) };
                    caption3    = " {1} is {HIGHLIGHTED}.";
                    break;

                default:
                    caption3 = "";
                    break;
                }
            }
            else
            {
                caption3 = "";
            }


            bool highlightByCompound = false;

            // Make a list of the peaks in this pathway
            Dictionary <Peak, List <Compound> > peaks = new Dictionary <Peak, List <Compound> >();

            foreach (Compound compound in this.Compounds)
            {
                foreach (Annotation annotation in compound.Annotations)
                {
                    Peak peak = annotation.Peak;

                    if (peaks.ContainsKey(peak))
                    {
                        peaks[peak].Add(compound);
                    }
                    else
                    {
                        peaks[peak] = new List <Compound>();
                        peaks[peak].Add(compound);
                    }
                }
            }

            // Depending on the mode assign either each combination of compounds OR clusters a unique colour
            Cluster fakeCluster = new Cluster(this.DisplayName, null);
            List <List <Compound> > uniqueCompoundCombinations = new List <List <Compound> >();
            List <List <Cluster> >  uniqueClusterCombinations  = new List <List <Cluster> >();

            int cindex = -1;

            IntensityMatrix vm = source.Subset(z => peaks.ContainsKey(z), null, ESubsetFlags.None);

            for (int vIndex = 0; vIndex < vm.NumVectors; vIndex++)
            {
                var             vec       = vm.Vectors[vIndex];
                Peak            peak      = vec.Peak;
                var             asses     = vec.Peak.FindAssignments(core).ToArray();
                List <Compound> compounds = peaks[peak];
                Color           col;

                // Find or create peak in list
                if (highlightByCompound)
                {
                    int uniqueIndex = Maths.FindMatch(uniqueCompoundCombinations, compounds);

                    if (uniqueIndex == -1)
                    {
                        uniqueIndex = uniqueCompoundCombinations.Count;
                        uniqueCompoundCombinations.Add(compounds); // add list of peaks for this peak
                    }

                    if (uniqueCompoundCombinations[uniqueIndex].Count == 1)
                    {
                        col = Color.Black;
                    }
                    else
                    {
                        cindex++;

                        if (cindex == UiControls.BrightColours.Length)
                        {
                            // If there are too many don't bother
                            col      = Color.Black;
                            caption2 = "";

                            foreach (var lii in colours)
                            {
                                lii.Value.Colour = Color.Black;
                            }
                        }
                        else
                        {
                            col = UiControls.BrightColours[cindex % UiControls.BrightColours.Length];
                        }
                    }
                }
                else
                {
                    var l           = asses.Select(z => z.Cluster).ToList();
                    int uniqueIndex = Maths.FindMatch(uniqueClusterCombinations, l);

                    if (uniqueIndex == -1)
                    {
                        uniqueIndex = uniqueClusterCombinations.Count;
                        uniqueClusterCombinations.Add(l); // add list of peaks for this peak
                    }

                    col = UiControls.BrightColours[uniqueIndex % UiControls.BrightColours.Length];
                }

                StringBuilder legend = new StringBuilder();
                int           xCount = 0;

                foreach (Annotation potential in peak.Annotations)
                {
                    if (this.Compounds.Contains(potential.Compound))
                    {
                        if (legend.Length != 0)
                        {
                            legend.Append(" OR ");
                        }

                        legend.Append(potential.Compound.DefaultDisplayName);
                    }
                    else
                    {
                        xCount++;
                    }
                }

                if (xCount != 0)
                {
                    legend.Append(" OR " + xCount + " others not in this pathway");
                }

                fakeCluster.Assignments.Add(new Assignment(vec, fakeCluster, double.NaN));


                string seriesName = peak.DisplayName + (!asses.IsEmpty() ? (" (" + StringHelper.ArrayToString(asses.Select(z => z.Cluster)) + ")") : "") + ": " + legend.ToString();
                var    li         = new LineInfo(seriesName, col, DashStyle.Solid);
                colours.Add(peak, li);
            }

            var r = new StylisedCluster(fakeCluster, this, colours);

            r.IsFake            = true;
            r.Highlight         = toHighlight;
            r.CaptionFormat     = (caption1 + caption2 + caption3);
            r.WhatIsHighlighted = highlightContents;
            return(r);
        }