2025年12月13日

Typst: fletcherで図式

Typst Advent Calendar 2025の13日目です.

Typst,その軽さもあり数学なものを簡単に書くのに使ったりしています.で,何書いてもどっかで図式を描きたくなる.LaTeXではtikz-cdを使っていて,論文書く時も大体読み込んでいます.SATySFiならばmatrixcdですね.というわけでTypstではどうするか.commuteというそれっぽい名前のパッケージもありますが,fletcherというtikz-cdに書式が近く見えるパッケージを使ってみました.tikz-cdの例に並べて書いてみます.なお,図式以外にもいろいろとグラフが描けるようですが,ここでは図式のみ考えます.

とりあえず

次で読み込んでおきましょう.

#import "@preview/fletcher:0.5.8" as fletcher: diagram, node, edge

簡単な例です.


#diagram($
  A edge("r", ->, f) edge("rd",->) & B edge("d",->, g) \
  & C
  $)

ディスプレイ数式で使うことが多いでしょう.

$
#diagram($
  A edge("r", "->", f) edge("rd","->") & B edge("d","->", g) \
  & C
  $)
$  

#diagramコマンドで描きます.#diagramの中身も数式に入れておきます.対象(マニュアル内ではvertex)は表のように並べ,横方向の対象の並びは&で分けて,縦方向の区切りは\で行います.edgeコマンドで矢印を引きます.その書式は次の通り.

edge(<対象>, <mark>, <ラベル>, <オプション>)

markというのは矢印の形のようです.上の例でわかるように,矢印の時には->とします.これを渡さないと単なる線になります.ラベルは矢印の上などに出てくるやつです.

#diagram($
  A edge("r", "->", f) & B edge("->", g, label-side: #right) & C edge("->",h,label-side: #center) & C
$)

ラベルの付く方向を変えるにはlabel-sideオプションを指定します.#rightを指定することで矢印に従い右に出ます.#centerとするとど真ん中.二つ目と三つ目のedgeでは行き先の指定を省略しました.「一番近く」に出るようです.なお基本数式モード内ですが,オプション引数は大体コードモード内で有効なものなので,基本的には#でいったんモードを切り替えることになります.

#diagram($
  A edge("r", "hook->") & B edge("hook'->") & C & D edge("l","hook'->")
$)

矢印の形(mark)の指定はこんな感じで文字列で指定するみたいです."hook->"hook""->"の組み合わせで,他のもこういう組み合わせでできるようです.ちなみに単にedge("r",->)でもよかったりするのですがマニュアルのどこに書いてあるのかな.試しにedge("r",arrow.hook)としても上みたいになりました.

#diagram($
  A edge() & B edge("->>") & C edge("=") & D edge("|->") & E edge("-->") & F edge("..>") & G
$)

矢印いろいろ.マニュアル見るともっとあります.

#diagram($
  A edge("rd","->",a, label-angle: #auto) & \
  & B 
$)

label-angleオプションでラベルが傾きます.#autoでよい感じになりますが,#right#left#top#bottomを指定できます.これらは矢印の傾きにあわせてくれますが,90度ずつ違います.なお,#(-15deg)とすると-15度になります.

#diagram($
  A edge("d", "->", shift: #(3mm)) edge("r","->", shift: #(-3mm))  & B \
  C edge("u", "->", shift: #(3mm)) & D edge("lu", "->", shift: #(3mm)) \
  E edge("u", "->", shift: #(3mm,-3mm))
$)

矢印をずらす.2引数与えるのは始点と終点を別方向にずらすことを意味します.


#diagram($
  A edge("r", ->,bend: #30deg) & B edge("l",->,bend: #30deg)
$)

少し迂回する矢印.

#diagram($
  A edge(->,stroke: #(2pt)) & B edge(stroke: #none, label-side: #center,in.rev) & b
  $
)

strokeオプションで矢印の太さが指定できます.#noneとすると消えます.

#diagram($
  A edge(->,f,label-pos: #0.2) & B edge(->,g,label-pos: #0.8) & C
  $)

label-posオプションでラベルの場所を指定できます.0から1までの数を指定します.0が始点の近く.

#diagram($
  A edge(->,bend: #45deg) edge(->,bend: #(-45deg)) & B$,
  edge((0.5,-0.2),(0.5,0.2),"=>",$alpha$)
)

tikz-cdでは矢印についたラベルの場所に名前をつけてその間に矢印をさらに引けましたが,そういう方法は見つけられませんでした.上ではまず数式モードから脱出してから矢印を描いています.数式モードから出ることで,edgeに始点と終点を指定することができるようになります.#diagramでできる図式は左上を(0,0)とした座標空間上に配置されていて,その座標を直接指定して線を引いています.

#diagram($
  A edge("rd",->) & B edge("ld",->, crossing: #true, crossing-thickness: #32)\
  C & D
$)

crossing: trueを指定すると,その周りを(デフォルトでは)白く塗りつぶします.これにより他の矢印が一部白抜きされます.どの程度の幅で塗りつぶすかはcrossing-thicknessオプションで指定できます.塗りつぶすという処理の事情で描画順が大事で,同じオプションをAからDの矢印に適用しても思うように機能しません.この時はDからAに逆向きの矢印をedge("lu", <-, crossing: #true, crossing-thickness: #32)として引けばよいでしょう.

#diagram($
  A edge(->,f) & B edge(->,g,label-sep: #1em) & C
$)

label-sepオプションで,ラベルの矢印からの距離を指定します.負の値を指定すると矢印にめり込んでいきます.

#diagram($
  node(#[$A$],stroke: #1pt) edge(->) & node(#[$B$],stroke: #1pt, shape: #rect)
$)

各対象を装飾するにはnodeでくくります.Aはそれだけ書けばよい気がするのですが何故か寝てくれないのでいったんマークアップモードに入ってから数式に戻しています.nodeにはいろいろオプションがあるのでマニュアルを見てみてください.

埋め込み $#diagram($Z edge("hook->",i) & X$)$ を考える.

インラインでも問題なく使えます.

デバッグ

#diagram(debug: true,$
  A edge(-gt;) & B
$)

#diagramdebug: trueを渡すとデバッグモードに入り,座標などの情報が出ます.値はtrueの他1,2,3の数字も指定できて,だんだんと情報量が増えていくようです.

0 件のコメント:

コメントを投稿

コメントの追加にはサードパーティーCookieの許可が必要です