/// <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)); }
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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }