ふんわり R-tips

ぜんぜんわからない、俺たちは雰囲気でRをやっている

ShinyアプリケーションをHTMLでカスタマイズする方法

このエントリは、Shiny公式サイトのCustomize your UI with HTMLを抜粋・翻訳・追記したものです。

https://shiny.rstudio.com/articles/html-tags.html

Shinyアプリケーションに任意のHTMLを追加してカスタマイズする方法を説明します。

Shinyアプリケーションのユーザインタフェース(UI)はweb上のドキュメントであり、ui.RがHTMLを生成するRの関数を実行して、webアプリケーションに変換しています。

shinyUIが生成するHTMLの説明

例として、01_helloを取り上げます。以下の説明は、08_htmlと重複する部分があります。

library(shiny)
runExample("01_hello")

上記のコードでサンプルアプリケーション「01_hello」が実行されます。01_helloのui.Rスクリプトを以下に示します。

library(shiny)

# Define UI for application that draws a histogram
shinyUI(fluidPage(

  # Application title
  titlePanel("Hello Shiny!"),

  # Sidebar with a slider input for the number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),

    # Show a plot of the generated distribution
    mainPanel(
      plotOutput("distPlot")
    )
  )
))

このコードは以下の図のようなアプリケーションを生成します。

f:id:phmpk:20161230151451p:plain

ui.Rスクリプト中shinyUI関数を呼び出します。shinyUI関数がHTMLを返すR関数を呼び出しています。コード内にHTMLを書く必要はなく、HTMLについて注意する必要はありません。以下のコードが返しているHTMLを、コメントアウトした行に記述します。

fluidPage(

  # Application title
  titlePanel("Hello Shiny!"),

  # Sidebar with a slider input for the number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),

    # Show a plot of the generated distribution
    mainPanel(
      plotOutput("distPlot")
    )
  )
)

## <div class="container-fluid">
##   <h2 style="padding: 10px 0px;">Hello Shiny!</h2>
##   <div class="row-fluid">
##     <div class="span4">
##       <form class="well">
##         <div>
##           <label class="control-label" for="bins">Number of bins:</label>
##           <input id="bins" type="slider" name="bins" value="30" class="jslider" data-## from="1" data-to="50" data-step="1" data-skin="plastic" data-round="FALSE## " data-locale="us" data-format="#,##0.#####" data-smooth="FALSE"/>
##         </div>
##       </form>
##     </div>
##     <div class="span8">
##       <div id="distPlot" class="shiny-plot-output" style="width: 100% ; height: ## 400px"></div>
##     </div>
##   </div>
## </div> 
titlePanel("Hello Shiny!")
## <h2 style="padding: 10px 0px;">Hello Shiny!</h2>

上記のHTMLに、任意のHTMLを追加してカスタマイズするために、tagsオブジェクトを使用します。

tags

shiny::tagsは110個の関数のリストです。各関数でHTMLタグを追加してアプリケーションをビルドします。関数名と、追加するHTMLタグの名前は対応しています。それぞれのタグの詳細はShiny HTML tags glossaryに書かれています。

names(tags)
##   [1] "a"           "abbr"        "address"     "area"        "article"
##   [6] "aside"       "audio"       "b"           "base"        "bdi"
##  [11] "bdo"         "blockquote"  "body"        "br"          "button"
##  [16] "canvas"      "caption"     "cite"        "code"        "col"
##  [21] "colgroup"    "command"     "data"        "datalist"    "dd"
##  [26] "del"         "details"     "dfn"         "div"         "dl"
##  [31] "dt"          "em"          "embed"       "eventsource" "fieldset"
##  [36] "figcaption"  "figure"      "footer"      "form"        "h1"
##  [41] "h2"          "h3"          "h4"          "h5"          "h6"
##  [46] "head"        "header"      "hgroup"      "hr"          "html"
##  [51] "i"           "iframe"      "img"         "input"       "ins"
##  [56] "kbd"         "keygen"      "label"       "legend"      "li"
##  [61] "link"        "mark"        "map"         "menu"        "meta"
##  [66] "meter"       "nav"         "noscript"    "object"      "ol"
##  [71] "optgroup"    "option"      "output"      "p"           "param"
##  [76] "pre"         "progress"    "q"           "ruby"        "rp"
##  [81] "rt"          "s"           "samp"        "script"      "section"
##  [86] "select"      "small"       "source"      "span"        "strong"
##  [91] "style"       "sub"         "summary"     "sup"         "table"
##  [96] "tbody"       "td"          "textarea"    "tfoot"       "th"
## [101] "thead"       "time"        "title"       "tr"          "track"
## [106] "u"           "ul"          "var"         "video"       "wbr"

divタグを生成するためには、以下のコードを実行します。

tags$div()
## <div></div> 

主なタグには、tags$なしのヘルプ関数が用意されています。例えばHTMLタグのcodetags$codeを呼び出します。tags$を付けることなくヘルパー関数を呼び出せるタグ関数は、a, br, code, div, em, h1, h2, h3, h4, h5, h6, hr, img, p, pre, span, strongです。

他のタグの名前を冠した関数はRのネイティブな関数と重複しているので、tags$を付けて呼び出す必要があります。

属性(Attributes)

タグ関数の引数は、そのままHTMLの属性を与えられます。引数の名前が属性の名前、引数の値が属性の値です。例えば、divタグに属性を追加するときは、以下のように、

tags$div(class = "header")
## <div class="header"></div>

値無しで属性を追加するときには、NAを設定します:

tags$div(class = "header", checked = NA)
## <div class="header" checked></div>

タグ関数の引数にネストしたHTMLを追加

各タグ関数の中に、ネストしたHTMLを引数にして加えることができます。

tags$div(class = "header", checked = NA,
  tags$p("Ready to take the Shiny tutorial? If so"),
  tags$a(href = "shiny.rstudio.com/tutorial", "Click Here!")
)
## <div class="header" checked>
##   <p>Ready to take the Shiny tutorial? If so</p>
##   <a href="shiny.rstudio.com/tutorial">Click Here!</a>
## </div> 
withTagsによるtags$の省略

withTags関数内ではtags$なしで、タグ関数を記述できます。

withTags({
  div(class="header", checked=NA,
    p("Ready to take the Shiny tutorial? If so"),
    a(href="shiny.rstudio.com/tutorial", "Click Here!")
  )
})
## <div class="header" checked>
##   <p>Ready to take the Shiny tutorial? If so</p>
##   <a href="shiny.rstudio.com/tutorial">Click Here!</a>
## </div>

01_helloのui.Rファイルに上記で説明したタグを追加すると、以下のコードになります。

library(shiny)

# Define UI for application that draws a histogram
shinyUI(fluidPage(

  # Application title
  titlePanel("Hello Shiny!"),

  # Sidebar with a slider input for the number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30),

      # adding the new div tag to the sidebar            
      tags$div(class="header", checked=NA,
               tags$p("Ready to take the Shiny tutorial? If so"),
               tags$a(href="shiny.rstudio.com/tutorial", "Click Here!")
      )
    ),

    # Show a plot of the generated distribution
    mainPanel(
      plotOutput("distPlot")
    )
  )
))

新しいHTMLとして、文とリンクが01_helloに追加されています。

f:id:phmpk:20170210195002p:plain

属性と子HTMLタグへの条件式

タグ関数の引数にNULLを設定すると、その引数はHTML出力中に現れません。以下のようにif文で条件式を指定することもできます。

tags$div(class = "header", id = NULL,
    NULL,
    "line 2"
)
## <div class="header">line 2</div> 


tags$div(class = "header", id = if (FALSE) 100,
    if (FALSE) "line 1",
    "line 2"
)
## <div class="header">line 2</div> 

List関数によるネスト

Rのlist関数を用いて、タグに子のリストを渡せます。タグ関数内で呼び出したlistは、そのタグの子としてリスト内の各要素が追加されます。

tags$div(class="header", checked=NA,
  list(
    tags$p("Ready to take the Shiny tutorial? If so"),
    tags$a(href="shiny.rstudio.com/tutorial", "Click Here!"),
    "Thank you"
  )
)
## <div class="header" checked>
##   <p>Ready to take the Shiny tutorial? If so</p>
##   <a href="shiny.rstudio.com/tutorial">Click Here!</a>
##   Thank you
## </div> 

HTMLの直接出力

タグオブジェクト、またはShinyUIの中に直接HTMLを記述することはできません。ShinyはHTMLそのままであれば、文字列として扱います。

tags$div(
  "<strong>Raw HTML!</strong>"
)
## <div>&lt;strong&gt;Raw HTML!&lt;/strong&gt;</div>

HTMLをそのまま加えるためには、HTML関数を用います。HTMLは(HTMLの)文字列を引数に取って、(Shinyの特別なクラスの)HTMLとして返します。

tags$div(
  HTML("<strong>Raw HTML!</strong>")
)
## <div><strong>Raw HTML!</strong></div> 

HTMLに渡されたコードに不備があってもエラーを返さない、という点に注意する必要があります。