private static MCharting.Series GetOrCreateSeriesForValue(MCharting.Plot plot, Column column, Visualisable vis, ref bool isGroup) { object value = column.GetRow(vis); MCharting.Series series = plot.Series.FirstOrDefault(z => (z.Tag == null && value == null) || (z.Tag != null && z.Tag.Equals(value))); if (series == null) { series = new MCharting.Series(); series.Name = Column.AsString(value, column.DisplayMode); series.Tag = value; if (value is GroupInfoBase) { GroupInfoBase group = (GroupInfoBase)value; UiControls.CreateIcon(series, group); isGroup = true; } else { series.Style.DrawPoints = new SolidBrush(column.GetColour(vis)); } plot.Series.Add(series); } return(series); }
protected Dictionary <GroupInfoBase, MCharting.Series> DrawLegend(MCharting.Plot plot, IEnumerable <GroupInfoBase> viewTypes) { Dictionary <GroupInfoBase, MCharting.Series> result = new Dictionary <GroupInfoBase, MCharting.Series>(); foreach (GroupInfoBase group in viewTypes) { MCharting.Series legendEntry = new MCharting.Series(); legendEntry.Name = group.DisplayName; legendEntry.Style.DrawVBands = new SolidBrush(group.Colour); plot.LegendEntries.Add(legendEntry); result.Add(group, legendEntry); } return(result); }
private void UpdatePlot() { if (this._scores == null) { this._lblSelection.Text = this._errorMessage; this._lblSelection.ForeColor = Color.Red; this._chart.Visible = false; return; } this._chart.Visible = true; this._lblSelection.Text = ""; this._lblSelection.ForeColor = ForeColor; MCharting.Plot plot = new MCharting.Plot(); plot.Title = $"{this._lblMethod.Text} of {this._core.FileNames.Title}"; plot.SubTitle = $"Source: {this._lblPcaSource.Text}, View: {this._lblPlotView.Text}, Legend: {this._lblLegend.Text}, Corrections: {this._lblCorrections.Text}, Observations: {this._lblObs.Text}, Peaks: {this._lblPeaks.Text}"; switch (this._method) { case EMethod.Pca: plot.XLabel = $"PC{this._component + 1}"; plot.YLabel = $"PC{this._component + 2}"; break; case EMethod.Plsr: plot.XLabel = $"Component {this._component + 1}"; plot.YLabel = $"Component {this._component + 2}"; plot.SubTitle += ", PLSR Response: " + this._lblPlsrSource.Text; break; } this._chart.Style.Margin = new Padding(48, 48, 48, 48); plot.Style.GridStyle = new Pen(Color.FromArgb(224, 224, 224)); // Get the "rows" IEnumerator enSources; Column column; this.GetSource(this._colourBy, out enSources, out column); // Get the "columns" double[,] plotPoints; if (this._plotSource == EPlotSource.Loadings) { plotPoints = this._loadings; } else { plotPoints = this._scores; } // Get the component if (this._component < 0) { this._component = 0; } if (this._component >= plotPoints.GetLength(1)) { this._component = plotPoints.GetLength(1) - 1; } this._btnPrevPc.Enabled = this._component != 0; this._btnNextPc.Enabled = this._component != plotPoints.GetLength(1) - 1; this._lblPlotView.Text = this._plotSource == EPlotSource.Loadings ? "Loadings" : "Scores"; this._btnScores.Checked = this._plotSource == EPlotSource.Scores; this._btnLoadings.Checked = this._plotSource == EPlotSource.Loadings; this._lblPcNumber.Text = "PC" + (this._component + 1).ToString() + " / " + plotPoints.GetLength(1); this._lblLegend.Text = column.DisplayName; bool isGroup = false; // Iterate scores for (int r = 0; r < plotPoints.GetLength(0); r++) { enSources.MoveNext(); MCharting.Series series = GetOrCreateSeriesForValue(plot, column, (Visualisable)enSources.Current, ref isGroup); var coord = new MCharting.DataPoint(plotPoints[r, this._component], plotPoints[r, this._component + 1]); coord.Tag = enSources.Current; series.Points.Add(coord); } // Assign colours if (!column.HasColourSupport && !isGroup) { foreach (var colour in PlotCreator.AutoColour(plot.Series)) { colour.Key.Style.DrawPoints = new SolidBrush(colour.Value); } } this._chart.Style.Animate = true; this._chart.Style.SelectionColour = Color.Yellow; this._chart.SetPlot(plot); }
/// <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); }