// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) 2014 OxyPlot contributors // // // Provides a series that visualizes the structure of a matrix. // // -------------------------------------------------------------------------------------------------------------------- namespace ExampleLibrary { using System; using System.Collections.Generic; using OxyPlot; using OxyPlot.Series; /// /// Provides a series that visualizes the structure of a matrix. /// public class MatrixSeries : XYAxisSeries { /// /// The image /// private OxyImage image; /// /// The matrix /// private double[,] matrix; /// /// Initializes a new instance of the class. /// public MatrixSeries() { this.GridInterval = 1; this.ShowDiagonal = false; this.MinimumGridLineDistance = 4; this.GridColor = OxyColors.LightGray; this.BorderColor = OxyColors.Gray; this.NotZeroColor = OxyColors.Black; this.ZeroTolerance = 0; this.TrackerFormatString = "{0}\r\n[{1},{2}] = {3}"; } /// /// Gets or sets the matrix. /// public double[,] Matrix { get { return this.matrix; } set { this.image = null; this.matrix = value; } } /// /// Gets or sets the interval between the grid lines (the grid is hidden if value is 0). /// public int GridInterval { get; set; } /// /// Gets or sets a value indicating whether to show the diagonal. /// /// true if the diagonal should be shown; otherwise, false. public bool ShowDiagonal { get; set; } /// /// Gets or sets the minimum grid line distance. /// public double MinimumGridLineDistance { get; set; } /// /// Gets or sets the color of the grid. /// /// The color of the grid. public OxyColor GridColor { get; set; } /// /// Gets or sets the color of the border around the matrix. /// /// The color of the border. public OxyColor BorderColor { get; set; } /// /// Gets or sets the color of the not zero elements of the matrix. /// public OxyColor NotZeroColor { get; set; } /// /// Gets or sets the zero tolerance (inclusive). /// /// The zero tolerance. public double ZeroTolerance { get; set; } /// /// Gets the point on the series that is nearest the specified point. /// /// The point. /// Interpolate the series if this flag is set to true. /// A TrackerHitResult for the current hit. public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) { var dp = this.InverseTransform(point); int i = (int)dp.Y; int j = (int)dp.X; if (i >= 0 && i < this.matrix.GetLength(0) && j >= 0 && j < this.matrix.GetLength(1)) { var value = this.matrix[i, j]; return new TrackerHitResult { Series = this, DataPoint = dp, Position = point, Item = null, Index = -1, Text = StringHelper.Format(this.ActualCulture, this.TrackerFormatString, null, this.Title, i, j, value) }; } return null; } /// /// Renders the series on the specified render context. /// /// The rendering context. public override void Render(IRenderContext rc) { if (this.Matrix == null) { return; } int m = this.Matrix.GetLength(0); int n = this.Matrix.GetLength(1); var p0 = this.Transform(0, 0); var p1 = this.Transform(n, m); // note matrix index [i,j] maps to image index [j,i] if (this.image == null) { var pixels = new OxyColor[n, m]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { pixels[j, i] = Math.Abs(this.Matrix[i, j]) <= this.ZeroTolerance ? OxyColors.Transparent : this.NotZeroColor; } } this.image = OxyImage.Create(pixels, ImageFormat.Png); } var x0 = Math.Min(p0.X, p1.X); var y0 = Math.Min(p0.Y, p1.Y); var w = Math.Abs(p0.X - p1.X); var h = Math.Abs(p0.Y - p1.Y); rc.DrawImage(this.image, x0, y0, w, h, 1, false); var points = new List(); if (this.GridInterval > 0) { var p2 = this.Transform(this.GridInterval, this.GridInterval); if (Math.Abs(p2.Y - p0.Y) > this.MinimumGridLineDistance) { for (int i = 1; i < n; i += this.GridInterval) { points.Add(this.Transform(0, i)); points.Add(this.Transform(n, i)); } } if (Math.Abs(p2.X - p0.X) > this.MinimumGridLineDistance) { for (int j = 1; j < m; j += this.GridInterval) { points.Add(this.Transform(j, 0)); points.Add(this.Transform(j, m)); } } } if (this.ShowDiagonal) { points.Add(this.Transform(0, 0)); points.Add(this.Transform(n, m)); } rc.DrawLineSegments(points, this.GridColor, 1, this.EdgeRenderingMode, null, LineJoin.Miter); if (this.BorderColor.IsVisible()) { var borderPoints = new[] { this.Transform(0, 0), this.Transform(m, 0), this.Transform(0, n), this.Transform(m, n), this.Transform(0, 0), this.Transform(0, n), this.Transform(m, 0), this.Transform(m, n) }; rc.DrawLineSegments(borderPoints, this.BorderColor, 1, this.EdgeRenderingMode, null, LineJoin.Miter); } } /// /// Updates the maximum and minimum values of the series. /// protected override void UpdateMaxMin() { base.UpdateMaxMin(); if (this.Matrix == null) { return; } this.MinX = 0; this.MaxX = this.Matrix.GetLength(1); this.MinY = 0; this.MaxY = this.Matrix.GetLength(0); } } }