Xamarin.Forms で OxyPlot を使ってみた

Xmarin.Forms でグラフ描画ライブラリ “OxyPlot” を使ってみました.

OxyPlot の紹介はこちら.

開発環境

  • Microsoft Visual Studio Community 2015
  • Xamarin 4.0.0.1717 (1390b70)
  • Xamarin.Android 6.0.0.35 (d300845)

OxyPlotの導入方法

Nugetで導入できます.

プレリリースのパッケージなので,”プレリリースを含める”のチェックが必要です.

グラフ描画の前段階

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OxyPlotSample
{
    class PopulationModel
    {
        public int Year { get; set; }
        public int YouthPopulation { get; set; }
        public int WorkingAgePopulation { get; set; }
        public int AgedPopulation { get; set; }

        public static List GetPopulationList()
        {
            var list = new List() {
                new PopulationModel()
                {
                    Year = 21,
                    YouthPopulation = 17011,
                    WorkingAgePopulation = 81493,
                    AgedPopulation = 42715
                },
                new PopulationModel()
                {
                    Year = 22,
                    YouthPopulation = 16839,
                    WorkingAgePopulation = 81735,
                    AgedPopulation = 43678
                },
                new PopulationModel()
                {
                    Year = 23,
                    YouthPopulation = 16705,
                    WorkingAgePopulation = 81342,
                    AgedPopulation = 44460
                },
                new PopulationModel()
                {
                    Year = 24,
                    YouthPopulation = 16547,
                    WorkingAgePopulation = 80175,
                    AgedPopulation = 45986
                },
                new PopulationModel()
                {
                    Year = 25,
                    YouthPopulation = 16390,
                    WorkingAgePopulation = 79010,
                    AgedPopulation = 47501
                }
            };

            return list;
        }
    }
}

今回のサンプルデータとなる日本の年齢別人口の Model クラスです.

using System;

using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;

namespace OxyPlotSample.Droid
{
    [Activity(Label = "OxyPlotSample", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            global::Xamarin.Forms.Forms.Init(this, bundle);

            // Xamarin.Forms.Forms.Init()の後にOxyPlot.Xamarin.Forms.Platform.Android.Forms.Init()を呼ぶ
            OxyPlot.Xamarin.Forms.Platform.Android.Forms.Init();

            LoadApplication(new App());
        }
    }
}

各プラットフォームから OxyPlot の初期化メソッドを呼び出す必要があります.

各プラットフォームごとの初期化メソッドは以下のようになります.

  • OxyPlot.Xamarin.Forms.Platform.Android.Forms.Init();
  • OxyPlot.Xamarin.Forms.Platform.iOS.Forms.Init();
  • OxyPlot.Xamarin.Forms.Platform.WinPhone.Forms.Init();

ソースコードに直書きするパターン


各プラットフォーム共通の View になる MainPage.xaml です.

xmlns:oxy="clr-namespace:OxyPlot.Xamarin.Forms;assembly=OxyPlot.Xamarin.Forms"

上記を宣言し,名前空間に割り当てを行います.

using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace OxyPlotSample
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            var model = new PlotModel();
            model.Background = OxyColors.White;
            var list = PopulationModel.GetPopulationList();

            var axisX = new CategoryAxis();
            axisX.Title = "年度";
            axisX.ItemsSource = list;
            axisX.LabelField = "Year";
            axisX.Position = AxisPosition.Bottom;
            model.Axes.Add(axisX);

            var axisY = new LinearAxis();
            axisY.Title = "人口[千人]";
            axisY.Position = AxisPosition.Left;
            model.Axes.Add(axisY);

            var seriesYouth = new ColumnSeries();
            seriesYouth.ItemsSource = list;
            seriesYouth.ValueField = "YouthPopulation";
            seriesYouth.IsStacked = true;
            model.Series.Add(seriesYouth);

            var seriesWorkingAge = new ColumnSeries();
            seriesWorkingAge.ItemsSource = list;
            seriesWorkingAge.ValueField = "WorkingAgePopulation";
            seriesWorkingAge.IsStacked = true;
            model.Series.Add(seriesWorkingAge);

            var seriesAged = new ColumnSeries();
            seriesAged.ItemsSource = list;
            seriesAged.ValueField = "AgedPopulation";
            seriesAged.IsStacked = true;
            model.Series.Add(seriesAged);

            this.PlotView.Model = model;
        }
    }
}

MainPage.csです.

ソースコード側にて要素を直書きしています.

こちらが実行結果になります.

MVVMで書くパターン

残念ながらできませんでしたorz

OxyPlot.Xamarin.Forms には PlotView しか定義がないので,OxyPlot.~ で参照できるかなと思ったのですが,それも参照が取れませんでした.

StackOverFlow あたりを見ても PlotModel とバインドする方法しか載っていなかったので,現状無理なのかもしれません…

一応,実現したかったコードを載せておきます.

using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace OxyPlotSample
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OxyPlotSample
{
    class MainPageViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        List populationList;

        public List PopulationList
        {
            protected set
            {
                if (populationList != value)
                {
                    populationList = value;
                    OnPropertyChanged("List");
                }
            }
            get { return populationList; }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this,
                    new PropertyChangedEventArgs(propertyName));
        }

        public MainPageViewModel()
        {
            this.PopulationList = PopulationModel.GetPopulationList();
        }
    }
}

.xaml で書けると .cs のコードビハインドがものすごくすっきりするのでぜひこの方法を使いたいのですが…

何か方法を知っている方がいらっしゃればぜひ教えてください!

まとめ

Xamarin.Forms でグラフ描画ライブラリ “OxyPlot” を使ってみました.

コードビハインドでは問題なく記述できます.

MVVM なパターンでは現状実現できません(確証はありません).
(PlotModel とバインドすることはできますが,これはあまり旨みがないと思います).

以上です.