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