LoginSignup
7
2

More than 5 years have passed since last update.

【Python】DashでRの出力を呼び出して描画する

Last updated at Posted at 2019-03-31

image.png

背景

Dashで可視化アプリケーションを作りたいが、出力する内容の一部をRのpackageから出力したい場面がありました。

UI(dropdown)はDashで用意して、計算の部分はRで行うような簡単なサンプルを作ってみます。

  • 環境

    • macOSX Mojave version 10.14,3
    • Python 3.6.1
    • R version 3.5.3
    • 実行環境はlocalで
  • 仕様

    • Dropdownで表示するBayesian networkを選んで,Rでinputに応じたネットワークが返されて描写される

方法

PythonからRを実行するとか、やり方は無数にありそうですが、ひとまず以下の流れで1パターン実装してみます。

  • 目次
    • 1. R(plumber)でAPIserverを準備
    • 2. Dashで、inputの内容をクエリパラメータに反映させてhtml.Img()で1.のエンドポイントにGETリクエストを送る
    • 3. できた

image.png

実装

ファイル構造は以下のようにします

$ tree
.
├── R
│   ├── run.R
│   └── api.R
├── app
│   └── app.py
└── README.md

1. R(plumber)でAPI serverを準備

GETリクエストのクエリパラメータ?type=に応じて描くBNが変わるようにfunctionを書きます。

api.R

library(plyr)
library(dplyr)
library(bnlearn)
library(plumber)
library(magrittr)

# BNを定義
alarm.model.string <- paste("[HIST|LVF][CVP|LVV][PCWP|LVV][HYP][LVV|HYP:LVF]",
                            "[LVF][STKV|HYP:LVF][ERLO][HRBP|ERLO:HR][HREK|ERCA:HR][ERCA]",
                            "[HRSA|ERCA:HR][ANES][APL][TPR|APL][ECO2|ACO2:VLNG][KINK]",
                            "[MINV|INT:VLNG][FIO2][PVS|FIO2:VALV][SAO2|PVS:SHNT][PAP|PMB][PMB]",
                            "[SHNT|INT:PMB][INT][PRSS|INT:KINK:VTUB][DISC][MVS][VMCH|MVS]",
                            "[VTUB|DISC:VMCH][VLNG|INT:KINK:VTUB][VALV|INT:VLNG][ACO2|VALV]",
                            "[CCHL|ACO2:ANES:SAO2:TPR][HR|CCHL][CO|HR:STKV][BP|CO:TPR]", sep = "") 
alarm.net <- alarm %>%
  names %>%
  empty.graph %>%
  `modelstring<-`(value = alarm.model.string)

#* @get /bayesiannetwork
#* @png
bn <- function(type="type1") {
  if(type=="type1"){
    plot(hc(learning.test))
  } else if(type=="type2"){
    graphviz.plot(alarm.net)
  } else {
    graphviz.plot(moral(alarm.net))
  } 
}

細かい解説



これによって
/bayesiannetwork?type=type1なら↓が返されて、

api.R
plot(hc(learning.test))

/bayesiannetwork?type=type2なら↓が、

api.R
graphviz.plot(alarm.net)

/bayesiannetwork?type=type3なら↓が返されるapiができます!

api.R
graphviz.plot(moral(alarm.net))

  • 上のapi.Rを実行するscriptを用意します.
run.R
library(plumber)

rapi <- plumb("api.R")
rapi$run(port=8888)

ここまで準備できたら、以下のコマンドでAPIサーバーを立ち上げます

$ Rscript run.R

Running plumber API at http://127.0.0.1:8888

2. Dashで、inputの内容をクエリパラメータに反映させてhtml.Img()で1.のエンドポイントにGETリクエストを送る

  • dashのdash_core_components.Dropdownで選んだ内容が、クエリパラメータに反映されたリンクを生成するような処理を書きます
app.py

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State


app = dash.Dash()
app.title = 'dash app with python and R'
app.scripts.config.serve_locally = True
app.config.suppress_callback_exceptions = True

app.layout = html.Div([
    html.H1(children='dash app with python and R'),
    dcc.Dropdown(
        id='my-dropdown',
        options=[
            {'label': 'Bayesian network 1', 'value': 'type1'},
            {'label': 'Bayesian network 2', 'value': 'type2'},
            {'label': 'Bayesian network 3', 'value': 'type3'}
        ],
        value='type1'
    ),

    html.Div(id='output-container')
])


@app.callback(
    dash.dependencies.Output('output-container', 'children'),
    [dash.dependencies.Input('my-dropdown', 'value')])
def render_link_with_parameter(value):
    url = 'http://localhost:8888/bayesiannetwork' + "?type=" + value
    render_div = html.Div(
        html.Div([
            html.P(url),
            html.Img(src=url)
        ])
    )
    return render_div



if __name__ == '__main__':
    app.run_server(debug=True)

  • dropdownで選んだ内容が、のちに生成するlinkのurlに反映されるようになっています。
  1. dropdownで描画するネットワークを選ぶ
  2. render_link_with_parameterが実行される
  3. 先ほど準備したAPIにGETリクエストが飛んで、RがBNを描画する
  4. htmlにネットワークが表示される
  • ここまで準備できたら、別なterminalからdashのapplicationのサーバーを起動します
$ python ¥app.py

3. できた

ezgif.com-video-to-gif.gif

おわりに

  • PythonとRの連携方法として、API経由でやりとりするのは便利そうでした
  • 画像の出力だけじゃなく、htmlwidgetsなどもRから返せるとのことです
  • よりスマートな方法があればぜひ教えてください:bow_tone1:

参考

7
2
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
7
2