库的下载
项目的引用右键,选择“管理NuGet程序包”,搜索OxyPlot,安装OxyPlot.WindowsForms
或者直接引用OxyPlot.dll,和OxyPlot.WIndowsForms.dll文件,在此处下载。
HelloWorld
首先在Form上创建一个PlotView控件,暂时无法直接拖入。
可以在InitializeComponent下调用InitPlot();
private void InitPlot() { this.plot1 = new OxyPlot.WindowsForms.PlotView(); this.SuspendLayout(); this.plot1.Dock = System.Windows.Forms.DockStyle.Fill; this.plot1.Location = new System.Drawing.Point(0, 0); this.plot1.Name = "plot1"; this.plot1.TabIndex = 0; this.plot1.Margin = new System.Windows.Forms.Padding(0); this.Controls.Add(this.plot1); this.ResumeLayout(); }
注意:如果是在Form的一个Panel下添加PlotView,
可以这样
this.panel1.Controls.Add(this.plot1);
然后创建Model,整体代码如下
public Form1() { InitializeComponent(); InitPlot(); var myModel = new PlotModel { Title = "Example 1" }; myModel.Series.Add(new FunctionSeries(Math.Cos, 0, 10, 0.1, "cos(x)")); this.plot1.Model = myModel; }
改变背景色,添加曲线
var myModel = new PlotModel { Title = "Example 1" ,Background=OxyColors.White}; myModel.Series.Add(new FunctionSeries(Math.Cos, 0, 10, 0.1, "cos(x)")); myModel.Series.Add(new FunctionSeries(Math.Sin, -10, 10, 0.1, "sin(x)")); myModel.Series.Add(new FunctionSeries(t => 5 * Math.Cos(t), t => 5 * Math.Sin(t), 0, 2 * Math.PI, 0.1, "cos(t),sin(t)")); this.plot1.Model = myModel;
一个实时更新曲线的例子
来源https://blog.csdn.net/weixin_42930928/article/details/81706540
public partial class Form1 : Form { private PlotView plot1; public Form1() { InitializeComponent(); InitPlot(); } private void InitPlot() { this.plot1 = new OxyPlot.WindowsForms.PlotView(); this.SuspendLayout(); this.plot1.Dock = System.Windows.Forms.DockStyle.Fill; this.plot1.Location = new System.Drawing.Point(0, 0); this.plot1.Name = "plot1"; this.plot1.TabIndex = 0; this.plot1.Margin = new System.Windows.Forms.Padding(0); this.panel1.Controls.Add(this.plot1); this.ResumeLayout(); } private PlotModel _myPlotModel; private DateTimeAxis _dateAxis; private LinearAxis _valueAxis; private Random rand = new Random(); private void Form1_Load(object sender, EventArgs e) { _myPlotModel = new PlotModel() { Title = "Temp & Humi", LegendTitle = "Legend", LegendOrientation = LegendOrientation.Horizontal, LegendPlacement = LegendPlacement.Inside, LegendPosition = LegendPosition.TopRight, LegendBackground = OxyColor.FromAColor(200, OxyColors.Beige), LegendBorder = OxyColors.Black }; //X轴 _dateAxis = new DateTimeAxis() { MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Dot, IntervalLength = 80, //IsZoomEnabled = false, //IsPanEnabled = false }; _myPlotModel.Axes.Add(_dateAxis); //Y轴 _valueAxis = new LinearAxis() { MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Dot, IntervalLength = 80, Angle = 60, IsZoomEnabled = false, IsPanEnabled = false, Maximum = 100, Minimum = -1 }; _myPlotModel.Axes.Add(_valueAxis); //添加标注线,温度上下限和湿度上下限 var lineTempMaxAnnotation = new OxyPlot.Annotations.LineAnnotation() { Type = LineAnnotationType.Horizontal, Color = OxyColors.Red, LineStyle = LineStyle.Solid, Y = 10, Text = "Temp MAX:10" }; _myPlotModel.Annotations.Add(lineTempMaxAnnotation); var lineTempMinAnnotation = new LineAnnotation() { Type = LineAnnotationType.Horizontal, Y = 30, Text = "Temp Min:30", Color = OxyColors.Red, LineStyle = LineStyle.Solid }; _myPlotModel.Annotations.Add(lineTempMinAnnotation); var lineHumiMaxAnnotation = new OxyPlot.Annotations.LineAnnotation() { Type = LineAnnotationType.Horizontal, Color = OxyColors.Red, LineStyle = LineStyle.Solid, //lineMaxAnnotation.MaximumX = 0.8; Y = 75, Text = "Humi MAX:75" }; _myPlotModel.Annotations.Add(lineHumiMaxAnnotation); var lineHumiMinAnnotation = new LineAnnotation() { Type = LineAnnotationType.Horizontal, Y = 35, Text = "Humi Min:35", Color = OxyColors.Red, LineStyle = LineStyle.Solid }; _myPlotModel.Annotations.Add(lineHumiMinAnnotation); //添加两条曲线 var series = new LineSeries() { Color = OxyColors.Green, StrokeThickness = 2, MarkerSize = 3, MarkerStroke = OxyColors.DarkGreen, MarkerType = MarkerType.Diamond, Title = "Temp", }; _myPlotModel.Series.Add(series); series = new LineSeries() { Color = OxyColors.Blue, StrokeThickness = 2, MarkerSize = 3, MarkerStroke = OxyColors.BlueViolet, MarkerType = MarkerType.Star, Title = "Humi", }; _myPlotModel.Series.Add(series); plot1.Model = _myPlotModel; Task.Factory.StartNew(() => { while (true) { var date = DateTime.Now; _myPlotModel.Axes[0].Maximum = DateTimeAxis.ToDouble(date.AddSeconds(1)); var lineSer = plot1.Model.Series[0] as LineSeries; lineSer.Points.Add(new DataPoint(DateTimeAxis.ToDouble(date), rand.Next(100, 300) / 10.0)); if (lineSer.Points.Count > 100) { lineSer.Points.RemoveAt(0); } lineSer = plot1.Model.Series[1] as LineSeries; lineSer.Points.Add(new DataPoint(DateTimeAxis.ToDouble(date), rand.Next(350, 750) / 10.0)); if (lineSer.Points.Count > 100) { lineSer.Points.RemoveAt(0); } _myPlotModel.InvalidatePlot(true); Thread.Sleep(1000); } }); } }
Tricks
LinearAxis的父类中有
AbsoluteMaximum和AbsoluteMinimum
用来UI 控制,超过此范围Pan 和zoom无效。
不管你如何Pan,Zoom,将最新数据显示在最右侧的办法
以上面例子,每隔一秒,X 轴的Maximum参数增加一秒,
要让用户移动之后,让最新数据自动归位到最右侧,只需要在InvalidDatePlot之前调用_myPlotModel.ResetAllAxes();
原理:Axis 中的ViewMinimum和ViewMaximun(就是实际看到的)只有在Minimum和Maximum没有指定的时候才会重新计算,
ResetAllAxes之后,ViewMinimum和ViewMaximum根据当前Minimum的和Maximum的 数据重新计算。
(实际双击鼠标中键起同样作用)
默认右键移动坐标,换成左键
var myController = new PlotController(); myController.UnbindMouseDown(OxyMouseButton.Right); myController.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt); plot1.Controller = myController;
点击鼠标获取屏幕坐标和坐标系坐标
plot1.Model.MouseDown += Model_MouseDown; private void Model_MouseDown(object sender, OxyMouseDownEventArgs e) { //double x = e.Position.X; //double y = e.Position.Y; DataPoint p=OxyPlot.Axes.Axis.InverseTransform(e.Position, plot1.Model.DefaultXAxis, plot1.Model.DefaultYAxis); this.Text=($"X is {x} and Y is {y} and Inverse is {p.ToString()}"); }
隐藏坐标轴
创建Axis对象时,IsAxisVisible 设置为false
防止zoom过于放大
在创建轴的时候,设置MinimumRange,
坐标轴的刻度线
分为大刻度线Major 和小刻度线Minor
默认将显示的坐标轴划分为7大段(MajorTickSize)
每个大段划分为4小段(MinorTickSize),这2个值都可以设置。注意MajorTickSize设置得太大可能无效,因为要保证Label显示的美观。
在创建Axis对象时,只需要设置MajorGridLineStyle即可绘制垂直于该轴的线条。比如LineStyle.Solid
如果使用了MajorStep和MinorStep,上面的(MajorTickSize和MinorTickSize就会无效)。
会按照坐标系的值,每隔一个MajorStep的值,绘制大刻度线,绘制label。然后同理用MinorStep绘制小刻度线。
绘制随时间更新的红线
var lineAnnotation = new LineAnnotation() { Type=LineAnnotationType.Vertical, X=100, Text="Current Time", Color=OxyColors.Red, LineStyle=LineStyle.Solid }; model.Annotations.Add(lineAnnotation); //当时间变化时 (plot1.Model.Annotations[0] as LineAnnotation).X+=30; plot1.Model.InvalidatePlot(true);
综上,绘制自定义Chart
namespace OxyTestFirst { public partial class Form1 : Form { private PlotView plot1; public Form1() { InitializeComponent(); InitPlot(); } private void InitPlot() { this.plot1 = new OxyPlot.WindowsForms.PlotView(); this.SuspendLayout(); this.plot1.Dock = System.Windows.Forms.DockStyle.Fill; this.plot1.Location = new System.Drawing.Point(0, 0); this.plot1.Name = "plot1"; this.plot1.TabIndex = 0; this.plot1.Margin = new System.Windows.Forms.Padding(0); this.panel1.Controls.Add(this.plot1); this.ResumeLayout(); } //private PlotModel _myPlotModel; //private DateTimeAxis _dateAxis; //private LinearAxis _valueAxis; //private Random rand = new Random(); private void Form1_Load(object sender, EventArgs e) { int samples = 5; int distance = 179; int rectPad = 34; var model = new PlotModel() { Background = OxyColors.White, Title = "Schedule 1", TitleFont= "Arial", TitlePadding=16 }; model.Axes.Add(new LinearAxis { Title="Samples", AxisTitleDistance=16, TitleFontSize=16, Position = AxisPosition.Left, AbsoluteMaximum=samples*distance, Maximum=samples*distance, AbsoluteMinimum=0,MinimumRange=1, MajorStep=distance, MinorStep=distance, LabelFormatter=y=> { int Nr = samples - (int)y / distance + 1; return Nr > samples ? "" : Nr.ToString(); } }); model.Axes.Add(new LinearAxis { Title="Runtime", AxisTitleDistance = 16, TitleFontSize = 16, Minimum = 0, Maximum=1500, AbsoluteMinimum=0, MinimumRange=5, Position = AxisPosition.Bottom, MajorTickSize=15, MinorTickSize=5, MajorGridlineStyle=LineStyle.Solid, MajorGridlineColor=OxyColors.LightGray, LabelFormatter = time => { int hour = 0; int min = 0; int sec = 0; sec = (int)time; if (sec >= 60) { min = ((int)sec) / 60; sec = sec % 60; } if (min >= 60) { hour = min / 60; min = min % 60; } return string.Format("{0:D2}:{1:D2}:{2:D2}", hour, min, sec); } }) ; var lineAnnotation = new LineAnnotation() { Type=LineAnnotationType.Vertical, X=100, Text="当前时间", Color=OxyColors.Red, LineStyle=LineStyle.Solid }; model.Annotations.Add(lineAnnotation); var rect1 = new RectangleAnnotation() { MinimumX = 0, MaximumX = 5.9, MinimumY = distance * (samples - 1) + rectPad, MaximumY = distance * (samples) - rectPad, Fill = OxyColor.FromRgb(155, 188, 243),//sky blue Stroke=OxyColors.Transparent }; model.Annotations.Add(rect1); var rect2 = new RectangleAnnotation() { MinimumX = 6, MaximumX = 180, MinimumY = distance * (samples - 1) + 1.5*rectPad, MaximumY = distance * (samples) - 1.5*rectPad, Fill = OxyColor.FromRgb(191, 2, 1),//red Stroke = OxyColors.Transparent }; var rect3 = new RectangleAnnotation() { MinimumX = 180.1, MaximumX = 240, MinimumY = distance * (samples - 1) + rectPad, MaximumY = distance * (samples) - rectPad, Fill = OxyColor.FromRgb(254, 152, 14), Stroke = OxyColors.Transparent//organge }; var rect4 = new RectangleAnnotation() { MinimumX = 180.1, MaximumX = 480, MinimumY = distance * (samples - 1) + 1.5 * rectPad, MaximumY = distance * (samples) - 1.5 * rectPad, Fill = OxyColor.FromRgb(254, 191, 20),//yellow Stroke = OxyColors.Transparent }; model.Annotations.Add(rect3); model.Annotations.Add(rect2); model.Annotations.Add(rect4); var myController = new PlotController(); myController.UnbindMouseDown(OxyMouseButton.Right); myController.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt); plot1.Controller = myController; //plot1.Model = Example.RectangleAnnotation(); plot1.Model = model; plot1.Model.MouseDown += Model_MouseDown; } private void Model_MouseDown(object sender, OxyMouseDownEventArgs e) { double x = e.Position.X; double y = e.Position.Y; DataPoint p=OxyPlot.Axes.Axis.InverseTransform(e.Position, plot1.Model.DefaultXAxis, plot1.Model.DefaultYAxis); this.Text=($"X is {x} and Y is {y} and Inverse is {p.ToString()}"); } } }