本文へスキップ
からだにいいもの

Rのトピックスを中心に『まだ、まだ、知らない、役に立つ情報?』を発信します。

Rで解析:SQLの問い合わせにVISUALIZE句を足してプロットする「ggsql」パッケージ

「ggsql」パッケージは、いつものSQLの問い合わせにVISUALIZE句とDRAW句を書き足すだけで、集計した結果をそのままプロットにできるパッケージです。Rのデータフレームを表として登録すれば、絞り込みや集計から図の指定までを1本の問い合わせで書けます。中ではDuckDBが動くので、別にデータベースを用意する必要はありません。仕上がった図はSVGやPDF、PNGで保存でき、Shinyアプリにもそのまま埋め込めます。SQLに慣れていて、集計した結果をすぐ図で確かめたい人に向いていると考えます。

パッケージバージョンは0.5.2。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。

パッケージのインストール

下記コマンドを実行してください。

# パッケージのインストール
install.packages("ggsql")

# パッケージの読み込み
library("ggsql")
スポンサーリンク

コマンド例

詳細はコメント、パッケージのヘルプを確認してください。

ggsqlでは、データを読む窓口を「リーダー」と呼びます。リーダーにデータフレームを表として登録し、SQLの問い合わせを投げます。プロットにするときは、SELECT文の後ろに「VISUALIZE 列名 AS x, 列名 AS y」で軸の対応を、「DRAW point」「DRAW line」「DRAW bar」で図の種類を書きます。ggsql_executeコマンドが返すのは図の仕様(Spec)で、これを書き出し役の「ライター」に渡すとSVGなどの形になります。

以下の例では、共通のデータとして、京都府内の4地区(左京区、伏見区、亀岡市、京丹後市)における、京野菜の月別出荷量と単価を模したデータを作成します。

# 乱数を固定
set.seed(1234)

# 4地区×12か月の出荷量と単価の架空データを作成
shukka <- data.frame(
  chiku = rep(c("左京区", "伏見区", "亀岡市", "京丹後市"), each = 12),
  tsuki = rep(1:12, times = 4),
  ryou = round(rnorm(48, mean = 120, sd = 30)),
  tanka = round(runif(48, min = 250, max = 600))
)

DuckDBのリーダーを作る:duckdb_readerコマンド

問い合わせ先になるDuckDBのリーダーを作ります。databaseを指定しなければメモリ上に作られ、Rを閉じると消えます。

オプション意味初期値
databaseDuckDBのデータベースファイルのパス、NULLの場合はメモリ上に作るNULL
# メモリ上にDuckDBのリーダーを作成
reader <- duckdb_reader()

データフレームを表として登録する:ggsql_registerコマンド

Rのデータフレームを、リーダーの中の表として登録します。登録した名前でSQLから参照できます。登録済みの表の一覧はggsql_table_namesコマンド、登録の解除はggsql_unregisterコマンドで行います。

オプション意味初期値
readerduckdb_reader()などで作成したリーダーなし
df登録するデータフレームなし
name表の名前なし
replaceTRUEの場合は同じ名前の表を置き換えるFALSE
# 出荷データを "shukka" という表として登録
ggsql_register(reader, shukka, "shukka")

# 登録されている表の名前を確認
ggsql_table_names(reader)
[1] "shukka"

SQLの結果をデータフレームで受け取る:ggsql_execute_sqlコマンド

VISUALIZE句を含まない、ふつうのSQLを実行して結果をデータフレームで受け取ります。プロットにする前に集計の中身を確かめるときに使えます。

オプション意味初期値
readerduckdb_reader()やodbc_reader()などで作成したリーダーなし
query実行するSQLの文字列なし
# 地区ごとの年間出荷量と平均単価を集計し、出荷量の多い順に並べる
ggsql_execute_sql(
  reader,
  "SELECT chiku, SUM(ryou) AS goukei, ROUND(AVG(tanka), 1) AS heikin_tanka
   FROM shukka GROUP BY chiku ORDER BY goukei DESC"
)
     chiku goukei heikin_tanka
1   伏見区   1440        414.6
2   左京区   1282        343.4
3   亀岡市   1233        469.7
4 京丹後市   1159        460.9

問い合わせからプロットを作る:ggsql_executeコマンド

VISUALIZE句とDRAW句を含む問い合わせを実行し、図の仕様(Spec)を返します。表示するとプロットになります。GROUP BYで集計した結果をそのまま棒グラフにしたり、「AS stroke」で地区ごとに線の色を分けたりできます。

オプション意味初期値
readerduckdb_reader()やodbc_reader()などで作成したリーダーなし
queryggsqlの問い合わせの文字列(SQLとVISUALIZE句)なし
# 地区ごとの年間出荷量を集計し、棒グラフにする
spec_bar <- ggsql_execute(
  reader,
  "SELECT chiku, SUM(ryou) AS goukei FROM shukka GROUP BY chiku
   VISUALIZE chiku AS x, goukei AS y
   DRAW bar
   LABEL title => '地区別の年間出荷量'"
)

# プロットを表示
spec_bar

# 6月以降の出荷量の推移を、地区ごとに色を分けた折れ線にする
spec_line <- ggsql_execute(
  reader,
  "SELECT * FROM shukka WHERE tsuki >= 6
   VISUALIZE tsuki AS x, ryou AS y, chiku AS stroke
   DRAW line"
)

# プロットを表示
spec_line

問い合わせを実行前に確かめる:ggsql_validateコマンド

SQLを実行せずに、問い合わせの書き方に誤りがないかを確かめます。結果が正しいかどうかはggsql_is_validコマンドでTRUE/FALSEとして取り出せます。

オプション意味初期値
query確かめるggsqlの問い合わせの文字列なし
# 折れ線の問い合わせの書き方を確かめる
ggsql_validate(
  "SELECT * FROM shukka WHERE tsuki >= 6
   VISUALIZE tsuki AS x, ryou AS y, chiku AS stroke
   DRAW line"
)
<ggsql_validated> [valid]
• Has VISUALISE clause

プロットをファイルに保存する:ggsql_saveコマンド

図の仕様をファイルに書き出します。形式はファイルの拡張子で決まり、.svg、.pdf、.hep、.png、.jsonが使えます。.pngの書き出しにはrsvgパッケージが要ります。

オプション意味初期値
specggsql_execute()が返した図の仕様なし
file保存先のパス、拡張子で形式(.svg、.pdf、.hep、.png、.json)が決まるなし
width幅(ピクセル)600
height高さ(ピクセル)400
dpi解像度(1インチあたりのドット数)96
# 地区別の棒グラフを幅800、高さ500のSVGとして保存
ggsql_save(spec_bar, "shukka_chiku.svg", width = 800, height = 500)

地区別の棒グラフを幅800、高さ500のSVGとして保存

ライターで図の形式に変える:ggsql_renderコマンド

図の仕様をライターに渡して、SVGの文字列などに変えます。ライターにはsvg_writer、pdf_writer、hep_writerがあります。ファイルに保存せず、文字列のままほかの処理に渡したいときに使います。

オプション意味初期値
writersvg_writer()などで作成したライターなし
specggsql_execute()が返した図の仕様なし
# 折れ線の仕様を幅800、高さ500のSVGの文字列に変える
svg_text <- ggsql_render(svg_writer(width = 800, height = 500), spec_line)

# SVGの文字列をファイルに書き出す
writeLines(svg_text, "shukka_suii.svg")

SVGの文字列をファイルに書き出す

Shinyアプリにプロットを置く:ggsqlOutputコマンド

Shinyアプリの画面に、ggsqlのプロットを表示する枠を置きます。サーバー側ではrenderGgsqlコマンドに問い合わせの文字列を渡します。例では、選んだ地区の月別出荷量を棒グラフにします。

オプション意味初期値
outputId表示に使う出力の名前なし
width表示枠の幅(CSSの指定)“100%”
height表示枠の高さ(CSSの指定)“400px”
# Shinyを読み込み
library("shiny")

# 地区を選ぶ欄と、プロットの表示枠を置いた画面を作成
ui <- fluidPage(
  selectInput("chiku", "地区", choices = unique(shukka$chiku)),
  ggsqlOutput("chart", height = "450px")
)

# 選んだ地区の月別出荷量を棒グラフにする処理を作成
server <- function(input, output, session) {
  output$chart <- renderGgsql(
    {
      sprintf(
        "SELECT * FROM shukka WHERE chiku = '%s'
       VISUALIZE tsuki AS x, ryou AS y
       DRAW bar",
        input$chiku
      )
    },
    reader = reader
  )
}

# アプリを起動
shinyApp(ui, server)


この記事が誰かの役に立ちますように。

スポンサーリンク
価格および配送状況は変更される場合があります。購入時は商品ページをご確認ください。
当サイトに表示されている商品情報はAmazonから提供されたものであり、更新または削除される場合があります。
karada-goodはAmazonアソシエイトとして、適格販売により収入を得ています。