SDD(Sleep-Driven Development)

睡眠の重要性!!睡眠の重要性!!

OxyPlotでグラフを表示する(WPF)

WPFでグラフを表示するライブラリを探してたとき、Oxyplotを使っている人が多かった(気がした)ので使ってみたメモ。

Webに転がってるサンプルはC#で書かれたものが多いけどせっかく高性能なXAMLが使えるのに使わないのはもったいない!ということでグラフの見た目はなるべくXAMLで書いていきます

開発環境はWIndows10+VisualStudio2015 Community+.NetFramework4.6です。

OxyPlotとは

OXYPlotは様々なグラフの作成を容易にするMIT Licenseのライブラリです。

さまざまなプラットフォームに対応しており

に対応しているらしいです。

ただ、現時点(2016年2月)では プレリリース になっています。

サンプルプロジェクト作成

実際にプロジェクトを作成します。

f:id:crocus7724:20160222192516p:plain

今回はWPFアプリケーションで作成し、プロジェクト名は「OxyPlotSample」にしました。

Nugetでインストール

NugetからOxyPlotをインストールします。

このとき、「プレリリースを含める」にチェックが入ってないと表示されません。

f:id:crocus7724:20160222192845p:plain

上のほうになにやらいろいろありますが今回は使わないのでスルーして「OxyPlot.Wpf」をインストールします。

ちなみに私がインストールしたときのバージョンは1.0.0-unstable1983でした。

unstableの文字が怖いのですが安心してください。Nugetにあるやつ全てunstableです。

グラフに表示するデータ作成

無事OxyPlotがインストールできたのでグラフを作成していきたいのですが、その前にグラフ用のデータを作成します。

クラスを追加し、名前を「MainWindowViewModel」にします。一応WPFなのでViewModelと名前がついてますが今回はサンプルなので名前だけです。

中身は以下のようにしました。

using System.Collections.Generic;
using OxyPlot;

namespace OxyPlotSample
{
    public class MainWindowViewModel
    {
        public MainWindowViewModel()
        {
            DataList = new List<DataPoint>
            {
                {new DataPoint(0, 0)},
                {new DataPoint(2, 4)},
                {new DataPoint(5, 8)},
                {new DataPoint(8, 3)},
                {new DataPoint(12, 5)},
            };
        }

        public List<DataPoint> DataList { get; }
    }
}

DataPointのコレクションをグラフのItemSourceにバインドしてあげることでグラフが描かれます。

グラフ作成

データもできたので実際にグラフを作成していきます。 今回はもともとあるMainWindow.xamlに直接書いていきます。

<Window x:Class="OxyPlotSample.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:OxyPlotSample"
        xmlns:oxy="http://oxyplot.org/wpf"
        mc:Ignorable="d"
        Title="MainWindow" >
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <oxy:Plot>
            <oxy:Plot.Series >
                <oxy:LineSeries ItemsSource="{Binding DataList}" />
            </oxy:Plot.Series>
        </oxy:Plot>
    </Grid>
</Window>

基本的にOxyPlotでグラフを描画するときはPlotで作っていきます。
そのなかのSeriesプロパティがグラフの要素(今回は線)を描画する部分です。

ここまで書いてからビルドすると・・・

f:id:crocus7724:20160222203145p:plain

XAMLのデザイナーでもItemSourceの値通りに描画してくれました!これはありがたい。 実際にデバッグで実行してみても

f:id:crocus7724:20160222203450p:plain

ちゃんとグラフが描画されてますね!

しかしこのままではなんか殺風景というかせっかく高機能なWPFを使っているのにこれでは面白くありません。 というわけでこれをもとに改造していきます。

背景変更

まず背景の白がなんか安っぽさを出していますよね。黒のほうがかっこいいですよね! というわけで黒にしましょう!

背景を黒にするのは簡単です。PlotのBackgroundプロパティに変更したい色を指定するだけです。 今回は真っ黒なのもなんかあれなので#FF1A1A1Aくらいにしました。

これで実行すると・・・

f:id:crocus7724:20160222210221p:plain

軸がとても見えにくくなりました(当たり前)

軸変更

なので次は軸を変更していきます。

軸はPlotのAxesに軸クラスを追加していきます。

<oxy:Plot.Axes>
                <oxy:LinearAxis Position="Left" AxislineColor="Gray" 
                                MajorGridlineStyle="Solid" MajorGridlineColor="Gray"
                                MinorGridlineStyle="Dot" MinorGridlineColor="Gray" 
                                TicklineColor="Gray" TextColor="Gray" />
</oxy:Plot.Axes>

まずPlot.AxesにLinearAxisを追加します。これは普通の線状の軸です。

まずPositionでどこの軸なのかを明確にします。次にAxislineColorで軸の色を追加します。
MajorGridlineとMinorGridlineは補助線ですね(正式名称知らない)
それぞれのGridlineStyleは線の種類を指定します。Solidは線でDotは点でまんまです。GridlineColorで色を指定します。
TicklineColorは軸の目盛りの色を指定します。TextColorは目盛りの数字の色です。

今回は背景が黒なので軸は灰色で統一しました。

実行結果は・・・

f:id:crocus7724:20160222212256p:plain

うまくいっているふうに見えますが左軸の色が反映されていません。

ここは結構ハマりました。もっといい解決法があるかもしれませんが、PlotプロパティのPlotAreaBorderColorをTransparentに、 AxislineStyleをSolidに変更したら・・・ f:id:crocus7724:20160222213245p:plain ちゃんと色がついてくれました!! どうやらAxislineStyleは最初はNone?だったらしく描画そのものがされていない様子。そしてPlotAreaBorderColorが軸の上に描画されているらしくそっちが優先されているみたいでした。まあ普通は消す必要ないと思いますが今回は軸がちゃんと反映されているか確かめるために消えてもらいました。

グラフの変更

軸を変更できたので次はグラフの線を色々変更していきます。 変更後はこうなりました。

<oxy:Plot.Series>
                <oxy:LineSeries ItemsSource="{Binding DataList}"
                                LineStyle="Dash" MarkerSize="5" MarkerType="Circle" 
                                MarkerStroke="DarkGreen" MarkerStrokeThickness="2"
                                MarkerFill="GreenYellow" />
</oxy:Plot.Series>

あんまり変わっていませんがLineStyleで線の種類を設定します。
Marker関連はItemSourceのコレクションの各要素の値の部分にMarkerTypeで指定した印が入るようになります。 簡単に説明すると、Strokeで印の外枠の色を、StrokeThicknessで外枠の幅を、Fillで印の中の色を指定します。

これの実行結果はこうなります。

f:id:crocus7724:20160222215254p:plain

凡例作成

グラフの見た目が決まってきたので凡例を作成します。

<oxy:Plot Background="#FF1A1A1A" PlotAreaBorderColor="Transparent" 
                  LegendBackground="#FF333333" LegendSymbolLength="30"
                  LegendTextColor="#FFCCCCCC" 
                  LegendTitle="グラフの種類" LegendTitleColor="#FFAAAAAA">

凡例はPlotのLegend〜プロパティを指定していきます。 たぶんもう解説しなくてもなんとなく察せると思います。。。

実行結果はこちら

f:id:crocus7724:20160222220333p:plain

右上端っこにひっそりと凡例が追加されました。


以上が基本的なOxyPlotの使い方というか見た目の設定の仕方になります。
OxyPlotには他にも様々な機能があり、高性能なのですがなかなか解説を探すのに骨が折れます。
また、まだプレリリースなだけあり、結構仕様変更が入ってるぽい?です。(ネットで見つけたコードのプロパティが存在しなかったり)
しかし、比較的楽に、また自由にグラフが描けるのでグラフを描画する必要が出てきたときは使ってみてはいかがでしょうか?

そして、最終的にグラフはこうなりました。

f:id:crocus7724:20160222230039p:plain

MainWindowViewModel.cs

using System.Collections.Generic;
using OxyPlot;

namespace OxyPlotSample
{
    public class MainWindowViewModel
    {
        public MainWindowViewModel()
        {
            DataList = new List<DataPoint>
            {
                {new DataPoint(0, 0)},
                {new DataPoint(2, 4)},
                {new DataPoint(5, 8)},
                {new DataPoint(8, 3)},
                {new DataPoint(12, 5)},
            };

            DataList2=new List<DataPoint>
            {
                {new DataPoint(0,8) },
                {new DataPoint(2,4) },
                {new DataPoint(5,6) },
                {new DataPoint(7,12) },
                {new DataPoint(13,17) },
            };
        }

        public List<DataPoint> DataList { get; }

        public List<DataPoint> DataList2 { get;} 
    }
}

MainWindow.xaml

<Window x:Class="OxyPlotSample.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:OxyPlotSample"
        xmlns:oxy="http://oxyplot.org/wpf"
        mc:Ignorable="d"
        Title="MainWindow">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <oxy:Plot Background="#FF1A1A1A" Padding="20"
                  PlotAreaBorderColor="Transparent"
                  LegendBackground="#66333333" LegendSymbolLength="30"
                  LegendTextColor="#CCCCCCCC"
                  LegendTitle="グラフの種類" LegendTitleColor="#CCAAAAAA"
                  Title="サンプルグラフ" TitleColor="Gray" TitlePadding="20"
                  Subtitle="OxyPlotのサンプルグラフです" TextColor="Gray">
            <oxy:Plot.Series>

                <oxy:AreaSeries ItemsSource="{Binding DataList2}" LineStyle="Solid" Color="Aqua"
                                MarkerType="Square" MarkerFill="Blue" MarkerStroke="DarkBlue"
                                Title="サンプルエリアグラフ" />

                <oxy:LinearBarSeries ItemsSource="{Binding DataList}"
                                     StrokeColor="OrangeRed" BarWidth="30" FillColor="DarkOrange" Title="サンプル棒グラフ" />

                <oxy:LineSeries ItemsSource="{Binding DataList}" BrokenLineStyle="LongDash"
                                LineStyle="Dash" MarkerSize="5" MarkerType="Circle"
                                MarkerStroke="DarkGreen" MarkerStrokeThickness="2"
                                MarkerFill="GreenYellow"
                                Title="サンプル線グラフ" />

            </oxy:Plot.Series>

            <oxy:Plot.Axes>
                <oxy:LinearAxis Position="Left" AxislineColor="Gray"
                                AxislineStyle="Solid"
                                MajorGridlineStyle="Solid" MajorGridlineColor="Gray"
                                MinorGridlineStyle="Dot" MinorGridlineColor="Gray"
                                TextColor="Gray" TickStyle="None"
                                StartPosition="-0.01" Maximum="20"
                                IntervalLength="150"
                                Title="X軸" TitleColor="Gray" />

                <oxy:LinearAxis Position="Bottom" AxislineColor="Gray" AxislineStyle="Solid"
                                MajorGridlineStyle="Solid" MajorGridlineColor="Gray"
                                MinorGridlineStyle="Dot" MinorGridlineColor="Gray"
                                TextColor="Gray" TickStyle="None" Maximum="15"
                                IntervalLength="200" StartPosition="-0.01"
                                Title="Y軸" TitleColor="Gray" />

            </oxy:Plot.Axes>
        </oxy:Plot>
    </Grid>
</Window>

AreaSeriesってどういうとき使うの?

以上です。