SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

現役エンジニア直伝! 「現場」で使えるコンポーネント活用術(ComponentOne Studio)

手の位置をチャートで可視化しよう

  • このエントリーをはてなブックマークに追加

 IoT(Internet of Things)というキーワードは今後のICTを考える上での重要なキーワードです。そして、センサーからクラウドにアップロードされた様々なデータの活用方法の一つとして、利用者に分かりやすい形で表示して状態の把握を容易にすることで次のアクションの判断基準とするような利用形態があります。そのようなアウトプットで有効な「見える化」手法の一つはセンサーの値を時系列でグラフにすることでしょう。そこで今回はセンサーの値を「ComponentOne Studio for WinRT XAML」のChartコントロールでグラフ化してWindows 8タブレットで表示する方法を紹介したいと思います。

  • このエントリーをはてなブックマークに追加

使用センサー

 今回利用するセンサーは手のひらや指の位置を検出できる「Leap Motion」を使用します。Leap MotionはWindowsストアアプリからも利用可能で、簡単に対応アプリが作れるテンプレートも提供されています。

 Leap Motionからの手のひらのデータはX,Y,Zの三次元データとして取得できます。

 Leapの上で手を左右にふればX値が変わり、上下に動かせばY値、前後に動かせばZ値が変わります。単位はLeapの中心位置からの距離でmm(ミリメートル)単位で取得できます。

図1 Leapの座標系
図1 Leapの座標系

Chartを追加する

 Windowsストアアプリのプロジェクトを新規作成し、MainPage.xamlを表示してツールボックスから「C1Chart」をxaml上にドラッグ&ドロップします。Page属性としてあらたに「xmlns:Xaml="using: C1.Xaml.Chart"」が追加され、ページ定義中にも「<Xaml:C1Chart />」が追加されます。

図2 初期表示
図2 初期表示
リスト1 初期設定値
<Chart:C1Chart ChartType="Column" HorizontalAlignment="Left" Height="150" Margin="946,431,0,0" Palette="Office" VerticalAlignment="Top" Width="200">
    <Chart:C1Chart.Data>
        <Chart:ChartData>
            <Chart:ChartData.Children>
                <Chart:DataSeries Label="s1" Opacity="1" Values="20 22 19 24 25"/>
                <Chart:DataSeries Label="s2" Opacity="1" Values="8 12 10 12 15"/>
            </Chart:ChartData.Children>
        </Chart:ChartData>
    </Chart:C1Chart.Data>
    <Chart:C1ChartLegend Position="Right" VerticalContentAlignment="Center"/>
</Chart:C1Chart>

 初期設定値は2種類の値が表示されている棒グラフになります。この定義のポイントは次のようなところです。

XAML定義のポイント

(1)ChartTypeプロパティ

 C1Chart定義の一番ベースとなる部分にChartTypeプロパティとして「Column」が指定されています。これはこのグラフが棒グラフであることを示しています。位置情報を可視化するときは棒グラフではなく折れ線グラフの方が適切なので、このプロパティ値を変更すれば目的の折れ線グラフに変更できます。

(2) DataSeries

 2種類のデータは2つのDataSeriesとして定義しています。今回はX,Y,Zの3種類の値を表示したいのでDataSeriesを3つ用意することになります。

初期表示からの変更ポイント

 ツールボックスから設定した直後の状態から目的のデザインに変更するためには次のような作業項目が必要になります。

  1. グラフサイズを全画面サイズに変更
  2. グラフの色合いを変更
  3. 折れ線グラフに変更
  4. 3種類の値を表示するように変更

チャートを加工する

 設置直後の定義から次のようなデザインに変更します。

図3 画面デザイン
図3 画面デザイン

全画面サイズに変更

 初期設定では縦横の大きさや画面上での位置が明示的に指定されているため、画面全体を使ってグラフを表示できていません。そこで明示的なサイズ指定を削除して全画面表示に切り替えます。ただしこのままではタイトルにかかってしまうので、Grid.Rowも明示的に指定します。

リスト2 全画面サイズに変更
<Chart:C1Chart ChartType="Column" Grid.Row="1" Palette="Office">

 これで目指すデザインと同じサイズで棒グラフが表示できます。

色合いを変更

 初期状態の色合いも黒ベースで見やすいのですが色合いをExcelライクに近づけてみます。そのためにはThemeプロパティとPaletteプロパティを利用します。

リスト3 色合いを変更
<Chart:C1Chart ChartType="Column" Grid.Row="1" Theme="Office2007Blue" Palette="Metro">

 これで白系バックのグラフに変更できました。この他にもさまざまな組込済テーマがありますので、好みに合ったテーマをさがしてみるとよいでしょう。

折れ線グラフに変更

 それではグラフを折れ線グラフに変更してみましょう。

 折れ線グラフへの変更はChartTypeをLineにすることで実現できます。

リスト4 折れ線グラフに変更
<Chart:C1Chart ChartType="Line" Grid.Row="1" Theme="Office2007Blue" Palette="Metro">

 これで2種類の値が同時に表示されている折れ線グラフを表示させるところまでたどり着きました。

3種類の値を表示するように変更

 2種類の折れ線を3種類の折れ線に変更するためには、DataSeriesを3つに増やします。

 これまでの変更点も含め、C1ChartのXAML定義全体を再確認してみましょう。

リスト5 3種類の値を表示するように変更
<Chart:C1Chart ChartType="Line" Grid.Row="1" Theme="Office2007Blue" Palette="Metro">
    <Chart:C1Chart.Data>
        <Chart:ChartData>
            <Chart:ChartData.Children>
                <Chart:DataSeries Label="X" Opacity="1" Values="20 22 19 24 25"/>
                <Chart:DataSeries Label="Y" Opacity="1" Values="8 12 10 12 15"/>
                <Chart:DataSeries Label="Z" Opacity="1" Values="10 12 15 8 12 "/>
            </Chart:ChartData.Children>
        </Chart:ChartData>
    </Chart:C1Chart.Data>
    <Chart:C1ChartLegend Position="Right" VerticalContentAlignment="Center"/>
</Chart:C1Chart>

 さて、ここまで画面デザインができたところで大きな疑問がわいてくると思います。ここが今回のサンプルの最大の難関で、ヘルプをざっと眺めてみてみただけでは解決する方法がみつからなかったポイントになります。

 それは「どうやって計測値をC1Chartに渡すのか」ということです。現時点ではXAMLに表示する値を直接記載していますので、これではリアルタイムに変化させることができません。

サンプルデータを表示

 ここでいきなりLeap Motionから値をとってきて、データ設定方法を確認しながらデータ連携方法を確認していくのでは非効率的なので、サンプルデータを生成するクラスを用意しましょう。

 XAMLなのできちんとしたコントロールであればBindingによりデータ表示できるはずだと予想して、次のようなサンプルデータクラスを定義します。

表示データ形式の定義

 3種類のデータを表示するのでグラフとある時点(X軸のある時点)での値はX,Y,Zの3つの値を持ちます。そこで表示用データクラスとして次のような定義を行います。

リスト6 データクラス
Public Class TValue
    Public Property ValueX As Integer
    Public Property ValueY As Integer
    Public Property ValueZ As Integer
End Class

データ連携用ViewModelクラスの用意

 このデータについて折れ線グラフのX軸方向に配列のようにデータが時系列で並べればよいので、ObservableCollectionを使って「ObservableCollection(Of Models.TValue)」を公開するViewModelクラスを用意します。

リスト7 ViewModelクラス
Public Class MainViewModel
    Implements INotifyPropertyChanged

    Public Property HandData As ObservableCollection(Of Models.TValue)

    Public Event PropertyChanged(sender As Object,
                                 e As PropertyChangedEventArgs) _
                             Implements INotifyPropertyChanged.PropertyChanged
    Protected Sub OnPropertyChanged(<CallerMemberName> Optional propertyName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub
End Class

 もちろんBindingできるようにINotifyProperyChangedインターフェースを実装します。

サンプルデータクラスの用意

 データ連携用ViewModelクラスを継承してサンプルデータクラスを作り、サンプルデータを設定します。

リスト8 サンプルデータ投入クラス
Public Class MainSample
    Inherits ViewModels.MainViewModel

    Public Sub New()
        Me.HandData.Add(New Models.TValue With {.ValueX = 80, .ValueY = 400, .ValueZ = 20})
        Me.HandData.Add(New Models.TValue With {.ValueX = 400, .ValueY = 20, .ValueZ = 60})
        Me.HandData.Add(New Models.TValue With {.ValueX = 20, .ValueY = 60, .ValueZ = 150})
        Me.HandData.Add(New Models.TValue With {.ValueX = 60, .ValueY = 150, .ValueZ = 300})
        Me.HandData.Add(New Models.TValue With {.ValueX = 150, .ValueY = 300, .ValueZ = 130})
        Me.HandData.Add(New Models.TValue With {.ValueX = 300, .ValueY = 130, .ValueZ = 500})
        Me.HandData.Add(New Models.TValue With {.ValueX = 130, .ValueY = 500, .ValueZ = 80})
        Me.HandData.Add(New Models.TValue With {.ValueX = 500, .ValueY = 80, .ValueZ = 400})
    End Sub
End Class

サンプルデータ表示

 サンプルデータクラスが用意できたのでMainPage.xamlでサンプルデータクラスを参照してグラフの3つのDataSeriesにデータをBindingしてみましょう。

リスト9 MainPage.xaml
<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CZ1404IoT"
    xmlns:common="using:CZ1404IoT.Common"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:Chart="using:C1.Xaml.Chart"
    xmlns:data="using:CZ1404IoT.Data"
    x:Name="pageRoot"
    x:Class="CZ1404IoT.Views.MainPage"
    d:DataContext="{d:DesignInstance IsDesignTimeCreatable=True,Type=data:MainSample}"
    mc:Ignorable="d">

        :
     (中略)
        :

        <Chart:C1Chart x:Name="Chart" ChartType="Line" Grid.Row="1" Theme="Office2007Blue" Palette="Metro">
            <Chart:C1Chart.Data>
                <Chart:ChartData ItemsSource="{Binding HandData}">
                    <Chart:ChartData.Children>
                        <Chart:DataSeries Label="X" ValueBinding="{Binding ValueX}"/>
                        <Chart:DataSeries Label="Y" ValueBinding="{Binding ValueY}"/>
                        <Chart:DataSeries Label="Z" ValueBinding="{Binding ValueZ}"/>
                    </Chart:ChartData.Children>
                </Chart:ChartData>
            </Chart:C1Chart.Data>
            <Chart:C1ChartLegend Position="Right" VerticalContentAlignment="Center"/>
        </Chart:C1Chart>
    </Grid>
</Page>
(1)デザイン時インスタンスの指定

 「d:DataContext="{d:DesignInstance IsDesignTimeCreatable=True,Type=data:MainSample}"」とPageタグに定義することで、XAMLデザイナで開いたときにMainSampleクラスが生成されてDataContextに割り当たります。これはあくまでもデザイナで開いた時だけで実行時には無視されます。

(2)グラフ化プロパティの指定

 「<Chart:ChartData ItemsSource="{Binding HandData}">」で、グラフにはHandDataコレクションに設定されている値を使うことを定義します。

(3)個々の要素の指定

 「<Chart:DataSeries Label="X" ValueBinding="{Binding ValueX}"/>」で、グラフの1要素にはHandDataコレクションのValueXプロパティの値を割り当てることを定義します。

 これでXAMLエディタでサンプルデータがグラフ表示できます。

図4 画面デザイン
図4 画面デザイン

Leapデータの取得

LeapModelの定義

 テンプレートから新規にプロジェクトを作成し、その中にあるLeapModelクラスを参考にして次のようなLealModelクラスを作成します。

リスト10 MainPage.xaml
Imports System.Runtime.Serialization
Imports Newtonsoft.Json
Imports Windows.Networking.Sockets
Imports Windows.Storage.Streams
Imports Windows.Web

Namespace Models
    Public Class TValue
        Public Property ValueX As Integer
        Public Property ValueY As Integer
        Public Property ValueZ As Integer
    End Class

    Public Class LeapModel
        Implements INotifyPropertyChanged

        Public Property HandData As New ObservableCollection(Of TValue)

        Private WithEvents Timer As New DispatcherTimer
        Private WithEvents LeapListener As SampleListener

        Public Sub New()
            If Not DesignMode.DesignModeEnabled Then
                For index As Integer = 0 To 99
                    Me.HandData.Add(New TValue)
                Next
                Me.LeapListener = New SampleListener
                Me.Timer.Interval = New TimeSpan(0, 0, 0, 0, 0.1)
                Me.Timer.Start()
            End If
        End Sub

        Private Sub Timer_Tick(sender As Object, e As Object) Handles Timer.Tick
            Me.Timer.Stop()
            Dim data = LeapListener.Pos
            If data.Hand IsNot Nothing Then
                Me.HandData.Add(New TValue With {.ValueX = data.Hand(0).X,
                                                 .ValueY = data.Hand(0).Y,
                                                 .ValueZ = data.Hand(0).Z})
                If Me.HandData.Count >= 100 Then
                    Me.HandData.RemoveAt(0)
                End If
            Else
                Me.HandData.Add(New TValue)
            End If
            Me.Timer.Start()
        End Sub

        Public Event PropertyChanged(sender As Object,
                                     e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
        Protected Sub OnPropertyChanged(<CallerMemberName> Optional propertyName As String = Nothing)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End Sub
    End Class

    Friend Class SampleListener

            :
         (中略)
            :

        Private Function NormalizeVector3(tip As String()) As SharpDX.Vector3
            Return New SharpDX.Vector3(CType(tip(0), Single), 
                                        CType(tip(1), Single), 
                                        CType(tip(2), Single))
        End Function

    End Class
End Namespace

 これでLeapからあがってきた手のひらの三次元位置が随時HandDataコレクションに設定され、100個を超えたら古いものが削除されてX軸が常に最大100データでデータが随時更新されるようになります。

MainViewModelの対応

 次にMainViewModelでLeapModelを使うように設定します。

リスト11 MainViewModelクラス(抜粋)
Private Model As New Models.LeapModel

Public Sub New()
    AddHandler Model.PropertyChanged, AddressOf Model_PropertyChanged
End Sub

Public Property HandData As ObservableCollection(Of Models.TValue)
    Get
        Return Me.Model.HandData
    End Get
    Set(value As ObservableCollection(Of Models.TValue))
        Me.Model.HandData = value
    End Set
End Property

 これでHandDataコレクションのデータ供給元がLeapModelです。

MainPage.xaml.vbの対応

 最後にXAMLにMainViewModelをつなぎこむ部分を記載しましょう。MainViewModelはapp.xaml.vbでMainVMというプロパティで公開していますので次ようなコードをMainPage.xaml.vbに追記します。

リスト12 MainPage.xaml.vb抜粋
Private Sub NavigationHelper_LoadState(sender As Object, 
                                       e As Common.LoadStateEventArgs)
    Me.DataContext = App.MainVM
End Sub

実行

図5 実行画面
図5 実行画面
図6 実行動画

 http://youtu.be/5Kbvm-_X0Zo

 手の動きに反応して機敏にグラフが変化するのが分かると思います。このようにグラフ化というのは値の動きや変化というデータに対して人に何らかの思考を促すのに適したアウトプット形式なのです。

まとめ

 複雑になりがちなグラフ表示もC1Chartを使えば非常に簡単に見た目もよいグラフ表示が可能です。また、リアルタイムにデータを表示させてみて、その表示性能の良さも特筆すべきものであるという実感を得ました。

 今回は手のひら1つでしたが、両掌の位置、各指の位置などもC1Chartで見える化すればLeap Motionで特定の動きを検出したいときの分析に役立つでしょう。そして入力を切り替えて各種環境センサーなどの値を使うことで環境の見えるかなど快適な住空間などのデザインなどの役立つ情報が得られるかもしれません。

 今年のトレンドの一つであるIoTをC1Chartで加速してみてはいかがでしょうか。

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7753 2014/11/07 15:23

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング