見出し画像

腸閉塞番外編: 入院中だって楽しいことしたいので、R で CSS Grid Layout を使うcssgrid パッケージを作った

クローン病の悪化に伴う腸閉塞で入院して19–20日目のこと。退院が近付いて随分元気なので R言語の shiny パッケージを使った Web アプリケーション作りを楽しんでいた。ここで shiny の UI レイアウトの不自由さに不満を抱いたので、CSS Grid Layout による拡張を提供する cssgrid パッケージを作った。R Markdown によるレポートやスライドでも威力を発揮するので是非使ってみて欲しい。

ドキュメント: https://cssgrid.atusy.net/
GitHub: https://github.com/atusy/cssgrid/

CSS Grid Layout について

CSS Grid Layout では HTML と CSS を使って 格子状のマス目にコンテンツを配置していく。コンテンツ数に合わせて格子を自動で作ったり、複数の格子を繋げて特定のコンテンツの領域を大きく確保するなど、 応用の幅が広い。

乱暴な言いかたをするとエクセルのセルを結合したり拡大縮小しなが作ったレイアウトを端的に、柔軟に作れる。

日本語の紹介記事は @kura07 さんによる CSS Grid Layout を極める!(基礎編)が詳しいので見てみて欲しい。

以下では CSS Grid Layout を R から利用できる cssgrid パッケージの利用例を簡単に紹介する。

cssgrid パッケージ基本のキ

grid_item 関数で Grid Layout 内に配置したいコンテンツを作り、grid_layout 関数に食わせるだけ。grid_item の area 引数に入れたキーワードを、grid_layout の areas 引数で行列風に配置すると、レイアウト完了。行と列のサイズは grid_layout の rows 引数と cols 引数に指定する。

library(cssgrid)
style <- "border: solid black;"
grid_layout(
 grid_item("A", area = "a", style = style),
 grid_item("B", area = "b", style = style),
 grid_item("C", area = "c", style = style),
 cols = c("1fr 2fr"), rows = c("1fr 1fr"),
 areas = c("a b", 
           "a c"),
 style = style
)

Tidyverse 流のコーディングが可能

できるだけ data frame でデータを用意し、パイプの果てで出力するというのが Tidyverse 流のコーディングと理解しているが、勿論、 cssgrid パッケージは Tidyverse フレンドリーだ。例えば以下のようなよくあるレイアウトを作るコードも data frame でコンテンツを用意しておき、最後に grid_layout 関数で配置できる。

以下のソースコードは以下は https://cssgrid.atusy.net/articles/cssgrid.html#tidyverse-style-coding のものを改変した。

library(cssgrid)
library(tidyverse)

style <- "border: solid black;"

tibble(
  content = list(
    tags$h1("Title"), tags$h2("Sidebar"), tags$h2("Article A"), tags$h2("Article B")
  ),
  area = c("title", "side", "A", "B"),
  style = style
) %>%
  pmap(function(content, ...) grid_item(content, ...)) %>%
  tagList %>%
  grid_layout(
    cols = c("1fr 2fr"), rows = c("auto, 1fr 1fr"),
    areas = c(
      "title title",
      "side  A",
      "side  B"
    ),
    style = style
  )

Plotly で作った複数の図を画面幅に応じて再配置する

Plotly を使うと、マウスで拡大縮小や、ある点の情報を読むことが可能な図を作ることができる。更に CSS Grid Layout を使うと以下のように、複数の図を画面幅に応じて行数・列数を変更しながら表示することができるようになる。勿論 Plotly に限らず、任意のオブジェクトでいわゆるレスポンシブなレイアウトを提供できるようになる。

ソースコードと出力例はは https://cssgrid.atusy.net/articles/responsive.html を参照。

Shiny の UI のサイズを柔軟に決める

Shiny を使うと、R に HTML ベースな GUI を追加することができる。しかし、shiny パッケージが提供する関数では、UI のサイズを決定するために使える単位が px、%、em、pt、in、cm、mm、ex、pcに限られており、ある空間に複数の UI を割り当てたければ、全体の合計が 100% なり何なりになるよう調整する必要がある。これでは一つ UI が増減するごとに全体のサイズを弄り直さなければならない。

CSS Grid Layout には fr という単位があり、これを使うと、有効な空間を fr に与えた値を比率として塩梅できる。つまり、10cm 幅あるところに列の3列の幅 1fr 2fr 2fr として与えておくと、2cm 4cm 4cm にしてくれる。これだけなら 20% 40% 40% と変わりなさそうに見えるが、例えば 1fr 2fr 4cm といった書き方も可能で、こうするとまず、固定幅を優先し、fr 単位を持つ列のサイズは残りの幅から計算される。例えば幅10 cm なら 2cm 4cm 4cm に、19cm なら 5cm 10cm 4cm になる。

これを利用すると、ボタンのサイズを最小限にしつつ、入力フォームはできるだけ大きく、しかも適切な比率で配分する、といったことが可能になる。

ソースコードと出力例は https://cssgrid.atusy.net/articles/cssgrid.html#shiny-ui を参照。

終わりに

昨日の夕方ごろから作り出して、9時にはドキュメント整備に辿りついた。パッケージは思いつきさえすれば、案外すぐに作ることができる。みんなも日頃溜め込んだオリジナル関数があれば、是非パッケージ化して公開して欲しい。

まだまだドキュメントがこなれていないが、是非使ってみて、使いかたが分からなければ、ドキュメントの改善案を PR するなり Issue に挙げるなりして欲しい。



この記事が気に入ったらサポートをしてみませんか?