Visual Studio | WPF > OxyPlot > 折れ線グラフ描画のパフォーマンス > 1万点: 瞬時に描画 | zooming and panning: デフォルトで有効 | 1秒ごとにデータ追加の実装例

```txt:動作環境
Windows 8.1 Pro (64bit)
Microsoft Visual Studio 2017 Community
OxyPlot.Wpf v1.0.0
Sublime Text 2
```

@yumetodo さんに推薦いただいたOxyPlotを試してみた。

### 関連

- [Visual Studio | WPF > グラフ > LiveCharts > 折れ線グラフ描画のパフォーマンス > チューニング後 > 1000点のグラフなら | 適用例](https://qiita.com/7of9/items/a032c9b25789c5f90482)
- [c++ builder > TeeChart > 1つのグラフ:データ数20万件で固まる / 複数のグラフ: トータルデータ数20万件で固まる](https://qiita.com/7of9/items/348c23e4ade4afe872f8)

### 参考

[WPF OxyPlotで円グラフを作る](https://qiita.com/kuro4/items/98d498c3abb052511b5a) by @kuro4 さん

情報感謝です。

ただし、MVVMなど入れると複雑になるため、簡易的な実装とする。

### 準備

- NugetでOxyPlot.Wpf v1.0.0をインストール
- XAMLに以下を追加
    - `xmlns:oxy="http://oxyplot.org/wpf"`
- code behindに以下を追加
    - `using OxyPlot;`
    - `using OxyPlot.Series;`

### code

```MainWindow.xaml
<Window x:Class="_171127_t1530_tooManyPoints.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_171127_t1530_tooManyPoints"
        xmlns:oxy="http://oxyplot.org/wpf"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <oxy:PlotView Model="{Binding _PlotModel, Mode=OneWay}"/>
    </Grid>
</Window>
```

```MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
// 以下を追加した
using OxyPlot;
using OxyPlot.Series;

namespace _171127_t1530_tooManyPoints
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public PlotModel _PlotModel { get; private set; } = new PlotModel() { Title = "LineSeries" };

        public MainWindow()
        {
            InitializeComponent();
            graph_init();
        }

        private void graph_init()
        {
            var series = new LineSeries
            {
                StrokeThickness = 0.5,
            };

            graph_add_series_addEach(series);
            _PlotModel.Series.Add(series);

            this.DataContext = this;
        }

        static readonly int kNumPoint = 10000;

        private void graph_add_series_addEach(LineSeries series)
        {
            var gen = new Random();
            for (int idx=0; idx < kNumPoint; idx++)
            {
                var yval = gen.NextDouble() * 10.0;
                series.Points.Add(new DataPoint(idx, yval));
            }            
        }
    }
}
```

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/7b00d2c1-8661-ad7a-03fd-9d17f684a3c9.png)

- 1万点: 瞬時に描画
- 10万点: 3秒程度の後に描画

### zooming and panning

デフォルトで有効になっていた。

[操作についてはこちら](https://qiita.com/7of9/items/4b2aee6f161bec39a757#%E3%83%9E%E3%82%A6%E3%82%B9%E6%93%8D%E4%BD%9C%E3%81%A7%E5%8F%AF%E8%83%BD%E3%81%A0%E3%81%A3%E3%81%9F)

パフォーマンスも良い。

### 1秒ごとにデータ追加の実装例

参考: [OxyPlotのコントロール(PlotView)をリアルタイムにアップデートする方法](https://qiita.com/maruh/items/035a39a2a01102ce248f)

上記にて表示の更新方法を知りました。
InvalidatePlot()を使用する方法を使ってみます。

情報感謝です。

```MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
// 以下を追加した
using OxyPlot;
using OxyPlot.Series;
using System.Windows.Threading;

namespace _171127_t1530_tooManyPoints
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private DispatcherTimer myTimer;
        private LineSeries mySeries;
        private Random randGen;
        private int pos = 0;
        public PlotModel _PlotModel { get; private set; } = new PlotModel() { Title = "LineSeries" };

        public MainWindow()
        {
            InitializeComponent();

            // 1. 1秒タイマーの設定
            myTimer = new DispatcherTimer(DispatcherPriority.Normal);
            myTimer.Interval = new TimeSpan(0, 0, 1);
            myTimer.Tick += myTimer_Tick;

            randGen = new Random();

            graph_init();

            myTimer.Start();
        }

        private void graph_init()
        {
            mySeries = new LineSeries
            {
                StrokeThickness = 0.5,
            };

            graph_add_series_addEach();
            _PlotModel.Series.Add(mySeries);
            this.DataContext = this;
        }

        static readonly int kNumAddPoint = 5000;
        static readonly int kMaxPoint = 200000;

        private void graph_add_series_addEach()
        {
            for (int idx=0; idx < kNumAddPoint; idx++)
            {
                var yval = randGen.NextDouble() * 10.0;
                mySeries.Points.Add(new DataPoint(pos, yval));
                pos++;
            }
        }

        void myTimer_Tick(object sender, EventArgs e)
        {
            if (pos > kMaxPoint)
            {
                return;
            }

            graph_add_series_addEach();
            _PlotModel.InvalidatePlot(true);
        }
    }
}
```

- 1秒ごとにデータを追加する
- 20万点でデータ追加を停止する

20万点ではpanningが重いが、描画はできている。

TeeChartなみのことはできそうだ。