Neuerstellung

- Quelle: https://github.com/oxyplot/oxyplot
This commit is contained in:
2023-09-02 09:24:59 +02:00
commit 9520c1fa4a
810 changed files with 117869 additions and 0 deletions

View File

@@ -0,0 +1,323 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CustomSeriesExamples.cs" company="OxyPlot">
// Copyright (c) 2014 OxyPlot contributors
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace ExampleLibrary
{
using System;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
using OxyPlot.Legends;
[Examples("Custom series"), Tags("Series")]
public static class CustomSeriesExamples
{
[Example("ErrorSeries")]
public static PlotModel ErrorSeries()
{
int n = 20;
var model = new PlotModel { Title = "ErrorSeries" };
var l = new Legend
{
LegendPosition = LegendPosition.BottomRight
};
model.Legends.Add(l);
var s1 = new ErrorSeries { Title = "Measurements" };
var random = new Random(31);
double x = 0;
double y = 0;
for (int i = 0; i < n; i++)
{
x += 2 + (random.NextDouble() * 10);
y += 1 + random.NextDouble();
double xe = 1 + (random.NextDouble() * 2);
double ye = 1 + (random.NextDouble() * 2);
s1.Points.Add(new ErrorItem(x, y, xe, ye));
}
model.Series.Add(s1);
return model;
}
[Example("LineSegmentSeries")]
public static PlotModel LineSegmentSeries()
{
var model = new PlotModel { Title = "LineSegmentSeries" };
var lss1 = new LineSegmentSeries { Title = "The first series" };
// First segment
lss1.Points.Add(new DataPoint(0, 3));
lss1.Points.Add(new DataPoint(2, 3.2));
// Second segment
lss1.Points.Add(new DataPoint(2, 2.7));
lss1.Points.Add(new DataPoint(7, 2.9));
model.Series.Add(lss1);
var lss2 = new LineSegmentSeries { Title = "The second series" };
// First segment
lss2.Points.Add(new DataPoint(1, -3));
lss2.Points.Add(new DataPoint(2, 10));
// Second segment
lss2.Points.Add(new DataPoint(0, 4.8));
lss2.Points.Add(new DataPoint(7, 2.3));
// A very short segment
lss2.Points.Add(new DataPoint(6, 4));
lss2.Points.Add(new DataPoint(6, 4 + 1e-8));
model.Series.Add(lss2);
return model;
}
[Example("FlagSeries")]
public static PlotModel FlagSeries()
{
var model = new PlotModel { Title = "FlagSeries" };
var s1 = new FlagSeries { Title = "Incidents", Color = OxyColors.Red };
s1.Values.Add(2);
s1.Values.Add(3);
s1.Values.Add(5);
s1.Values.Add(7);
s1.Values.Add(11);
s1.Values.Add(13);
s1.Values.Add(17);
s1.Values.Add(19);
model.Series.Add(s1);
return model;
}
[Example("MatrixSeries - diagonal matrix")]
public static PlotModel DiagonalMatrix()
{
var model = new PlotModel();
var matrix = new double[3, 3];
matrix[0, 0] = 1;
matrix[1, 1] = 2;
matrix[2, 2] = 3;
// Reverse the vertical axis
model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0 });
model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom });
model.Series.Add(new MatrixSeries { Matrix = matrix, ShowDiagonal = true });
return model;
}
[Example("PolarHeatMap")]
public static PlotModel PolarHeatMap()
{
var model = new PlotModel { Title = "Polar heat map", PlotMargins = new OxyThickness(40, 80, 40, 40), PlotType = PlotType.Polar, PlotAreaBorderThickness = new OxyThickness(0) };
var matrix = new double[2, 2];
matrix[0, 0] = 0;
matrix[0, 1] = 2;
matrix[1, 0] = 1.5;
matrix[1, 1] = 0.2;
model.Axes.Add(new AngleAxis { StartAngle = 0, EndAngle = 360, Minimum = 0, Maximum = 360, MajorStep = 30, MinorStep = 15 });
model.Axes.Add(new MagnitudeAxis { Minimum = 0, Maximum = 100, MajorStep = 25, MinorStep = 5 });
model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Rainbow(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black });
model.Series.Add(new PolarHeatMapSeries { Data = matrix, Angle0 = 30, Angle1 = 150, Magnitude0 = 0, Magnitude1 = 80, Interpolate = false });
return model;
}
[Example("PolarHeatMap Reversed Angle Axis")]
public static PlotModel PolarHeatMapReversedAngleAxis()
{
var model = new PlotModel { Title = "Polar heat map", PlotMargins = new OxyThickness(40, 80, 40, 40), PlotType = PlotType.Polar, PlotAreaBorderThickness = new OxyThickness(0) };
var matrix = new double[2, 2];
matrix[0, 0] = 0;
matrix[0, 1] = 2;
matrix[1, 0] = 1.5;
matrix[1, 1] = 0.2;
model.Axes.Add(new AngleAxis { StartAngle = 360, EndAngle = 0, Minimum = 0, Maximum = 360, MajorStep = 30, MinorStep = 15 });
model.Axes.Add(new MagnitudeAxis { Minimum = 0, Maximum = 100, MajorStep = 25, MinorStep = 5 });
model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Rainbow(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black });
model.Series.Add(new PolarHeatMapSeries { Data = matrix, Angle0 = 30, Angle1 = 150, Magnitude0 = 0, Magnitude1 = 80, Interpolate = false });
return model;
}
[Example("PolarHeatMap Rotated CounterClockwise 90")]
public static PlotModel PolarHeatMapRotatedCounterClockwise90()
{
var model = new PlotModel { Title = "Polar heat map", PlotMargins = new OxyThickness(40, 80, 40, 40), PlotType = PlotType.Polar, PlotAreaBorderThickness = new OxyThickness(0) };
var matrix = new double[2, 2];
matrix[0, 0] = 0;
matrix[0, 1] = 2;
matrix[1, 0] = 1.5;
matrix[1, 1] = 0.2;
model.Axes.Add(new AngleAxis { StartAngle = 90, EndAngle = 90+360, Minimum = 0, Maximum = 360, MajorStep = 30, MinorStep = 15 });
model.Axes.Add(new MagnitudeAxis { Minimum = 0, Maximum = 100, MajorStep = 25, MinorStep = 5 });
model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Rainbow(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black });
model.Series.Add(new PolarHeatMapSeries { Data = matrix, Angle0 = 30, Angle1 = 150, Magnitude0 = 0, Magnitude1 = 80, Interpolate = false });
return model;
}
[Example("PolarHeatMap Rotated CounterClockwise on PI degrees")]
public static PlotModel PolarHeatMapRotatedCounterClockwisePi()
{
var model = new PlotModel { Title = "Polar heat map", PlotMargins = new OxyThickness(40, 80, 40, 40), PlotType = PlotType.Polar, PlotAreaBorderThickness = new OxyThickness(0) };
var matrix = new double[2, 2];
matrix[0, 0] = 0;
matrix[0, 1] = 2;
matrix[1, 0] = 1.5;
matrix[1, 1] = 0.2;
model.Axes.Add(new AngleAxis { StartAngle = Math.PI, EndAngle = Math.PI + 360, Minimum = 0, Maximum = 360, MajorStep = 30, MinorStep = 15 });
model.Axes.Add(new MagnitudeAxis { Minimum = 0, Maximum = 100, MajorStep = 25, MinorStep = 5 });
model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Rainbow(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black });
model.Series.Add(new PolarHeatMapSeries { Data = matrix, Angle0 = 30, Angle1 = 150, Magnitude0 = 0, Magnitude1 = 80, Interpolate = false });
return model;
}
[Example("PolarHeatMap (interpolated)")]
public static PlotModel PolarHeatMapInterpolated()
{
var model = PolarHeatMap();
model.Title = "Polar heat map (interpolated)";
((PolarHeatMapSeries)model.Series[0]).Interpolate = true;
return model;
}
[Example("PolarHeatMap fixed size image")]
public static PlotModel PolarHeatMapFixed()
{
var model = PolarHeatMap();
model.Title = "Polar heat map with fixed size image";
((PolarHeatMapSeries)model.Series[0]).ImageSize = 800;
return model;
}
[Example("PolarHeatMap on linear axes")]
public static PlotModel PolarHeatMapLinearAxes()
{
var model = new PlotModel { Title = "Polar heat map on linear axes" };
var matrix = new double[2, 2];
matrix[0, 0] = 0;
matrix[0, 1] = 2;
matrix[1, 0] = 1.5;
matrix[1, 1] = 0.2;
model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -100, Maximum = 100 });
model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 100 });
model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Rainbow(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black });
model.Series.Add(new PolarHeatMapSeries { Data = matrix, Angle0 = 30, Angle1 = 150, Magnitude0 = 0, Magnitude1 = 80, Interpolate = true });
return model;
}
[Example("PolarHeatMap linear axes, fixed size image (256x256)")]
public static PlotModel PolarHeatMapLinearAxesFixed256()
{
var model = PolarHeatMapLinearAxes();
model.Title = "Polar heat map on linear axes & fixed size image (256x256)";
((PolarHeatMapSeries)model.Series[0]).ImageSize = 256;
return model;
}
[Example("PolarHeatMap linear axes, fixed size image (1000x1000)")]
public static PlotModel PolarHeatMapLinearAxesFixed1000()
{
var model = PolarHeatMapLinearAxes();
model.Title = "Polar heat map on linear axes & fixed size image (1000x1000)";
((PolarHeatMapSeries)model.Series[0]).ImageSize = 1000;
return model;
}
[Example("Design structure matrix (DSM)")]
public static PlotModel DesignStructureMatrix()
{
// See also http://en.wikipedia.org/wiki/Design_structure_matrix
var data = new double[7, 7];
// indexing: data[column,row]
data[1, 0] = 1;
data[5, 0] = 1;
data[3, 1] = 1;
data[0, 2] = 1;
data[6, 2] = 1;
data[4, 3] = 1;
data[1, 4] = 1;
data[5, 4] = 1;
data[2, 5] = 1;
data[0, 6] = 1;
data[4, 6] = 1;
for (int i = 0; i < 7; i++)
{
data[i, i] = -1;
}
var model = new PlotModel { Title = "Design structure matrix (DSM)" };
model.Axes.Add(new LinearColorAxis { Position = AxisPosition.None, Palette = new OxyPalette(OxyColors.White, OxyColors.LightGreen), LowColor = OxyColors.Black, Minimum = 0, IsAxisVisible = false });
var topAxis = new CategoryAxis
{
Position = AxisPosition.Top
};
topAxis.Labels.AddRange(new[] { "A", "B", "C", "D", "E", "F", "G" });
model.Axes.Add(topAxis);
var leftAxis = new CategoryAxis
{
Position = AxisPosition.Left,
StartPosition = 1,
EndPosition = 0
};
leftAxis.Labels.AddRange(new[] { "Element A", "Element B", "Element C", "Element D", "Element E", "Element F", "Element G" });
model.Axes.Add(leftAxis);
var hms = new DesignStructureMatrixSeries
{
Data = data,
Interpolate = false,
LabelFormatString = "#",
LabelFontSize = 0.25,
X0 = 0,
X1 = data.GetLength(0) - 1,
Y0 = 0,
Y1 = data.GetLength(1) - 1,
};
model.Series.Add(hms);
return model;
}
}
public class DesignStructureMatrixSeries : HeatMapSeries
{
protected override string GetLabel(double v, int i, int j)
{
if (i == j)
{
return ((CategoryAxis)this.XAxis).Labels[i];
}
return base.GetLabel(v, i, j);
}
}
}

View File

@@ -0,0 +1,70 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ErrorItem.cs" company="OxyPlot">
// Copyright (c) 2014 OxyPlot contributors
// </copyright>
// <summary>
// Represents an error item.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ExampleLibrary
{
using OxyPlot;
/// <summary>
/// Represents an error item.
/// </summary>
public class ErrorItem
{
/// <summary>
/// Initializes a new instance of the <see cref="ErrorItem" /> class.
/// </summary>
public ErrorItem()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ErrorItem" /> class.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="xerror">The xerror.</param>
/// <param name="yerror">The yerror.</param>
public ErrorItem(double x, double y, double xerror, double yerror)
{
this.X = x;
this.Y = y;
this.XError = xerror;
this.YError = yerror;
}
/// <summary>
/// Gets or sets the X.
/// </summary>
public double X { get; set; }
/// <summary>
/// Gets or sets the Y.
/// </summary>
public double Y { get; set; }
/// <summary>
/// Gets or sets the X error.
/// </summary>
public double XError { get; set; }
/// <summary>
/// Gets or sets the Y error.
/// </summary>
public double YError { get; set; }
/// <summary>
/// Returns c# code that generates this instance.
/// </summary>
/// <returns>C# code.</returns>
public string ToCode()
{
return CodeGenerator.FormatConstructor(this.GetType(), "{0},{1},{2},{3}", this.X, this.Y, this.XError, this.YError);
}
}
}

View File

@@ -0,0 +1,163 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ErrorSeries.cs" company="OxyPlot">
// Copyright (c) 2014 OxyPlot contributors
// </copyright>
// <summary>
// Represents an error series.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ExampleLibrary
{
using System;
using System.Collections.Generic;
using OxyPlot;
using OxyPlot.Series;
/// <summary>
/// Represents an error series.
/// </summary>
public class ErrorSeries : XYAxisSeries
{
/// <summary>
/// The list of error items.
/// </summary>
private readonly List<ErrorItem> points = new List<ErrorItem>();
/// <summary>
/// Initializes a new instance of the <see cref="ErrorSeries" /> class.
/// </summary>
public ErrorSeries()
{
this.Color = OxyColors.Black;
this.StrokeThickness = 1;
}
/// <summary>
/// Gets or sets the color.
/// </summary>
/// <value>The color.</value>
public OxyColor Color { get; set; }
/// <summary>
/// Gets the list of points.
/// </summary>
/// <value>A list of <see cref="ErrorItem" />.</value>
public List<ErrorItem> Points
{
get
{
return this.points;
}
}
/// <summary>
/// Gets or sets the stroke thickness.
/// </summary>
/// <value>The stroke thickness.</value>
public double StrokeThickness { get; set; }
/// <summary>
/// Renders the series on the specified render context.
/// </summary>
/// <param name="rc">The rendering context.</param>
public override void Render(IRenderContext rc)
{
var points = this.Points;
if (points.Count == 0)
{
return;
}
this.VerifyAxes();
int n = points.Count;
// Transform all points to screen coordinates
var segments = new List<ScreenPoint>(n * 6);
for (int i = 0; i < n; i++)
{
var sp = XAxis.Transform(points[i].X, points[i].Y, YAxis);
var ei = points[i];
double errorx = ei != null ? ei.XError * XAxis.Scale : 0;
double errory = ei != null ? ei.YError * Math.Abs(YAxis.Scale) : 0;
double d = 4;
if (errorx > 0)
{
var p0 = new ScreenPoint(sp.X - (errorx * 0.5), sp.Y);
var p1 = new ScreenPoint(sp.X + (errorx * 0.5), sp.Y);
segments.Add(p0);
segments.Add(p1);
segments.Add(new ScreenPoint(p0.X, p0.Y - d));
segments.Add(new ScreenPoint(p0.X, p0.Y + d));
segments.Add(new ScreenPoint(p1.X, p1.Y - d));
segments.Add(new ScreenPoint(p1.X, p1.Y + d));
}
if (errory > 0)
{
var p0 = new ScreenPoint(sp.X, sp.Y - (errory * 0.5));
var p1 = new ScreenPoint(sp.X, sp.Y + (errory * 0.5));
segments.Add(p0);
segments.Add(p1);
segments.Add(new ScreenPoint(p0.X - d, p0.Y));
segments.Add(new ScreenPoint(p0.X + d, p0.Y));
segments.Add(new ScreenPoint(p1.X - d, p1.Y));
segments.Add(new ScreenPoint(p1.X + d, p1.Y));
}
}
// clip the line segments with the clipping rectangle
for (int i = 0; i + 1 < segments.Count; i += 2)
{
rc.DrawReducedLine(
new[] { segments[i], segments[i + 1] },
0,
this.GetSelectableColor(this.Color),
this.StrokeThickness,
this.EdgeRenderingMode,
null,
LineJoin.Bevel);
}
}
/// <summary>
/// Renders the legend symbol on the specified rendering context.
/// </summary>
/// <param name="rc">The rendering context.</param>
/// <param name="legendBox">The legend rectangle.</param>
public override void RenderLegend(IRenderContext rc, OxyRect legendBox)
{
double xmid = (legendBox.Left + legendBox.Right) * 0.5;
double ymid = (legendBox.Top + legendBox.Bottom) * 0.5;
var pts = new[]
{
new ScreenPoint(legendBox.Left, ymid),
new ScreenPoint(legendBox.Right, ymid),
new ScreenPoint(legendBox.Left, ymid - 2),
new ScreenPoint(legendBox.Left, ymid + 3),
new ScreenPoint(legendBox.Right, ymid - 2),
new ScreenPoint(legendBox.Right, ymid + 3),
new ScreenPoint(xmid, legendBox.Top),
new ScreenPoint(xmid, legendBox.Bottom),
new ScreenPoint(xmid - 2, legendBox.Top),
new ScreenPoint(xmid + 3, legendBox.Top),
new ScreenPoint(xmid - 2, legendBox.Bottom),
new ScreenPoint(xmid + 3, legendBox.Bottom)
};
rc.DrawLineSegments(pts, this.GetSelectableColor(this.Color), this.StrokeThickness, this.EdgeRenderingMode, null, LineJoin.Miter);
}
/// <summary>
/// Updates the maximum and minimum values of the series.
/// </summary>
protected override void UpdateMaxMin()
{
base.UpdateMaxMin();
this.InternalUpdateMaxMin(this.points, p => p.X - p.XError, p => p.X + p.XError, p => p.Y - p.YError, p => p.Y + p.YError);
}
}
}

View File

@@ -0,0 +1,236 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="FlagSeries.cs" company="OxyPlot">
// Copyright (c) 2014 OxyPlot contributors
// </copyright>
// <summary>
// Renders a 'flag' above the x-axis at the specified positions (in the Values list).
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ExampleLibrary
{
using System.Collections.Generic;
using System.Linq;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
/// <summary>
/// Renders a 'flag' above the x-axis at the specified positions (in the Values list).
/// </summary>
public class FlagSeries : ItemsSeries
{
/// <summary>
/// The symbol position (y coordinate).
/// </summary>
private double symbolPosition;
/// <summary>
/// The symbol text size.
/// </summary>
private OxySize symbolSize;
/// <summary>
/// Initializes a new instance of the <see cref="FlagSeries" /> class.
/// </summary>
public FlagSeries()
{
this.Values = new List<double>();
this.Color = OxyColors.Black;
this.FontSize = 10;
this.Symbol = ((char)0xEA).ToString();
this.Font = "Wingdings 2";
this.TrackerFormatString = "{0}: {1}";
}
/// <summary>
/// Gets or sets the color of the symbols.
/// </summary>
/// <value>The color.</value>
public OxyColor Color { get; set; }
/// <summary>
/// Gets the maximum value.
/// </summary>
/// <value>The maximum value.</value>
public double MaximumX { get; private set; }
/// <summary>
/// Gets the minimum value.
/// </summary>
/// <value>The minimum value.</value>
public double MinimumX { get; private set; }
/// <summary>
/// Gets or sets the symbol to draw at each value.
/// </summary>
/// <value>The symbol.</value>
public string Symbol { get; set; }
/// <summary>
/// Gets the values.
/// </summary>
/// <value>The values.</value>
public List<double> Values { get; private set; }
/// <summary>
/// Gets the x-axis.
/// </summary>
/// <value>The x-axis.</value>
public Axis XAxis { get; private set; }
/// <summary>
/// Gets or sets the x-axis key.
/// </summary>
/// <value>The x-axis key.</value>
public string XAxisKey { get; set; }
/// <summary>
/// Gets the point on the series that is nearest the specified point.
/// </summary>
/// <param name="point">The point.</param>
/// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param>
/// <returns>A TrackerHitResult for the current hit.</returns>
public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate)
{
foreach (var v in this.Values)
{
if (double.IsNaN(v) || v < this.XAxis.ActualMinimum || v > this.XAxis.ActualMaximum)
{
continue;
}
double x = this.XAxis.Transform(v);
var r = new OxyRect(x - (this.symbolSize.Width / 2), this.symbolPosition - this.symbolSize.Height, this.symbolSize.Width, this.symbolSize.Height);
if (r.Contains(point))
{
return new TrackerHitResult
{
Series = this,
DataPoint = new DataPoint(v, double.NaN),
Position = new ScreenPoint(x, this.symbolPosition - this.symbolSize.Height),
Text = StringHelper.Format(this.ActualCulture, this.TrackerFormatString, null, this.Title, v)
};
}
}
return null;
}
/// <summary>
/// Renders the series on the specified render context.
/// </summary>
/// <param name="rc">The rendering context.</param>
public override void Render(IRenderContext rc)
{
if (this.XAxis == null)
{
return;
}
this.symbolPosition = this.PlotModel.PlotArea.Bottom;
this.symbolSize = rc.MeasureText(this.Symbol, this.ActualFont, this.ActualFontSize);
foreach (var v in this.Values)
{
if (double.IsNaN(v) || v < this.XAxis.ClipMinimum || v > this.XAxis.ClipMaximum)
{
continue;
}
double x = this.XAxis.Transform(v);
rc.DrawText(
new ScreenPoint(x, this.symbolPosition),
this.Symbol,
this.Color,
this.ActualFont,
this.ActualFontSize,
this.ActualFontWeight,
0,
HorizontalAlignment.Center,
VerticalAlignment.Bottom);
}
}
/// <summary>
/// Renders the legend symbol on the specified render context.
/// </summary>
/// <param name="rc">The rendering context.</param>
/// <param name="legendBox">The legend rectangle.</param>
public override void RenderLegend(IRenderContext rc, OxyRect legendBox)
{
rc.DrawText(
legendBox.Center,
this.Symbol,
this.Color,
this.ActualFont,
this.ActualFontSize,
this.ActualFontWeight,
0,
HorizontalAlignment.Center,
VerticalAlignment.Middle);
}
/// <summary>
/// Check if this data series requires X/Y axes. (e.g. Pie series do not require axes)
/// </summary>
/// <returns>True if no axes are required.</returns>
protected override bool AreAxesRequired()
{
return true;
}
/// <summary>
/// Ensures that the axes of the series is defined.
/// </summary>
protected override void EnsureAxes()
{
this.XAxis = this.XAxisKey != null ?
this.PlotModel.GetAxis(this.XAxisKey) :
this.PlotModel.DefaultXAxis;
}
/// <summary>
/// Check if the data series is using the specified axis.
/// </summary>
/// <param name="axis">An axis which should be checked if used</param>
/// <returns>True if the axis is in use.</returns>
protected override bool IsUsing(Axis axis)
{
return axis == this.XAxis;
}
/// <summary>
/// Sets default values (colors, line style etc) from the plot model.
/// </summary>
protected override void SetDefaultValues()
{
}
/// <summary>
/// Updates the axis maximum and minimum values.
/// </summary>
protected override void UpdateAxisMaxMin()
{
this.XAxis.Include(this.MinimumX);
this.XAxis.Include(this.MaximumX);
}
/// <summary>
/// Updates the data from the ItemsSource.
/// </summary>
protected override void UpdateData()
{
// todo
}
/// <summary>
/// Updates the maximum and minimum values of the series.
/// </summary>
protected override void UpdateMaxMin()
{
this.MinimumX = this.Values.Min();
this.MaximumX = this.Values.Max();
}
}
}

View File

@@ -0,0 +1,165 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="LineSegmentSeries.cs" company="OxyPlot">
// Copyright (c) 2014 OxyPlot contributors
// </copyright>
// <summary>
// Represents a line series where the points collection define line segments.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ExampleLibrary
{
using System;
using System.Collections.Generic;
using System.Linq;
using OxyPlot;
using OxyPlot.Series;
/// <summary>
/// Represents a line series where the points collection define line segments.
/// </summary>
public class LineSegmentSeries : LineSeries
{
/// <summary>
/// Initializes a new instance of the <see cref="LineSegmentSeries" /> class.
/// </summary>
public LineSegmentSeries()
{
this.ShowVerticals = true;
this.Epsilon = 1e-8;
}
/// <summary>
/// Gets or sets a value indicating whether to show vertical lines where there is no gap in x-coordinate.
/// </summary>
/// <value><c>true</c> if verticals should be shown; otherwise, <c>false</c>.</value>
public bool ShowVerticals { get; set; }
/// <summary>
/// Gets or sets the x-coordinate gap tolerance.
/// </summary>
/// <value>The epsilon value.</value>
public double Epsilon { get; set; }
/// <summary>
/// Renders the series on the specified rendering context.
/// </summary>
/// <param name="rc">The rendering context.</param>
public override void Render(IRenderContext rc)
{
if (Points.Count == 0)
{
return;
}
if (Points.Count % 2 != 0)
{
throw new InvalidOperationException("The number of points should be even.");
}
if (this.XAxis == null || this.YAxis == null)
{
throw new InvalidOperationException("Axis has not been defined.");
}
var screenPoints = Points.Select(this.Transform).ToList();
var verticalLines = new List<ScreenPoint>();
for (int i = 0; i < screenPoints.Count; i += 2)
{
if (screenPoints[i].DistanceToSquared(screenPoints[i + 1]) < this.StrokeThickness)
{
screenPoints[i] = new ScreenPoint(screenPoints[i].X - (this.StrokeThickness * 0.5), screenPoints[i].Y);
screenPoints[i + 1] = new ScreenPoint(screenPoints[i].X + (this.StrokeThickness * 0.5), screenPoints[i].Y);
}
if (this.ShowVerticals && i > 0 && Math.Abs(screenPoints[i - 1].X - screenPoints[i].X) < this.Epsilon)
{
verticalLines.Add(screenPoints[i - 1]);
verticalLines.Add(screenPoints[i]);
}
}
if (this.StrokeThickness > 0)
{
if (this.LineStyle != LineStyle.None)
{
rc.DrawLineSegments(screenPoints, this.ActualColor, this.StrokeThickness, this.EdgeRenderingMode, this.LineStyle.GetDashArray(), this.LineJoin);
}
rc.DrawLineSegments(verticalLines, this.ActualColor, this.StrokeThickness / 3, this.EdgeRenderingMode, LineStyle.Dash.GetDashArray(), this.LineJoin);
}
rc.DrawMarkers(screenPoints, this.MarkerType, null, this.MarkerSize, this.MarkerFill, this.MarkerStroke, this.MarkerStrokeThickness, this.EdgeRenderingMode);
}
/// <summary>
/// Gets the point on the series that is nearest the specified point.
/// </summary>
/// <param name="point">The point.</param>
/// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param>
/// <returns>A TrackerHitResult for the current hit.</returns>
public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate)
{
var points = this.Points;
if (points == null)
{
return null;
}
var spn = default(ScreenPoint);
var dpn = default(DataPoint);
double index = -1;
double minimumDistance = double.MaxValue;
for (int i = 0; i + 1 < points.Count; i += 2)
{
var p1 = points[i];
var p2 = points[i + 1];
if (!this.IsValidPoint(p1) || !this.IsValidPoint(p2))
{
continue;
}
var sp1 = this.Transform(p1);
var sp2 = this.Transform(p2);
// Find the nearest point on the line segment.
var spl = ScreenPointHelper.FindPointOnLine(point, sp1, sp2);
if (ScreenPoint.IsUndefined(spl))
{
// P1 && P2 coincident
continue;
}
double l2 = (point - spl).LengthSquared;
if (l2 < minimumDistance)
{
double u = (spl - sp1).Length / (sp2 - sp1).Length;
dpn = new DataPoint(p1.X + (u * (p2.X - p1.X)), p1.Y + (u * (p2.Y - p1.Y)));
spn = spl;
minimumDistance = l2;
index = i + u;
}
}
if (minimumDistance < double.MaxValue)
{
return new TrackerHitResult
{
Series = this,
DataPoint = dpn,
Position = spn,
Item = this.GetItem((int)index),
Index = index
};
}
return null;
}
}
}

View File

@@ -0,0 +1,236 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MatrixSeries.cs" company="OxyPlot">
// Copyright (c) 2014 OxyPlot contributors
// </copyright>
// <summary>
// Provides a series that visualizes the structure of a matrix.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ExampleLibrary
{
using System;
using System.Collections.Generic;
using OxyPlot;
using OxyPlot.Series;
/// <summary>
/// Provides a series that visualizes the structure of a matrix.
/// </summary>
public class MatrixSeries : XYAxisSeries
{
/// <summary>
/// The image
/// </summary>
private OxyImage image;
/// <summary>
/// The matrix
/// </summary>
private double[,] matrix;
/// <summary>
/// Initializes a new instance of the <see cref="MatrixSeries" /> class.
/// </summary>
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}";
}
/// <summary>
/// Gets or sets the matrix.
/// </summary>
public double[,] Matrix
{
get
{
return this.matrix;
}
set
{
this.image = null;
this.matrix = value;
}
}
/// <summary>
/// Gets or sets the interval between the grid lines (the grid is hidden if value is 0).
/// </summary>
public int GridInterval { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to show the diagonal.
/// </summary>
/// <value><c>true</c> if the diagonal should be shown; otherwise, <c>false</c>.</value>
public bool ShowDiagonal { get; set; }
/// <summary>
/// Gets or sets the minimum grid line distance.
/// </summary>
public double MinimumGridLineDistance { get; set; }
/// <summary>
/// Gets or sets the color of the grid.
/// </summary>
/// <value>The color of the grid.</value>
public OxyColor GridColor { get; set; }
/// <summary>
/// Gets or sets the color of the border around the matrix.
/// </summary>
/// <value>The color of the border.</value>
public OxyColor BorderColor { get; set; }
/// <summary>
/// Gets or sets the color of the not zero elements of the matrix.
/// </summary>
public OxyColor NotZeroColor { get; set; }
/// <summary>
/// Gets or sets the zero tolerance (inclusive).
/// </summary>
/// <value>The zero tolerance.</value>
public double ZeroTolerance { get; set; }
/// <summary>
/// Gets the point on the series that is nearest the specified point.
/// </summary>
/// <param name="point">The point.</param>
/// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param>
/// <returns>A TrackerHitResult for the current hit.</returns>
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;
}
/// <summary>
/// Renders the series on the specified render context.
/// </summary>
/// <param name="rc">The rendering context.</param>
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<ScreenPoint>();
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);
}
}
/// <summary>
/// Updates the maximum and minimum values of the series.
/// </summary>
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);
}
}
}

View File

@@ -0,0 +1,397 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PolarHeatMapSeries.cs" company="OxyPlot">
// Copyright (c) 2014 OxyPlot contributors
// </copyright>
// <summary>
// Implements a polar heat map series.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace OxyPlot.Series
{
using System;
using System.Collections.Generic;
using System.Linq;
using OxyPlot.Axes;
/// <summary>
/// Implements a polar heat map series.
/// </summary>
public class PolarHeatMapSeries : XYAxisSeries
{
/// <summary>
/// The image
/// </summary>
private OxyImage image;
/// <summary>
/// The pixels
/// </summary>
private OxyColor[,] pixels;
/// <summary>
/// Initializes a new instance of the <see cref="PolarHeatMapSeries" /> class.
/// </summary>
public PolarHeatMapSeries()
{
this.Interpolate = true;
}
/// <summary>
/// Gets or sets the size of the image - if set to 0, the image will be generated at every update.
/// </summary>
/// <value>The size of the image.</value>
public int ImageSize { get; set; }
/// <summary>
/// Gets or sets the x-coordinate of the left column mid point.
/// </summary>
public double Angle0 { get; set; }
/// <summary>
/// Gets or sets the x-coordinate of the right column mid point.
/// </summary>
public double Angle1 { get; set; }
/// <summary>
/// Gets or sets the y-coordinate of the top row mid point.
/// </summary>
public double Magnitude0 { get; set; }
/// <summary>
/// Gets or sets the y-coordinate of the bottom row mid point.
/// </summary>
public double Magnitude1 { get; set; }
/// <summary>
/// Gets or sets the data array.
/// </summary>
/// <remarks>Note that the indices of the data array refer to [x,y].</remarks>
public double[,] Data { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to interpolate when rendering.
/// </summary>
/// <remarks>This property is not supported on all platforms.</remarks>
public bool Interpolate { get; set; }
/// <summary>
/// Gets or sets the minimum value of the dataset.
/// </summary>
public double MinValue { get; protected set; }
/// <summary>
/// Gets or sets the maximum value of the dataset.
/// </summary>
public double MaxValue { get; protected set; }
/// <summary>
/// Gets or sets the color axis.
/// </summary>
/// <value>The color axis.</value>
public IColorAxis ColorAxis { get; protected set; }
/// <summary>
/// Gets or sets the color axis key.
/// </summary>
/// <value>The color axis key.</value>
public string ColorAxisKey { get; set; }
/// <summary>
/// Renders the series on the specified render context.
/// </summary>
/// <param name="rc">The rendering context.</param>
public override void Render(IRenderContext rc)
{
if (this.Data == null)
{
this.image = null;
return;
}
if (this.ImageSize > 0)
{
this.RenderFixed(rc, this.PlotModel);
}
else
{
this.RenderDynamic(rc, this.PlotModel);
}
}
/// <summary>
/// Renders by an image sized from the available plot area.
/// </summary>
/// <param name="rc">The rc.</param>
/// <param name="model">The model.</param>
public void RenderDynamic(IRenderContext rc, PlotModel model)
{
int m = this.Data.GetLength(0);
int n = this.Data.GetLength(1);
// get the available plot area
var dest = model.PlotArea;
int width = (int)dest.Width;
int height = (int)dest.Height;
if (width == 0 || height == 0)
{
return;
}
if (this.pixels == null || this.pixels.GetLength(0) != height || this.pixels.GetLength(1) != width)
{
this.pixels = new OxyColor[width, height];
}
var p = this.pixels;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// transform from screen to magnitude/angle
var sp = new ScreenPoint(dest.Left + x, dest.Top + y);
var xy = this.InverseTransform(sp);
double angle;
double magnitude;
if (this.PlotModel.PlotType != PlotType.Polar)
{
angle = Math.Atan2(xy.Y, xy.X) / Math.PI * 180;
magnitude = Math.Sqrt((xy.X * xy.X) + (xy.Y * xy.Y));
}
else
{
angle = xy.Y / Math.PI * 180;
magnitude = xy.X;
while (angle < 0)
{
angle += 360;
}
while (angle > 360)
{
angle -= 360;
}
}
// transform to indices in the Data array
var ii = (angle - this.Angle0) / (this.Angle1 - this.Angle0) * m;
var jj = (magnitude - this.Magnitude0) / (this.Magnitude1 - this.Magnitude0) * n;
if (ii >= 0 && ii < m && jj >= 0 && jj < n)
{
// get the (interpolated) value
var value = this.GetValue(ii, jj);
// use the color axis to get the color
p[x, y] = OxyColor.FromAColor(160, this.ColorAxis.GetColor(value));
}
else
{
// outside the range of the Data array
p[x, y] = OxyColors.Transparent;
}
}
}
// Create the PNG image
this.image = OxyImage.Create(p, ImageFormat.Png);
// Render the image
rc.DrawImage(this.image, dest.Left, dest.Top, dest.Width, dest.Height, 1, false);
}
/// <summary>
/// Refreshes the image next time the series is rendered.
/// </summary>
public void Refresh()
{
this.image = null;
}
/// <summary>
/// Renders by scaling a fixed image.
/// </summary>
/// <param name="rc">The render context.</param>
/// <param name="model">The model.</param>
public void RenderFixed(IRenderContext rc, PlotModel model)
{
if (image == null)
{
int m = this.Data.GetLength(0);
int n = this.Data.GetLength(1);
int width = this.ImageSize;
int height = this.ImageSize;
if (this.pixels == null || this.pixels.GetLength(0) != height || this.pixels.GetLength(1) != width)
{
this.pixels = new OxyColor[width, height];
}
var p = this.pixels;
for (int yi = 0; yi < height; yi++)
{
for (int xi = 0; xi < width; xi++)
{
double x = (xi - width * 0.5) / (width * 0.5) * this.Magnitude1;
double y = -(yi - height * 0.5) / (height * 0.5) * this.Magnitude1;
double angle = Math.Atan2(y, x) / Math.PI * 180;
double magnitude = Math.Sqrt(x * x + y * y);
while (angle < 0)
{
angle += 360;
}
while (angle > 360)
{
angle -= 360;
}
// transform to indices in the Data array
var ii = (angle - this.Angle0) / (this.Angle1 - this.Angle0) * m;
var jj = (magnitude - this.Magnitude0) / (this.Magnitude1 - this.Magnitude0) * n;
if (ii >= 0 && ii < m && jj >= 0 && jj < n)
{
// get the (interpolated) value
var value = this.GetValue(ii, jj);
// use the color axis to get the color
p[xi, yi] = OxyColor.FromAColor(160, this.ColorAxis.GetColor(value));
}
else
{
// outside the range of the Data array
p[xi, yi] = OxyColors.Transparent;
}
}
}
// Create the PNG image
this.image = OxyImage.Create(p, ImageFormat.Png);
}
OxyRect dest;
if (this.PlotModel.PlotType != PlotType.Polar)
{
var topleft = this.Transform(-this.Magnitude1, this.Magnitude1);
var bottomright = this.Transform(this.Magnitude1, -this.Magnitude1);
dest = new OxyRect(topleft.X, topleft.Y, bottomright.X - topleft.X, bottomright.Y - topleft.Y);
}
else
{
var top = this.Transform(this.Magnitude1, 90);
var bottom = this.Transform(this.Magnitude1, 270);
var left = this.Transform(this.Magnitude1, 180);
var right = this.Transform(this.Magnitude1, 0);
dest = new OxyRect(left.X, top.Y, right.X - left.X, bottom.Y - top.Y);
}
// Render the image
rc.DrawImage(this.image, dest.Left, dest.Top, dest.Width, dest.Height, 1, false);
}
/// <summary>
/// Gets the value at the specified data indices.
/// </summary>
/// <param name="ii">The first index in the Data array.</param>
/// <param name="jj">The second index in the Data array.</param>
/// <returns>The value.</returns>
protected virtual double GetValue(double ii, double jj)
{
if (!this.Interpolate)
{
var i = (int)Math.Floor(ii);
var j = (int)Math.Floor(jj);
return this.Data[i, j];
}
ii -= 0.5;
jj -= 0.5;
// bi-linear interpolation http://en.wikipedia.org/wiki/Bilinear_interpolation
var r = (int)Math.Floor(ii);
var c = (int)Math.Floor(jj);
int r0 = r > 0 ? r : 0;
int r1 = r + 1 < this.Data.GetLength(0) ? r + 1 : r;
int c0 = c > 0 ? c : 0;
int c1 = c + 1 < this.Data.GetLength(1) ? c + 1 : c;
double v00 = this.Data[r0, c0];
double v01 = this.Data[r0, c1];
double v10 = this.Data[r1, c0];
double v11 = this.Data[r1, c1];
double di = ii - r;
double dj = jj - c;
double v0 = (v00 * (1 - dj)) + (v01 * dj);
double v1 = (v10 * (1 - dj)) + (v11 * dj);
return (v0 * (1 - di)) + (v1 * di);
}
/// <summary>
/// Gets the point on the series that is nearest the specified point.
/// </summary>
/// <param name="point">The point.</param>
/// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param>
/// <returns>A TrackerHitResult for the current hit.</returns>
public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate)
{
return null;
}
/// <summary>
/// Ensures that the axes of the series is defined.
/// </summary>
protected override void EnsureAxes()
{
base.EnsureAxes();
this.ColorAxis = this.ColorAxisKey != null ?
this.PlotModel.GetAxis(this.ColorAxisKey) as IColorAxis :
this.PlotModel.DefaultColorAxis as IColorAxis;
}
/// <summary>
/// Updates the maximum and minimum values of the series.
/// </summary>
protected override void UpdateMaxMin()
{
base.UpdateMaxMin();
this.MinValue = this.GetData().Min();
this.MaxValue = this.GetData().Max();
//this.XAxis.Include(this.MinX);
//this.XAxis.Include(this.MaxX);
//this.YAxis.Include(this.MinY);
//this.YAxis.Include(this.MaxY);
var colorAxis = this.ColorAxis as Axis;
if (colorAxis != null)
{
colorAxis.Include(this.MinValue);
colorAxis.Include(this.MaxValue);
}
}
/// <summary>
/// Gets the data as a sequence (LINQ-friendly).
/// </summary>
/// <returns>The sequence of data.</returns>
protected IEnumerable<double> GetData()
{
int m = this.Data.GetLength(0);
int n = this.Data.GetLength(1);
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
yield return this.Data[i, j];
}
}
}
}
}