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

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

Rで解析:baseのRグラフィックスで高度な作図!「tinyplot」パッケージ〜

統計解析やデータ可視化を日常的に行うデータサイエンティストや研究者は、複雑なデータを効果的に伝えるための可視化手法に頭を悩ませることが少なくありません。特に、Rのbase graphics system(base R標準のグラフィックスシステム)は非常に強力で柔軟なプロット機能を備えていますが、グループ化したデータに凡例を付けて描画するといった処理には、複数回の関数呼び出しやプロット領域の調整、凡例の手動作成など、多くの手間がかかります。そうした悩みを解消してくれるのが、今回紹介する「tinyplot」パッケージです。自動凡例やfacet、テーマなどを簡単に設定でき、データの理解を深めるためのプロットを手軽に作成できます。

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

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

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

# パッケージのインストール
install.packages("tinyplot")
# パッケージの読み込み
library("tinyplot")
スポンサーリンク

コマンド例

詳細はコード内のコメントやパッケージのヘルプをご確認ください。

tinyplot() の使用例

tinyplot()はbase Rのplot()を置き換える中心的な描画関数で、by引数によるグループ化やfacetによるパネル分割、自動凡例の表示、テーマの適用などをオプション一つで指定できます。

オプション意味初期値
xxとyの引数がプロットのxとy座標を指定する。既存のベクトルやデータフレームの列名でも定義可能NULL
yxとyの引数がプロットのxとy座標を指定する。既存のベクトルやデータフレームの列名でも定義可能NULL
xmin関連する領域や区間プロットの最小・最大座標を指定する。「rect」または「segments」型の場合は4つの座標すべてが必要。「pointrange」「errorbar」「ribbon」型の場合はxに加えてymin/ymaxのみが必要NULL
xmax同上(xminの説明を参照)NULL
ymin同上(xminの説明を参照)NULL
ymax同上(xminの説明を参照)NULL
weights観測値の重みを指定するオプションの数値ベクトル。type_lm()やtype_spineplot()など、重みに対応する型でのみ使用される。対応していない型に指定すると警告が発生するNULL
labelsテキストラベルを指定する。type_text()で使用されるNULL
byグループ化変数を指定する。デフォルトは色別の表示NULL
facetfaceting変数を指定するNULL
facet.argsfacetの制御に使用するオプションのリストNULL
dataデータフレーム(またはリスト)から変数を取得するNULL
typeプロットの種類を指定する。NULL(デフォルト):xとyの入力タイプに応じて適切なプロットを選択NULL
legendレジェンドの位置を指定する。NULL(デフォルト):グループ変数に基づいて自動的にレジェンドが描かれるNULL
mainプロットのタイトルNULL
subプロットのサブタイトルNULL
capプロットのキャプションNULL
xlabx軸のラベルNULL
ylaby軸のラベルNULL
annデフォルトの注釈(タイトルとx、y軸ラベル)をプロットに表示するかどうかpar(“ann”)
xlimxの範囲を指定しますNULL
ylimyの範囲を指定しますNULL
axes軸を描画するかどうか、またはどのような軸を描画するかを指定しますTRUE
xaxtx軸の種類を指定しますNULL
yaxty軸の種類を指定しますNULL
xaxsx軸の間隔計算のスタイルを指定しますNULL
yaxsy軸の間隔計算のスタイルを指定しますNULL
xaxbx軸の目盛りが表示される点を指定しますNULL
yaxby軸の目盛りが表示される点を指定しますNULL
xaxlx軸の目盛りの表示形式を指定しますNULL
yaxly軸の目盛りの表示形式を指定しますNULL
log軸を対数目盛りにするかどうかを指定します(”x”、”y”、”xy”など)“”
flipプロットの向きを反転させるかどうかを指定しますFALSE
frame.plotプロットに枠線を描画するかどうかを指定しますNULL
grid背景パネルグリッドを自動的に追加するかどうかを指定する論理値または文字列NULL
paletteNULL(デフォルト)の場合、by グループ変数のクラスとカーディナリティ(水準数)に基づいてパレットが自動選択される。順序のない因子や文字列で水準数が妥当な範囲であればユーザーのデフォルトpalette()(例:”R4″)を継承し、順序因子や高カーディナリティの場合は”Viridis”パレットが使用される。palette.pals()やhcl.pals()に列挙されているパレット名を文字列で指定する、パレット生成関数を渡す、色のベクトル/リストを直接指定する、といった方法も可能NULL
pchプロットの記号を指定するNULL
ltyカテゴリ数に等しい長さの文字・整数またはベクトルを指定します。特別な値 lty = “by” を指定すると、グループ数に応じて自動的に線種がループしますNULL
lwd線幅。カテゴリ数に等しい長さの数値スカラーかベクトルを指定NULL
colカテゴリ数に応じた色を指定するNULL
bg背景色を指定するか、自動グループ化による色分けを継承NULL
fillbgの別名で、両方が指定された場合はbgが優先されるNULL
alphaアルファチャンネルの色調整用の数値(0は透明、1は不透明)NULL
cexプロットの文字や記号をデフォルトより何倍にスケールするかを指定する数値ベクトルNULL
add新しいプロットを描画するのではなく、現在のプロットに要素を追加するFALSE
drawプロットキャンバス上で直接描画するための関数。主に各facetの共通要素を追加する際に使用されるNULL
empty内側のプロット領域が空白になるかどうかを指定する論理値FALSE
restore.parパラメーター設定を復元するかどうかを指定する論理値FALSE
fileディスクにプロットを書き出すためのファイルパスを指定する文字列NULL
widthプロットの幅を指定する数値NULL
heightプロットの高さを指定する数値NULL
aspy/x のアスペクト比を指定します(plot.windowを参照)NA
theme一時的なテーマを定義するキーワードやリストNULL
formulaグループ化変数を含む、オプションの式NULL
subsetモデルフレームからデータを抽出する際に使用する、観測値の部分集合を指定する式NULL
na.actionモデルフレームからデータを抽出する際、欠損値(NA)が含まれる場合の処理方法を指定する関数NULL
drop.unused.levels因子の未使用水準を除外するかどうかを指定する論理値TRUE
# データの準備
aq = transform(
  airquality,
  Month = factor(Month, labels = month.abb[unique(Month)])
)

# 多くの場合、`tinyplot` は通常の `plot` の代替としてそのまま使用可能
op = tpar(mfrow = c(1, 2))
plot(0:10, main = "plot")
tinyplot(0:10, main = "tinyplot")
# 元のレイアウトに戻す
tpar(op)

# 補足:`tinyplot::tpar()` は `par()` の(ほぼ)代替として使用できる
# 通常のplotと異なり、tinyplotでは `by` 引数、あるいは同等の
# `|` を使ったformula構文でグループを指定できる
# atomicメソッド
with(aq, tinyplot(Day, Temp, by = Month))
# formulaメソッド
tinyplot(Temp ~ Day | Month, data = aq)

# (自動的に凡例も表示されることに注目)
# 入力の手間を省きたい場合は、同等の短縮エイリアス `plt()` も使用可能
# 短縮エイリアス
plt(Temp ~ Day | Month, data = aq)

# 標準的なbaseプロットの引数を使ってプロットの見た目を調整できる。
# 例えば `pch`(プロット記号)を変更して塗りつぶし点にしたり、
# `cex`(文字拡大率)でサイズを大きくしたりする。
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  pch = 16,
  cex = 2
)

# 特別な "by" 指定を使うと、これらの見た目の要素もグループごとに
# マッピングできる(デフォルトの色分けに加えて)
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  pch = "by",
  cex = "by"
)

# 重なり合う点にはアルファ(透明度)を追加できる
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  pch = 16,
  cex = 2,
  alpha = 0.3
)

# 共通の単色背景を持つ塗りつぶし点を得るには、適切なプロット記号
# (21〜25)を使用し、特別な `bg`/`fill` 引数と組み合わせる。
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  # 塗りつぶし円を使用
  pch = 21,
  cex = 2,
  # [0,1]の数値を指定すると、透明度付きのグループ背景色になる
  bg = 0.3,
  # デフォルトの色マッピングを上書きし、すべての点の枠線を黒にする
  col = "black"
)

# 補足:「バブル」プロットにするには、`cex` 引数に適切なベクトルを渡す。
# データの追加の次元(ここでは風速 Wind)を表現するのに便利。
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  pch = 21,
  # 文字サイズをデータの別の特徴量にマッピング
  cex = aq$Wind,
  bg = 0.3,
  col = "black"
)

# グループ化された折れ線プロットに変換するには、`type` 引数を調整するだけでよい。
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  type = "l"
)

# 他のプロット種別も同様に指定できる。tinyplotが直接提供する
# 密度プロットやその他の組み込みプロット種類(リボン、ポイントレンジなど)も含む。
tinyplot(
  ~ Temp | Month,
  data = aq,
  type = "density",
  fill = "by"
)

# facet(パネル分割)プロットもサポートされている。facet単独でも描画可能...
tinyplot(
  Temp ~ Day,
  facet = ~Month,
  data = aq,
  type = "area",
  main = "Temperatures by month"
)

# by(色)グループ化と組み合わせる/対比させることもできる。
aq = transform(aq, Summer = Month %in% c("Jun", "Jul", "Aug"))
tinyplot(
  Temp ~ Day | Summer,
  facet = ~Month,
  data = aq,
  type = "area",
  palette = "dark2",
  main = "Temperatures by month and season"
)

# facet.args補助引数に `nrow` や `ncol` を渡すことで、デフォルトの
# 正方形ウィンドウ配置を上書きできる。プロット枠をオフにすることで、
# facet間の軸ラベルの重複も減らせることに注目。
tinyplot(
  Temp ~ Day | Summer,
  facet = ~Month, facet.args = list(nrow = 1),
  data = aq,
  type = "area",
  palette = "dark2",
  frame = FALSE,
  main = "Temperatures by month and season"
)

# 両側formulaを使うと、facetウィンドウを固定グリッドに配置できる。
# 左辺(LHS) → facetの行、右辺(RHS) → facetの列
aq$hot = ifelse(aq$Temp >= 75, "hot", "cold")
aq$windy = ifelse(aq$Wind >= 15, "windy", "calm")
tinyplot(
  Temp ~ Day,
  facet = windy ~ hot,
  data = aq
)

# 各facetに共通の要素を追加するには `draw` 引数を使用する
tinyplot(
  Temp ~ Day,
  facet = windy ~ hot,
  data = aq,
  draw = abline(h = 75, lty = 2, col = "hotpink")
)

# 自動凡例の位置や見た目は適切な引数でカスタマイズできる。
# 以下の `legend` 位置引数の末尾にある "!" で、`tinyplot` に対して凡例をプロット領域の「外側」に配置するよう指示する。
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  type = "l",
  legend = legend("bottom!", title = "Month of the year", bty = "o")
)

# legend = "direct" を使うと、各グループのデータの最後の点に
# テキストラベルを(対応する色で)配置できる。x軸でソートされた
# 折れ線プロットに最適で、「最後」は「最も右」に対応する。
# 右余白は自動的に拡張されラベルが収まるようになる。
# 全体の余白を詰めたい場合は動的テーマとの組み合わせが相性が良い。
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  type = "l",
  legend = "direct",
  theme = "clean2"
)

# `nudge_x/y` を使うとラベル位置を手動調整
# `repel` を使うと重なったラベルを自動的に分離できる:
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  type = "l",
  legend = legend("direct", nudge_y = c(May = -1, Jun = 2)),
  # legend = legend("direct", repel = TRUE), # 別の選択肢
  theme = "clean2"
)

# デフォルトのグループ色は、グループ数に応じて "R4" または "Viridis"
# パレットから継承される。ただし `palette.pals()` や `hcl.pals()` に
# 列挙されているすべてのパレットを簡易文字列として指定できるほか、
# ユーザーが有効なパレット生成関数を渡してより細かく制御することも可能
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  type = "l",
  palette = "tableau"
)

# グラフィカルパラメーター(例:`(t)par`経由)を設定してプロットの
# 見た目をカスタマイズすることも可能
tinyplot(
  Temp ~ Day | Month,
  data = aq,
  type = "b",
  alpha = 0.5,
  main = "Daily temperatures by month",
  sub = "Brought to you by tinyplot",
  cap = "Source: Base R airquality dataset",
  theme = "clean2"
)

・コマンド例から出力されるプロットの一部を紹介

ラベルの体裁に便利:tinylabelコマンド

tinylabel()は軸目盛りや凡例のラベル表記を、カンマ区切りや通貨、パーセント表示、対数表示、任意の書式変換関数などに整える補助関数です。

オプション意味初期値
x数値ベクトル
labeller形式設定関数 (例えば format、toupper、abs など) 又は便利な文字列 (“percent”、”comma”、”log”、”dollar”、”euro”、”sterling”) を指定することができますNULL
na.ignore論理値。NA 値を無視するかどうかを指定します。デフォルトは TRUE ですTRUE
na.rm論理値。NA 値を削除するかどうかを指定します。デフォルトは TRUE ですが、na.ignore が FALSE の場合のみ評価されますTRUE
# 数値10000をカンマ区切り表記に変換
tinylabel(x = 1e4, "comma")
#[1] "10,000"
# 上と同じ結果
tinylabel(x = 1e4, ",")
#[1] "10,000"
# こちらは "dollar" 指定
tinylabel(x = 1e4, "$")
#[1] "$10,000"

# tinyplot() 呼び出しからtinylabelを利用する場合
# x/yaxlは軸の目盛りラベルの調整に使用
# legend = list(labeller = ...) は凡例ラベルの調整に使用
s77 = transform(data.frame(state.x77), Illiteracy = Illiteracy / 100)
tinyplot(Life.Exp ~ Income | Illiteracy, data = s77,
         xaxl = '$',
         legend = list(labeller = '%'))

# 対数変換の例(軸のスケーリングと組み合わせ)
tinyplot(x = 10^c(10:0), y = 0:10, type = "b",
         log = "x", xaxl = "log")

# `x/yaxb` と組み合わせて目盛り位置(ブレークポイント)も同時に調整する例
tinyplot(x = 10^c(10:0), y = 0:10, type = "b",
         log = "x", xaxl = "log", xaxb = 10^c(1,3,5,7,9))

## カスタム関数の例
dat = data.frame(
  date = seq(as.Date("2000/1/1"), by = "month", length.out = 12),
  trend = 1:12 + rnorm(12, sd = 1)
)
## 例1:日付のフォーマット
tinyplot(trend ~ date, data = dat,
         xaxl = function(x) format(x, "%b, %Y"))

# 長い文字列を18文字ごとに改行する、base::strwrap の
# 「ベクトル化」バージョンを作成
strwrap18 = function(x) sapply(
  strwrap(x, width = 18, simplify = FALSE),
  paste,
  collapse = "\n"
)

# y軸の目盛りラベルが長いデータセットで動作を確認
dat2 = data.frame(
  x = rep(rnorm(100), 3),
  y = c(
    "tinyplot is a lightweight extension of the base R graphics system.",
    "R is a language for statistical computing.",
    "Data visualization is an essential skill."
  )
)
## 例2:文字列の折り返し
tinyplot(y ~ x, data = dat2, type = "j",
         yaxl = strwrap18,
         # ラベルを水平表示し、余白を動的に調整するためテーマを使用
         theme = "bw")

・コマンド例から出力されるプロットの一部を紹介

tinytheme() の使用例

tinytheme()はtinyplotの配色やフォント、余白といった見た目をテーマとしてまとめて切り替える関数で、一度設定するとリセットするまで以降のプロットにも継続して適用されます。

オプション意味初期値
themeテーマ名を指定する文字列です。動的プロットは * で示されていますc(“default”, “basic”, “dynamic”, “clean”, “clean2”, “bw”, “linedraw”, “classic”, “minimal”, “ipsum”, “ipsum2”, “dark”, “socviz”, “broadsheet”, “nber”, “web”, “ridge”, “ridge2”, “tufte”, “float”, “void”)
registerオプションの文字列です。提供されたテーマが登録され、同時に有効化されますNULL
# 再利用可能なプロット関数
p = function() tinyplot(
  lat ~ long | depth, data = quakes,
  main = "Earthquakes off Fiji",
  sub = "Data courtesy of the Harvard PRIM-H project"
)
p()

# テーマを設定
tinytheme("dark")
p()

# 設定したテーマは持続し、以降のプロットにも適用される
tinyplot(0:10)

# 別のテーマを試す
tinytheme("clean")
p()

# デフォルト設定を上書きしてテーマをカスタマイズ
tinytheme("clean",
          adj.xlab = 1, adj.ylab = 1,
          cex.lab = 0.75, cex.axis = 0.9,
          font.sub = 3,
          gap.axis = 0, gap.lab = 0.5,
          tcl = -0.1)
p()

# 別のカスタムテーマの例(フォントも変更)
tinytheme("bw", font.main = 2, col.axis = "darkcyan", family = "HersheyScript")
p()

# 補足:一部の専用テーマは特定のプロット種別専用
tinytheme("ridge2")
tinyplot(I(cut(lat, 10)) ~ depth, data = quakes, type = "ridge")

# テーマをリセット
tinytheme()
p()

# 一時的なテーマを使う場合は `tinyplot(..., theme = <テーマ>)` を直接指定
tinyplot(0:10, theme = "clean", main = "This theme is ephemeral")
tinyplot(10:0, main = "See, no more theme")

# リストで引数を渡して一時的なテーマをカスタマイズ
tinyplot(0:10, main = "Custom", theme = list("clean", grid.col = "hotpink"))

# テーマ一覧の紹介
## y軸ラベルが長くfacetを含む、やや複雑なプロットを使って
## 動的な余白調整などを確認する

thms = eval(formals(tinytheme)$theme)

for (thm in thms) {
  tinytheme(thm)
  tinyplot(
    I(Sepal.Length*1e4) ~ Petal.Length | Species, facet = "by", data = iris,
    yaxl = ",", 
    main = paste0('tinytheme("', thm, '")'),
    sub = "A subtitle",
    cap = "A caption"
  )
  box("outer", lty = 2)
}

# リセット
tinytheme()

・コマンド例から出力されるプロットの一部を紹介

type_summary() の使用例

type_summary()はグループごとのデータを指定した関数(既定値は平均)で要約し、その結果を折れ線として重ねて描画するためのtype指定用関数です。

オプション意味初期値
fun要約関数を指定します。ave関数と互換性のある関数である必要がありますmean
lines()関数に渡す追加の引数(例:type=”p”、col=”pink”など)
# ひよこの体重の平均値を時間経過で描画
tinyplot(weight ~ Time, data = ChickWeight, type = "summary")

# 注:デフォルトの関数は "mean"(平均)なので、以下も同じ結果になる
# tinyplot(weight ~ Time, data = ChickWeight, type = type_summary())
# tinyplot(weight ~ Time, data = ChickWeight, type = type_summary(mean))

# 中央値を描画する場合
tinyplot(weight ~ Time, data = ChickWeight, type = type_summary(median))

# グループ化やfacetとの組み合わせも可能
tinyplot(weight ~ Time | Diet, facet = "by", data = ChickWeight, type = "summary")

# カスタム関数を使う例
tinyplot(
  weight ~ Time | Diet,
  facet = "by", data = ChickWeight,
  type = type_summary(function(y) quantile(y, probs = 0.9) / max(y))
)

type_glm() の使用例

type_glm()は一般化線形モデル(GLM)をデータに当てはめ、その予測曲線と信頼区間をプロットに重ねて描画するためのtype指定用関数です。

オプション意味初期値
familyエラー分布とリンク関数を指定します。glm()に渡され、family関数名(文字列)、family関数そのもの、またはfamily関数呼び出しの結果を指定できます“gaussian”
se論理値。信頼区間を描画するかどうかを指定しますTRUE
level信頼水準を指定します0.95
type文字列(部分マッチ可)。当てはめ済みモデルオブジェクトから抽出する予測値の種類を指定します“response”
weightsモデル当てはめに使う観測値の重みを指定するオプションの数値ベクトル。tinyplot()のトップレベル引数weightsからも指定可能(両方指定した場合はトップレベル引数が優先)NULL
# "glm" という文字列で簡易指定する方法
tinyplot(am ~ mpg, data = mtcars, type = "glm")

# `type_glm()` を使って追加の引数を渡しカスタマイズする方法
tinyplot(am ~ mpg, data = mtcars, type = type_glm(family = "binomial"))

type_lm() の使用例

type_lm()は線形回帰モデル(lm)をデータに当てはめ、その回帰直線と信頼区間をプロットに重ねて描画するためのtype指定用関数です。

オプション意味初期値
se論理値。信頼区間を描画するかどうかを指定しますTRUE
level信頼水準を指定します0.95
weightsモデル当てはめに使う観測値の重みを指定するオプションの数値ベクトル。tinyplot()のトップレベル引数weightsからも指定可能(両方指定した場合はトップレベル引数が優先)NULL
# "lm" という文字列で簡易指定する方法
tinyplot(Sepal.Width ~ Petal.Width, data = iris, type = "lm")

# グループごとにモデルを当てはめる例(シンプソンのパラドックスの例)
tinyplot(Sepal.Width ~ Petal.Width | Species, data = iris, type = "lm")
tinyplot_add(type = "p")

# `type_lm()` を使って追加の引数を渡しカスタマイズする方法
tinyplot(Sepal.Width ~ Petal.Width, data = iris, type = type_lm(level = 0.8))

# 重み付き回帰の例
# トップレベルの引数として指定する方法(formulaメソッドでは
# 非標準評価がサポートされる)...
s77 = as.data.frame(state.x77)
tinyplot(`Life Exp` ~ Income, data = s77, type = "lm", weights = Population)

# type constructorで直接指定する方法(評価済みのベクトルが必要)
tinyplot(`Life Exp` ~ Income, data = s77,
         type = type_lm(weights = s77$Population))

draw_legend() の使用例

draw_legend()はtinyplotの凡例部分だけを単独で描画・配置するための低レベル関数で、通常のbaseプロットに凡例を追加したり、凡例の余白や配置を細かく制御したりする際に使用します。

オプション意味初期値
legend凡例の配置方法を指定するNULL
legend_args凡例に渡す追加の引数NULL
by_depグループ化変数名(deparseされた”by”変数名)を指定するNULL
lgnd_labs凡例のラベルを指定するNULL
labellerラベルの形式を指定する文字列または関数。tinylabel()に渡されるNULL
typeプロットの種類を指定するNULL
pchプロットの記号を指定するNULL
ltyプロットの線種を指定するNULL
lwd線の太さを指定NULL
col色を指定NULL
bg背景色を指定NULL
cex文字の拡大率を指定NULL
gradient連続グラデーションを使用するかどうかを指定FALSE
lmar凡例の内側・外側の余白(行数)を c(inner, outer) の形式で指定。未指定の場合はtpar(“lmar”)(デフォルトc(1.0, 0.1))を使用NULL
has_sub凡例にサブキャプションがあるかどうかを指定FALSE
has_cap凡例にキャプションがあるかどうかを指定FALSE
cap_text凡例の下に表示するテキストを指定NULL
new_plot新しいプロットを作成するかどうかを指定TRUE
draw偽の場合、凡例は描かれないがサイズは返されるTRUE
soma_target数値。複数の凡例の揃えターゲット(行)を指定するNULL
dynmar_title_mar数値またはNULL。動的マージン(dynmar)テーマの「top!」凡例で、事前計算されたdynmar_computed[3]の値を設定するNULL
# プロットエリアを調整
oldmar = par("mar")

# プロット
draw_legend(
  # デフォルト(他に "left(!)"、"bottom(!)" などの指定も可能)
  legend = "right!",
  legend_args = list(title = "Key", bty = "o"),
  lgnd_labs = c("foo", "bar"),
  type = "p",
  pch = 21:22,
  col = 1:2
)

# 凡例は外側の余白に配置される...
box("figure", col = "cyan", lty = 4)
# ...そしてプロットはこの余白の端に合わせて比例的に調整される
box("plot")
# 通常どおり、標準的なプロット要素を追加できる
plot.window(xlim = c(1,10), ylim = c(1,10))
points(1:10)
points(10:1, pch = 22, col = "red")
axis(1); axis(2)
# など

# 重要:draw_legendの副作用として内側の余白が調整される
# (ここでは上で "right!" を指定したため右側の余白)
par("mar")

# リセットするには `dev.off()` を呼ぶか、手動でリセットする
par(mar = oldmar)

# 凡例自体の内側・外側の余白は `lmar` 引数で指定できる
# (`tpar(lmar = c(inner, outer))` でグローバルに設定することも可能)
draw_legend(
  legend_args = list(title = "Key", bty = "o"),
  lgnd_labs = c("foo", "bar"),
  type = "p",
  pch = 21:22,
  col = 1:2,
  # 内側の余白をゼロに設定
  lmar = c(0, 0.1)
)
box("figure", col = "cyan", lty = 4)

par(mar = oldmar)

# 連続的な(グラデーション)凡例もサポートされている
draw_legend(
  legend = "right!",
  legend_args = list(title = "Key"),
  lgnd_labs = LETTERS[1:5],
  col = hcl.colors(5),
  # グラデーション凡例を有効化
  gradient = TRUE
)

par(mar = oldmar)

get_saved_par() の使用例

get_saved_par()は直前のtinyplot()呼び出しの前後で保存されたグラフィックパラメータ(par)を取得する関数で、凡例などによって自動調整された余白を、後から要素を追加する際に正しく再現・復元するために使用します。

オプション意味初期値
when文字列。直前のtinyplot呼び出しの「before」(呼び出し前)か「after」(呼び出し後)のいずれかの時点で保存されたパラメーターを取得します。実質的な既定値は「before」ですc(“before”, “after”, “first”)
#
# 凡例付きのグループ化散布図を描画し、各グループの回帰直線を
# 手動で追加する例
#

# まずグループ化散布図を描画
tinyplot(Sepal.Length ~ Petal.Length | Species, iris)

# 調整済みのparを保持しておくと、後から要素を追加しやすい
for (s in levels(iris$Species)) {
  abline(
    lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s),
    col = which(levels(iris$Species)==s)
  )
}

# 直前のtinyplot呼び出し前の保存されたparを取得(まだ使用しない)
sp = get_saved_par("before")

# 変更された余白は通常のプロットにも影響するため、望ましくない場合がある
plot(1:10)

# 元のパラメーターにリセット(ここでは `par(sp)` も使用可能)
tpar(sp)
# 右余白を修正したシンプルなプロットを再描画
plot(1:10)

# 逆のパターンの例:restore.par = TRUE で「修正」する場合...
tinyplot(Sepal.Length ~ Petal.Length | Species, iris, restore.par = TRUE)

# parがずれているため、追加した回帰直線は誤った位置に描画される
for (s in levels(iris$Species)) {
  abline(
    lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s),
    col = which(levels(iris$Species)==s), lty = 2
  )
}
# 直前のtinyplot呼び出しの「終了後」のpar設定を取得して修正
tpar(get_saved_par("after"))
# これで回帰直線が正しい位置に描画される
for (s in levels(iris$Species)) {
  abline(
    lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s),
    col = which(levels(iris$Species)==s)
  )
}

# 終了前に、元の保存済みparに再度リセット
tpar(sp)


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

スポンサーリンク