Typstとは
TypstはポストLaTeXと目される高度な組版言語で、LaTeXに比べて構造を直感的に表現できる文法や、スタイルの再利用性の高さ、処理速度の速さなどが魅力です。Rとの連携については現在のところ、TypstではknitrやRMarkdownのように文書内に直接Rのコードを組み込むことはできませんが、Typstの外部データ読み込み機能とリアルタイムプレビューを活用すれば、RMarkdownよりも連携しやすいかもしれません。
Rとの連携
Rの分析結果をTypst内で用いるには、Rオブジェクトをjson
やyaml
などの形で外部ファイルとして保存しておく必要があります。ここでは、json
形式で保存し、それをTypstで利用する場合について説明します。
まず、Rでjson
形式のファイルを操作するためには、jsonlite
などのパッケージが必要です。
library(jsonlite) ## jsonファイルの読み書き用
そして、Rの分析結果やデータで、Typstで利用したい部分をjson
形式で保存するようにします。分析ごとにjson
ファイルにしてもいいですが、1つのリストにまとめておいた方が扱いやすいと思います。なお、lm
オブジェクトなど複雑な構造を持つオブジェクトの場合は、必要な要素を抜き出してjson
ファイルに変換する必要があります。次の例では、lavaan
による分析結果のうち、パラメータ推定値と適合度指標を取り出してリストにまとめ、それを要約統計量(summary
)と合わせてjson
ファイルに保存しています。
# モデルの推定
fit <- sem(model, data = data, std.lv = TRUE)
# 結果の表示
summary(fit, standardized = TRUE, fit.measures = TRUE)
# パラメータ推定値
params <- parameterEstimates(fit, standardized = TRUE)
# 適合度指標
fitmeasures <- fitMeasures(fit)
# 結果をリストにまとめる
result_list <- list(
summary = summary_table,
parameterEstimates = params,
fitMeasures = as.list(fitmeasures)
)
必要な変数あるいはオブジェクトのjson
ファイルへの書き出し処理は、分析スクリプトの最後に書いておくなどして、スクリプトを修正した場合にそれがjson
ファイルに反映されるようにしておくのがよいでしょう
作成したjson
ファイルは、Typstの文書内で#let 変数名 = json("ファイルパス")
とすることで読み込めます。ここでは、次のようにしてrjson
という名前でjson
ファイルを読み込みました。
#let rjson = json("../data/sem_result.json")
このようにして読み込むと、本文中で#rjson.fitMeasures.at(0)
のようにしてその内容を参照できるようになります。データが名前付きリストで保存されている場合、「.fitMeasures
」のように名前でアクセスできますし、そうでないリストでは「.at(0)
」のように位置でアクセス可能です。このとき、リストの開始位置は1ではなく0である点には注意が必要です。
なお、VS CodeのTinymist Typst
機能拡張を使っている場合、#rjson.
まで入力すると補完候補として要素名が上がってきますし、その時点で#rjson
の中身が即時プレビューで文書中に表示されるので、元のjson
ファイルを開いて確認する必要もありません。
Rデータからの表の作成
Rとの連携の例として、Rで出力した要約統計量を表にしてみます。ここでは、booktabs
とzero
パッケージを使って、心理学系論文スタイルの表にしてみます。
#figure(
caption: [自己効力感、ストレス、課題成績の平均値および標準偏差],
{
set text(size: 9pt)
show: format-table(str, (digits: 2), (digits: 2))
table(
stroke: none,
columns: 3,
align: (left, center, center),
toprule(),
table.header([変数],[平均値],[標準偏差]),
midrule(),
[自己効力感],[#rjson.summary.at(0).Mean],[#rjson.summary.at(0).SD],
[ストレス],[#rjson.summary.at(1).Mean],[#rjson.summary.at(1).SD],
[課題成績],[#rjson.summary.at(2).Mean],[#rjson.summary.at(2).SD],
bottomrule()
)
}
)
今回はシンプルは表1つだけなので、表の要素には#rjson
の値を1つ1つ指定していますが、表の行や列が多い場合は、for
文などを使って効率化するとよいでしょう。
Rで作成した図の利用
表ではなく図を用いたい場合は、ggplot2
で作図したものをSVG形式で保存してTypstに取り込むのがいいと思います。少なくとも私の環境(Mac)では、図に日本語が含まれていても問題なく表示できます。なお、Typstは、標準ではPDFを読み込めませんので注意してください。ggplot2
で作成した図をSVGファイルに保存するには、svglite
というRパッケージを使用します。
Rのコード
# 散布図+回帰直線
p <- ggplot(data, aes(x = SelfEfficacy, y = Performance)) +
geom_point(alpha = 0.6, color = "#0072B2") +
geom_smooth(method = "lm", se = TRUE, color = "#D55E00") +
labs(
x = "自己効力感",
y = "課題成績"
) +
theme_minimal(base_size = 10)
# SVGファイルに保存
ggsave("../figs/selfefficacy_performance.svg",
plot = p, width = 8, height = 6, units = "cm")
Typstのコード
#figure(
image("../figs/selfefficacy_performance.svg"),
caption: [
自己効力感と課題成績の散布図および回帰直線
],
)
Rデータを利用した作図
パス図などを作成したい場合、Rでの作図は思い通りにならず大変なので、LaTeXの場合にはTikZという描画ライブラリを用いてLaTeX内で作成していました。じつをいうとggplot2
の図は個人的にあまり好きではないので、LaTeXで文書を作成する際は、折れ線グラフなどもデータだけ書き出して、PGFPlotsでLaTeX内で作成することも多くありました。そちらの方が細かい調整がきくし、仕上がりも(少なくとも自分にとっては)綺麗だったからです。
Typstには、なんとこのTikZやPGFPlotsに相当するパッケージも用意されています。ここでは、試しにcetz
とfletcher
というパッケージで簡単なパス図を描いてみることにします。
// スクリプトを見やすくするために、前もって係数を変数に代入
#let b_se_st = rjson.parameterEstimates.at(0).est
#let b_st_pf = rjson.parameterEstimates.at(1).est
#let b_se_pf = rjson.parameterEstimates.at(2).est
#figure(
caption: [`cetz`と`fletcher`を用いて作成したパス図],
block[
// 図の中のフォントの設定
#set text(size: 9pt, font: "Source Han Sans JP", weight: 400);
#diagram(
node((0, 0), [自己効力感], stroke: .5pt),
edge(num(digits:2)[#b_se_st], "-|>"),
node((2, -1), [ストレス], stroke: .5pt),
edge(num(digits:2)[#b_st_pf],"-|>"),
node((4, 0), [課題成績], stroke: .5pt),
edge((0,0),(4,0),num(digits:2)[#b_se_pf], "-|>")
)
]
)
この例では、図中のパスに示した係数は、すべてrjson
から値を持ってきています。そのため、後で計算のやり直しが発生したとしても、その際にjson
ファイルがちゃんと更新されるようになっていれば、(モデルが変わらない限り)図を書き直す必要は一切ありません。
ところで、knitrやRMarkdownの場合、文章に修正を加えただけでもRのスクリプトを含めて文書全体をコンパイルしなくてはなりません。Rのコードブロックについてはある程度キャッシュが効くものの、MarkdownやLaTeXは本文のコンパイルにもそれなりの時間がかかるので、それらが積み上がると結構な時間のロスになります。
しかし、このようにjson
(またはyaml
)を介してRとやり取りすると、文章に修正が必要な場合はTypstのファイルを編集すればいいだけで、Rスクリプトの再実行は一切必要ありません。なので、一瞬で修正が終わります。Rスクリプトに修正を加える場合も、Rスクリプトを修正して実行しなおせば、Typst上の表示はリアルタイムで最新のものに更新されていきます。その点もすごく嬉しいところです。
おわりに
今回の説明用に作成したファイル一式は下記のリンク先に置いてあります。