2018年7月26日木曜日

これからの作業分担について

 前回までに健康管理アプリの土台が出来たため、今回から各自分担して作業を進めていく。
 作業内容は

  1. 患者基本情報項目の洗い出し・デザイン
  2. 患者基本情報データの取得
  3. 患者基本情報表示画面の作成
  4. 検査結果表示の修正・作成

である。
 4人で話し合い、作業分担を決めた後、各自スケジュール表(WBS)を作成した。
 そして、完成目標が10月20日(土)のオープンキャンパス展示となったため、それまでの完成を目指す。

2018年7月19日木曜日

MONACAサンプルアプリの編集7

今回は前回の続きとして、まず、グラフで基準値が一目でわかるように色を付ける改良を行っていく。
  1. .controller('PopulationChartController', ['$scope', function($scope) {
  2. $scope.formatData = function() {
  3. if (!$scope.data) {
  4. return [];
  5. }
  6. //alert(JSON.stringify($scope.data,null,2));
  7. var total = [],
  8. males = [],
  9. females =[];
  10.  
  11. $scope.data.forEach(function(item){
  12. var strDate = item.sampleDate.replace(/ /g, ' 02:');
  13. var sampleDate = Date.parse(strDate.replace(/-/g, '/'));
  14. var value = parseFloat(item.value);
  15. var normalValue = item.normalValue.split(/-/);
  16. var lower = parseFloat(normalValue[0]);
  17. var upper = parseFloat(normalValue[1]);
  18.  
  19. total.push({x: sampleDate, y: upper});
  20. males.push({x: sampleDate, y: value});
  21. females.push({x: sampleDate, y: lower});
  22. });
  23.  
  24. return [
  25. {
  26. key: '上限',
  27. values: total
  28. },
  29. {
  30. key: '下限',
  31. values: females
  32. },
  33. {
  34. key: '検査結果',
  35. values: males
  36. }
  37. ];
  38. };

上記のグラフデータを作成しているプログラムの中の26行目にある「return」で配列を戻している箇所を以下のように、グラフで基準値が一目でわかるように、色を付けるプログラムを書き加えていく。
  1. .controller('PopulationChartController', ['$scope', function($scope) {
  2. $scope.formatData = function() {
  3. if (!$scope.data) {
  4. return [];
  5. }
  6. //alert(JSON.stringify($scope.data,null,2));
  7. var total = [],
  8. males = [],
  9. females =[];
  10.  
  11. $scope.data.forEach(function(item){
  12. var strDate = item.sampleDate.replace(/ /g, ' 02:');
  13. var sampleDate = Date.parse(strDate.replace(/-/g, '/'));
  14. var value = parseFloat(item.value);
  15. var normalValue = item.normalValue.split(/-/);
  16. var lower = parseFloat(normalValue[0]);
  17. var upper = parseFloat(normalValue[1]);
  18.  
  19. total.push({x: sampleDate, y: upper});
  20. males.push({x: sampleDate, y: value});
  21. females.push({x: sampleDate, y: lower});
  22. });
  23.  
  24. return [
  25. {
  26. key: '上限',
  27. values: total,
  28. color: '#0000CC',
  29. area:true
  30. },
  31. {
  32. key: '下限',
  33. values: females,
  34. color: '#FF0000',
  35. area:true
  36. },
  37. {
  38. key: '検査結果',
  39. values: males,
  40. color: '#00FF00',
  41. strokeWidth:4
  42. }
  43. ];
  44. };

30行目と36行目と42行目にある、「color」は書き加えることで、グラフに色をつけることができる。それぞれ、上限、下限、検査結果にあった色を指定している。
図1 グラフに色を付けて表示した結果
図1のようにグラフに色付けされて、一目でわかりやすいように表示された。

また、43行目にある「strokeWidth」を書き加えることで、検査結果のグラフの線の太さを太くすることができ、31行目と37行目にある「area:true」を書き加えることで、エリアを0まで色付けすることができる。例えば、上限に書き加えれば、上限より下から0までのエリアが色付けされ、下限にも書き加えれば、下限より下から0までのエリアを色付けすることでできる。

図2 線の太さとエリアの色付けをして表示した結果

次に、アプリケーションタブバーの追加を行う。
onsen-uiではこのようにタブバーの定義を行う事ができる。
  1. <ons-tabbar>
  2. <ons-tab label="Tab 1" icon="ion-***"active></ons-tab>
  3. <ons-tab label="Tab 2" icon="ion-***"></ons-tab>
  4. </ons-tabbar>
上記のコーディングはタブバーの定義である。
「ons-tabbar」でタブバーの定義を行い、
「ons-tab~」からタブの追加を行う。 labelはタブアイコン直下に表示する名称であり、icon="ion-***"で表示したいアイコンの定義を行う。
尚、どの様なアイコンが使用できるかは、こちらを参考にするといいだろう。
また、「ons-tab」の属性に「active」を追加することで、そのページをデフォルトで表示することができる。
onsen-uiでのタブバーの定義方法が理解できたところで、実際プログラムに実装を行う。
  1. <ons-navigator var="navi" page="tab.html"></ons-navigator>
まず、上記htmlの「ons-navigator」の直下に追加していく。また、ナビゲータがデフォルト表示する「page」をこれから定義する「tab.html」へ変更しておく
  1. <ons-template id="tab.html">
  2. <ons-page>
  3. <ons-tabbar>
  4. <ons-tab page="main.html" label="メイン" icon="ion-home"active>
  5. </ons-tab>
  6. <ons-tab page="demographics.html" label="基本情報" icon="ion-person">
  7. </ons-tab>
  8. <ons-tab page="settings.html" label="設定" icon="ion-settings">
  9. </ons-tab>
  10. </ons-tabbar>
  11. </ons-page>
  12. </ons-template>
まず、1行目の「ons-template」でこのタブバーを「tab.html」として定義し、,2行目で「ons-page」の定義を行う。
また、タグの定義を行う際に開始タグと同時に終了タグの記載もしておくと効率が良い。
次に3行目でタブバーの定義を行う。4行目ではメイン画面(検査項目一覧)の表示、6行目では基本情報(利用者情報)、8行目では設定の定義を行い、タブとして追加した。
また、初めに表示される画面はメイン画面にしたい為、4行目には「active」を記載している。
図3 タブバーの追加を行った結果

これらの修正を行った後、アプリケーションの確認を行うと、上記図3のようにタブバーの表示を行うことができた。
しかし、メイン以外の基本情報、設定タブをタップしても、画面の変更が行われなかった。
これは何故というと、先ほどコーディングした際に定義した「demographics.html」と「settings.html」のファイルが存在しないためである。
そのため、次はこの二つのファイルの作成を行う。
まずMONACA左に表示されているツリーの「www」というディレクトリを右クリックする。その後、新規ファイル作成をクリックする。
図4MONACAアプリの新規ファイル作成画面
すると上記図4のような画面が表示されるので、画面に従って各htmlの追加を行う。また、追加したhtmlは「www」ディレクトリに格納されることを覚えておきたい。
作成したhtmlを表示してみると、予めHTMLのテンプレート(骨組み)が作成されているが、今回は使用しないため、すべて削除し、下記のプログラムを入力する。
  1. <ons-page>
  2. <ons-toolbar>
  3. <div class="center">基本情報</div>
  4. </ons-toolbar>
  5. </ons-page>
上記のプログラムを記入した後、スマホで確認をすると、
図5 基本情報タブをタップした結果

上記図5の様にタブ画面の切り替えを行う事が出来た。

次回は基本情報ページの充実を行いたいが、以前の患者データではアレルギー情報等が記入されていないため、アレルギーデータの格納場所が分からない。
その為、ORCA,またはOpenDolphin上で患者にアレルギー情報の記入を行い、再びWirashark等でパケットキャプチャを行い、アレルギーデータの格納場所の特定を行う。

2018年7月18日水曜日

MONACAサンプルアプリの編集6

今回は、前回編集を行っていく中で見つけた「検査一覧画面に表示される検査値を小数点第3位で四捨五入をする」、「検査値が基準値外の場合、背景色を変更する」といった二点の課題に対して改良を行っていく。

検査値を小数点第3位で四捨五入を行う。

検査値の表示を行った際、データの桁数があまりにも長く、見づらかったため小数点第3位で四捨五入を行い、小数点以下2桁まで表示する。
  1. Countries.get()
  2. .then(
  3. function(countries) {
  4. var list = countries.list[0];
  5. that.list = [];
  6. list.items.forEach(function(element){
  7. that.list.push(
  8. {
  9. itemName:element.itemName,
  10. value:element.value,
  11. unit:element.unit
  12. }
  13. );
  14. });
  15. }
  16. );
これは、前回コーディングしたプログラムである。10行目が、検査結果を連想記憶に設定しているところであるが、これを以下のように書き換える。
  1. value:Math.round(element.value *100) /100
Math.roundは、javascriptで四捨五入を行うときに使う関数であるが,この関数は小数点以下1桁目を四捨五入して整数を返す関数である。小数点以下3桁目を四捨五入するために,まず検査値を100倍にし、それをMath.round関数を使って四捨五入する。その結果を100で割ると、小数点以下3桁目を四捨五入した結果が得られる。
例として、9.785という値があるとする。このままMath.round関数を用いると小数点を四捨五入し、10になってしまう。これでは整数でしか表示を行う事が出来ないため、まず数字を100倍し、978.5にする。その後、Math.round関数を用いて四捨五入を行うと、979となる。ここでこの値を100で割ると9.79となり、実質的に小数点第3位で四捨五入を行った形になる。
図1 検査結果を小数点以下第2位まで表示した結果
この修正を行った後,MONACAアプリを起動すると、上記図1の様に検査値を小数点第2位まで表示することができた。

検査値が基準値外の場合、背景色を変更する。

前回、検査結果が基準値外の値であれば、スタイルシートを使って背景色を変更するために「normal」や「abnormal」というクラスの定義を行った。今回は,検査結果の値に応じてons-list-itemタグにクラス属性の値を設定する機能の実装を試みる。
  1. Countries.get()
  2. .then(
  3. function(countries) {
  4. var list = countries.list[0];
  5. that.list = [];
  6. list.items.forEach(function(element){
  7. that.list.push(
  8. {
  9. itemName:element.itemName,
  10. value:Math.round(element.value *100) /100
  11. unit:element.unit
  12. }
  13. );
  14. });
  15. }
  16. );
まず先ほども修正した上記javascriptのプログラムを以下のように書き換える。
  1. Countries.get()
  2. .then(
  3. function(countries) {
  4. var list = countries.list[0];
  5. that.list = [];
  6. list.items.forEach(function(element){
  7. var normalValue = element.normalValue.split(/-/);
  8. var lower = parseFloat(normalValue[0]);
  9. var upper = parseFloat(normalValue[1]);
  10. var bgColor;
  11. if(element.value >= lower && element.value <= upper){
  12. bgColor ="normal";
  13. }else{
  14. bgColor ="abnormal";
  15. }
  16. that.list.push(
  17. {
  18. itemName:element.itemName,
  19. value:Math.round(element.value *100) /100 ,
  20. unit:element.unit,
  21. bgColor:bgColor
  22. }
  23. );
  24. });
  25. }
  26. );
まず、条件判定を行うにあたって、基準値から上限・下限の取りだしを行う必要があるのだが、これは以前のブログに書いたプログラムを流用し、7~9行目のように記入する。尚、7行目に関しては、今回検査データはelementに格納されているため、element.normalValueへ変更した。次に、10行目に背景を表すクラス属性を格納する変数を「bgColor」として定義する。そして、11行目~15行目にif文を使って条件判断を記述する。内容は「検査値(element.value)が下限値(lower)以上かつ、上限値(upper)以下であれば正常(normal),そうでなければ異常(abnormal)」といったものである。最後に、that.list.pushで追加する連想配列の21行目にbgColor:bgColorと記載することで、クラス属性を表すbgColorの設定を行った。
  1. <ons-list>
  2. <ons-list-item class="{{country.bgColor}}"
  3. ng-click="countries.showCountry(country.itemName)" modifier="chevron"
  4. ng-repeat="country in countries.list | filter:query">
  5. <ons-col width="50%">{{ country.itemName }}</ons-col>
  6. <ons-col>{{country.value}}</ons-col>
  7. <ons-col>{{country.unit}}</ons-col>
  8. </ons-list-item>
  9. </ons-list>
そしてhtmlの2行目にある「ons-list-item」タグに「class="{{country.bgColor}}" 」を記述することで、javascriptで設定したクラス属性値("normal"または"abnormal")を設定することができる。
図2検査結果一覧画面で異常値に色を付けた結果
これらの編集を行うことで、上記図2のように基準値外の値が含まれている場合、背景を赤くすることができた。

次回は,グラフで基準値が一目でわかるように色を付ける改良を行う。また,ユーザの基本情報を表示する機能,検査項目をグルーピングする機能,タブバーで画面を切り替える機能についてどのようにしたら実現できるか考える。

2018年7月12日木曜日

MONACAサンプルアプリの編集5

今回は、検査項目一覧を表示した際に、検査項目名だけでなく、検査値、単位の追加表示を試みる。まず、javascript上での編集を行う。
  1. Countries.get()
  2. .then(
  3. function(countries) {
  4. var list = countries.list[0];
  5. that.list = [];
  6. list.items.forEach(function(element){
  7. that.list.push(element.itemName);
  8. });
  9. }
  10. );
上記のコードは以前のブログで記述したcountries.list配列に検査名を格納する処理であるが、このコード6行目以降を下記の様に変更する。
  1. list.items.forEach(function(element){
  2. that.list.push(
  3. {
  4. itemName:element.itemName,
  5. value:element.value,
  6. unit:element.unit
  7. }
  8. );
以前のブログで調べた検査―データ中にある検査名、検査値、単位それぞれに対応する値をpushメソッドを利用してthat.list配列の中に格納する。javascriptでは、この様なディクショナリ形式(連想配列)で関連する一塊のデータをまとめて記述できる。
次に、このままでは追加した検査値や単位がスクリーンには表示されないので、htmlの修正も行っていく。
  1. <ons-list>
  2. <ons-list-item ng-click="countries.showCountry(country)" modifier="chevron"
  3. ng-repeat="country in countries.list | filter:query">
  4. {{ country }}
  5. </ons-list-item>
4行目の{{country}}はcounties.listから取り出した要素データを表示するものだが、これを下記の様に書き換える。
  1. {{ country.itemName }}
  2. {{ country.value}}
  3. {{ country.unit}}
この様にcountry.検査名(itemName),検査値(value),単位(unit)と記述することで、対応したデータを表示することが出来る。
図1 検査項目一覧画面
これらの変更を行う事で、上記図1の様に検査項目のほかに、検査値、単位を表示させることが出来る。しかし、このままの状態では少々見栄えがよくないので、先ほどのhtmlを下記のように書き換える。
  1. <ons-col>{{ country.itemName }}</ons-col>
  2. <ons-col>{{country.value}}</ons-col>
  3. <ons-col>{{country.unit}}</ons-col>
<ons-col>はonsen-UI上で列を表示するタグである。
図2 ons-colタグで整形した検査項目一覧画面
上記はコードを書き換えた後の検査項目一覧画面である。先ほどの比較すると多少は見栄えがよくなってはいるが、まだ少し見栄えがよくない。そのため、再びhtml文を下記のように修正する。
  1. <ons-col width="60%">{{ country.itemName }}</ons-col>
  2. <ons-col>{{country.value}}</ons-col>
  3. <ons-col>{{country.unit}}</ons-col>
1行目にwidthを記述することで幅の調節を行う事が出来る。

図3 width属性で幅の調整を行った検査項目一覧画面
これにより、上記の図3の様に見栄えを整えることが出来た。
次回は検査値が基準値より外れている場合、色を変えて表示するようにプログラムを修正する。その準備として今回は簡単にcssの記述を行っておく。

正常値の場合

  1. <ons-list-item class="normal" ng-click="countries.showCountry(country.itemName)...

異常値の場合

  1. <ons-list-item class="abnormal" ng-click="countries.showCountry(country.itemName)...
まず、htmlの「ons-list-item」タグへ「normal」「abnormal」というclassの値を設定する。
検査値が基準値の範囲内であれば「normal」、範囲外であれば「abnormal」として色の変更を行う。そのために,style.cssでnormal,abnormalの定義を行う。
  1. .abnormal {
  2. background-color: #FF0000;
  3. }
  4.  
  5. .normal{
  6. background-color: #FFFFFF;
  7. }
上記の記述はそれぞれ「abnormal」であれば背景を赤、「normal」であれば背景を白にするといった定義である。
次回は,基準値から検査値が異常値かどうかを判定して,その結果から<ons-list-item>のclass属性に設定する値(normalまたはabnormal)を決定するプログラムを作成する。また、表示されている検査値の桁数があまりに長く見づらいため、表示は小数点以下2桁までにしたい。

中間報告会で受けた指摘と今後の方針

先日行われた中間報告会で「すでに類似したシステムは世にたくさん出ているが,それとこのシステムはいったいどこが違うのか」という質問を受けた。電子カルテシステムと直接つながっているPHR(個人健康記録)などカルテコ以外にそんなに例はないとは思うが,検査結果をグラフ表示するだけのアプリならどこにでも転がっているので,そのように思われてもしかたがないだろう。
そこで,今後,このシステムをどのように発展させていくかを考えてみた。

「医療情報学第5版医療情報システム編」のP74に次のような記載がある。
さらに健康志向の個人の増加に伴い,個人が常に携帯しているスマートフォンなどを利用して日々の運動量,心拍数,食事量,睡眠状態などの多種多様な項目を測定して管理できるアプリケーションが提供され始めている。
さらに
現段階では,これらのアプリケーションはスタンドアローンで動作しており,アプリケーション同士や特定健診システムや保健指導システムとの連携は取れていない。 しかし将来的には,アプリケーションが連動して日々健康指導を密に行うようなことが望まれる。このようなデータも含めた個人の生涯にわたる健康情報を管理し解析することで,個人に最適な快適で効果が高く効率的な健康指導が可能になると期待される。
と続く。
これをヒントに次のような機能を加えてはどうだろうか。
  1. 医師や保健師が電子カルテに入力した保健指導の内容をスマホアプリに表示する。
  2. 利用者の食事内容を写メで撮影して電子カルテ(または画像サーバ)へアップロードし,管理栄養士がそれを見て栄養指導する。
  3. 食事内容を撮影した画像から食材や栄養素,カロリーなどを計算してくれるWebAPIを探して利用する。
  4. 家庭用の体重計,血圧計,体温計などで計測したデータをスマホに自動取り込みするインターフェースがないか調べて,あれば利用する
  5. 天気APIを利用して天気や気温・気圧を自動でスマホに蓄積する

プログラムの改良についてのTODOリスト

  1. 検査項目一覧画面におけるグルーピング(例:生化学的検査)
  2. 検査項目のヘルプ(Google検索へリンクするなど)
  3. グラフの基準値の表示方法の工夫(色を付けるなど)
  4. グラフ画面で他の検査項目を選択する機能
  5. 患者基本属性(名前,生年月日など)の表示 
  6. 「設定」「保健指導」などの機能を追加するためのユーザインターフェース(タブバー,スライディングメニュー)
  7. Googleマップ(フィットネスクラブ)


2018年7月5日木曜日

MONACAサンプルアプリの編集4

今回は、グラフの描画部分のプログラミングを行う。具体的には、指定した国、年の人口を取得するPopulationサービスを書き換えて、OpenDolphinから指定した検査項目の検査結果を検査履歴から取得する処理を行う。
  1. nv.addGraph(function() {
  2. chart = nv.models.stackedAreaChart()
  3. .useInteractiveGuideline(true)
  4. .showControls(false)
  5. .margin({left: 50, right: 30});
上記のコードはNVD3を用いたグラフ描画の方法なのだが、これを以下のコードに書き換える
  1. nv.addGraph(function() {
  2. chart = nv.models.lineChart()
  3. .useInteractiveGuideline(true)
  4. .showControls(false)
  5. .margin({left: 50, right: 30});
2行目の「chart = nv.models.lineChart()」という記述を用いることで折れ線グラフの描画を行う事が出来る。しかし、この状態でアプリケーションを実行すると、エラーが表示され、グラフの描画を行う事が出来ない。3~5行目の.から始まる記述はメソッドを示しているのだが、いずれかのメソッドがlineChartのメソッドではないものが記述されている為、エラーが表示されてしまう。ここで、一つ一つのメソッドに対してコメントアウトを行い、どのメソッドがlineChartのものではないのか検証したところ、4行目の「.showControls(false)」といったメソッド(グループモードと積み上げモードを切り替える)がlineChartのメソッドではなかったので、このメソッドをコメントアウトしたところ、折れ線グラフでの描画を行う事が出来た。

次に、グラフのx軸に示されている日時が適切な形式になっていないため、変換を行う必要がある。
  1. chart.xAxis
  2. .tickFormat(d3.format(',r'));
この「chart.xAxis」というものは、グラフのx軸を示しているものである。2行目の「.tickFormat」というものは目盛の形式を示しており、(,r)のrは数字という意味であり、カンマは数字に3桁ごとにカンマを付与するといったものである。
これを、以下の書式に書き換える。
  1. chart.xAxis
  2. .tickFormat(
  3. function(d) {
  4. return d3.time.format('%Y-%m-%d')(new Date(d));
  5. }
  6. );
上記のxAxisのtickFormatメソッドは、変数dを通じて渡されてきた座標目盛りの値を、無名関数を使って任意の形式に編集している。ここでは基準日時からの経過秒が格納されている数値変数dをnew Date(d)によってJavascriptの日付オブジェクトに変換し、それをd3.time.format関数を使って書式'%Y-%m-%d'により「YYYY-MM-DD」の形式に編集している。
図1 x軸の目盛りを日付にしたグラフ画面
これよにり、上記図1のようにx軸に日付を表示することができた。
次に、y軸の値に単位を追加する処理を行う。
  1. chart.yAxis
  2. .tickFormat(function(d) {
  3. if ((d / 1000000) >= 1) {
  4. d = Math.round(d / 100000) / 10 + 'M';
  5. }
  6. else if ((d / 1000) >= 1) {
  7. d = Math.round(d / 100) / 10 + 'K';
  8. }
  9. return d;
  10. });
これは1,000,000や、1,000等の値の大きい数をそれぞれ、MやKの単位をつけて短くするものであるが、今回扱うデータはあまり大きい値ではないので、この部分をコメントアウトする。
  1. chart.yAxis
  2. .tickFormat(function(d) {
  3. /* if ((d / 1000000) >= 1) {
  4. d = Math.round(d / 100000) / 10 + 'M';
  5. }
  6. else if ((d / 1000) >= 1) {
  7. d = Math.round(d / 100) / 10 + 'K';
  8. }*/
  9. return d + scope.data[0].unit;
  10. });
9行目の「d + scope.data[0].unit;」という記述でグラフのy軸の数値に検査単位を付与することが出来る。ここで、scope.dataは、PopulationChartディレクティブのビューであるHTML中のpopulation-chartタグに付与されたdata属性を表している(下記)。
  1. <population-chart ng-if="country.showChart" data="country.population"></population-chart>
このcountry.populationにはPopulationサービスで作成した検査項目の時系列データが配列として格納されており、その直近の検査日の結果scope.data[0]の検査単位であるscope.data[0].unitを使用してy軸の目盛りに単位をつけている。

現状のグラフでは、正常値の上限値と下限値がy軸の最大値と最小値になってしまい、基準値の範囲がわかりくい状況である。そこで、y軸の範囲(最大値と最小値)を広げることにした。尚、検査項目ごとに基準値の値は異なるので、基準値の上限値や下限値に定数を加えたり引いたりしてy軸の最大値や最小値を設定するのは適切ではない。したがって、y軸の最大値を「基準値の上限値 + 上限値と下限値の差」、最大値を「下限値 - 上限値と下限値の差」とすることにした。そのために、lineChartのyDomainメソッドに以下のように目盛りの範囲を設定した。
  1. .yDomain([2 * lower-upper, 2 * upper-lower])
ここで、「lower」は基準値の下限、「upper」は基準値の上限である。
このように座標軸の最小・最大を設定するにはyDomainメソッドを使用する。
次に、基準値の下限「lower」と上限「upper」をscope.dataから求める。
  1. var normalValue = scope.data[0].normalValue.split(/-/);
  2. var lower = parseFloat(normalValue[0]);
  3. var upper = parseFloat(normalValue[1]);
直近の検査項目の情報はscope.data[0]に入っているので、そこから基準値scope.data[0].normalValueを取り出し、それを区切り文字「-」で分割し、先頭要素を下限値、2番目の要素を上限値として実数に変換する。これにより、下記の図2の様にグラフのy軸の最大値と最小値の設定を行う事ができ、正常値範囲がわかりやすくなった。

図2 基準値範囲を見やすくしたグラフ画面
ただし,図2をよく見ると,縦軸の最大値と最小値の値が計算誤差のせいで「・・・9999」と歯切れの悪い数値になっているので,編集する必要がある。

2018年7月4日水曜日

MONACAのサンプルアプリ編集3

前回は、Populationサービスを使ってOpenDolphinの検査データから、前の画面で選択した検査項目の時系列データを取得する処理を作成した。今回は、この取得したデータを使ってグラフを描画するためのデータ加工処理、およびグラフ描画を行う。
  1. .controller('PopulationChartController', ['$scope', function($scope) {
  2. $scope.formatData = function() {
  3. if (!$scope.data) {
  4. return [];
  5. }
  6. alert(JSON.stringify($scope.data,null,2));
  7.  
  8. var total = [],
  9. males = [],
  10. females =[];
  11.  
  12. for (var i = 0; i < $scope.data.length; i++) {
  13. var data = $scope.data[i];
  14.  
  15. total.push({x: data.age, y: data.total});
  16. males.push({x: data.age, y: data.males});
  17. females.push({x: data.age, y: data.females});
  18. }
まず、Javascriptの上記「poplationchartController」の12行目からのプログラムを以下のものに書き換える。
  1. $scope.data.forEach(function(item){
  2. var strDate = item.sampleDate.replace(/ /g, ' 02:');
  3. var sampleDate =Date.parse(strDate.replace(/-/g, '/'));
  4. var value =parseFloat(item.value);
  5. var normalValue = item.normalValue.split(/-/);
  6. var lower = parseFloat(normalValue[0]);
  7. var upper = parseFloat(normalValue[1]);
  8.  
  9. total.push({x: sampleDate, y: upper});
  10. males.push({x: sampleDate, y: value});
  11. females.push({x: sampleDate, y: lower});
  12. });
  13.  
  14. return [
  15. {
  16. key: '上限',
  17. values: total
  18. },
  19. {
  20. key: '下限',
  21. values: females
  22. },
  23. {
  24. key: '検査結果',
  25. values: males
  26. }
  27. ];
  28. };
OpenDolphinから取得した検査結果は以前のブログに書いたように次のようなフォーマットをしている。
{
  "list": [
    {
      "progressState": null,
      "items": [
        {
          "laboCode": null,
          "lipemia": null,
          "hemolysis": null,
          "dialysis": null,
          "reportStatus": "E",
          "groupCode": "01",
          "groupName": "生化学的検査",
          "parentCode": "0001",
          "medisCode": "3J010000002327101",
          "itemName": "総ビリルビン",
          "abnormalFlg": null,
          "normalValue": "0.2-1.2",
          "specimenCode": "023",
          "specimenName": "血清",
          "commentCode1": null,
          "comment1": null,
          "commentCode2": null,
          "comment2": null,
          "sortKey": null,
          "itemCode": "0001",
          "sampleDate": "2018-05-06 00:00",
          "patientId": "1.3.6.1.4.1.9414.70.1:00001",
          "unit": "mg/dL",
          "value": "0.4",
          "id": 1120
        },
       
       
       ・     
      (中略)
       
       
       
        {
          "laboCode": null,
          "lipemia": null,
          "hemolysis": null,
          "dialysis": null,
          "reportStatus": "E",
          "groupCode": "07",
          "groupName": "一般検査",
          "parentCode": "0493",
          "medisCode": "1B040130201506211",
          "itemName": "便中ヒトヘモ定性2日目",
          "abnormalFlg": null,
          "normalValue": "陰性",
          "specimenCode": "015",
          "specimenName": "便",
          "commentCode1": null,
          "comment1": null,
          "commentCode2": null,
          "comment2": null,
          "sortKey": null,
          "itemCode": "0493",
          "sampleDate": "2018-05-04 00:00",
          "patientId": "1.3.6.1.4.1.9414.70.1:00001",
          "unit": null,
          "value": "インセイ",
          "id": 1084
        }
      ],
      "sampleDate": "2018-05-04 00:00",
      "laboCenterCode": "LSCC",
      "moduleKey": "LSCC2018050442011",
      "reportFormat": null,
      "patientName": "山下 浩介",
      "patientSex": "M",
      "numOfItems": null,
      "patientId": "1.3.6.1.4.1.9414.70.1:00001",
      "id": 1051
    }
  ]
}
この中で、検査日時はsampleDateで、「2018-06-06 00:00」という形式になっている。Javascriptで日時として認識されるデータは「2018/06/06 00:00:00」という形式なので、これを正規表現を使って適切な書式に書き換える。
var strDate = item.sampleDate.replace(/ /g, ' 02:');
まず、「strDate」という変数を定義し、検査日時item.sampleDate中のスペースを「 02:」に置き換える。これにより、元の時刻「00:00」を「02:00:00」という時分秒の形式に置き換えることができる。なお、「02:00:00」は午前2時0分0秒を意味するが、この時間には意味がない。「01:00:00」でも何でもよかった。
var sampleDate =Date.parse(strDate.replace(/-/g, '/'));
次に、strDate.replace(/-/g, '/')で「strDate」の中の「-」を「/」へ置き換えて、日付「2018-06-06」を「2018/06/06」という形式に変換し、「Date.parse」という命令により文字列の日時をJavascriptの日時オブジェクトに変換する(Javascriptの日付オブジェクトは基準日時からの経過秒で表現されている)。これらの置き換え作業によって、検査日時を変数「sampleDate」に設定できた。
 var value =parseFloat(item.value);
これは、検査値「item.value」を「paresFloat」命令で文字列から実数値に変換し、変数「value」に代入しているところである。
var normalValue = item.normalValue.split(/-/);
var lower = parseFloat(normalValue[0]);
var upper = parseFloat(normalValue[1]);
これは「item.normalValue」に入っている検査の基準値を上限と下限に分離して、それぞれ変数「upper」と「lower」に格納する処理である。item.normalValueの中に格納されている値は「0-10」という書式になっているので、「-」を区切り文字として、「-」の前後で数字を分ける。例えば、「0.2-1.2」という値であれば、「0.2」と「1.2」の二つの値に分け、それぞれを下限値、上限値とする。
そのために、splitメソッドを使う。item.normalValue.split(/-/)は、item.normalValueの中身を「-」を区切り文字として分割し、その結果を配列に格納する。したがって変数「normalvalue」の先頭要素「normalValue[0]」には下限値が、2番目の要素「normalValue[1]」には上限値が格納される。
こうして得られた下限値・上限値をparseFloat関数を使って実数値に変換し、それぞれ変数「lower」,「upper」へ代入する。
total.push({x: sampleDate, y: upper});
males.push({x: sampleDate, y: value});
females.push({x: sampleDate, y: lower});

こうして 検査日時、検査結果、基準値の下限値・上限値が得られたので配列「total」へは上限値を、配列「males」へは検査値を、そして配列「females」へは下限値を、それぞれ追加している。
これらの処理により、グラフの描画が行えるようになった。
実際にスマートフォンの方で確認したところ、図1の様な画面が表示され、グラフの描画を行うことが出来た。
図1 検査結果グラフ
ただし、このグラフは折れ線グラフではなく、積み上げグラフになっている。これは、元のアプリがそのような仕様になっているからである。また、X軸の目盛りが日付ではなく数値になっている。これはJavascriptの日付オブジェクトの内部形式(基準日時からの経過秒)がそのまま表示されているからである。さらに、Y軸に単位が表示されていない。
次回は折れ線グラフになるように、そして、X軸の目盛りが日付に、Y軸に単位を表示するように修正を行っていきたい。
 それからもう一つ。全画面の検査一覧画面に検査結果が表示されていない。基準値外であれば色をつけて強調するなどしたい。
 また、単に折れ線グラフだけでなく検査項目に応じたグラフ表示も考えたい。
 さらに、検査項目によっては、複数の項目を比較しながら見たいケースがあるかもしれない。そのような検査項目を調べて、同時に複数の検査値を表示する機能(例えばバランスを見ることができるようなレーダーチャートなど)も持たせたい。
 患者名など患者情報が表示されていないので、それも表示したい。基本情報、バイタル、アレルギーなど。

レーダーチャートの表示2

前回 レーダーチャートの表示を行うことが出来たので、今回は実際の値を代入したグラフの描画を試みる。 .controller('RaderChartController', ['$scope', 'Countries', funct...