LoginSignup
4
5

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-11-27
動作環境
Windows 8.1 Pro (64bit)
Microsoft Visual Studio 2017 Community
OxyPlot.Wpf v1.0.0
Sublime Text 2

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

関連

参考

WPF OxyPlotで円グラフを作る 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

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

zooming and panning

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

操作についてはこちら

パフォーマンスも良い。

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

参考: OxyPlotのコントロール(PlotView)をリアルタイムにアップデートする方法

上記にて表示の更新方法を知りました。
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なみのことはできそうだ。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5