ト部蛸焼のブログ

日頃知ったことをアウトプットするためのブログ

LaTeX文書で文字列をハイライト&真下にキャプションしてみたい

この記事が目指す出力

f:id:tobetakoyaki:20200724005047p:plain

導入

先日,スライド発表の機会があり,内容と無関係な「どう魅せるか*1」という点に心血を注いでいました.その過程で,Beamerや通常のドキュメントで特定の文章にハイライトを施すという方法を発見しました.今回の記事ではこれについて紹介するとともに,更なる微調整の方策についても紹介します.


先行研究

↓この記事の「先行研究」*2 に位置づけられる文献はこちらです.↓
www.opt.mist.i.u-tokyo.ac.jp

具体的にはこの中のhighlightマクロが対象です*3.このコマンドをxparseパッケージを想定したコマンドに成形し直すと以下のようになります*4

\NewDocumentCommand{\highlight}{O{red}m}{%
  \tikz[baseline=(x.base)]{%
    \node[rectangle,rounded corners,fill=#1!10](x){#2};%
  }%
}%
\NewDocumentCommand{\highlightcap}{O{red}mm}{%
  \tikz[baseline=(x.base)]{%
    \node[rectangle,rounded corners,fill=#1!10](x){#2}%
    node[below of=x, color=#1]{#3};%
  }%
}

ちなみに1つ目の引数がオプション引数になっており,例えばそれをblueに設定すれば着色を青色に変更できる優れものです (図1).

f:id:tobetakoyaki:20200723235913p:plain
図1. highlightマクロ(1): こんな感じの出力が得られるようになる

スライドで「軽くこの部分を説明したい」というときに使えそうなコマンドではないでしょうか.ここで,このコマンドをもう少し使いやすい形に変えることを考えます.
具体的には,以下の2点を改良します.

  • 2つのコマンドを1つのコマンドに統一する
  • キャプションと文字列の距離を調整する

2点目の必要性を説明します.
先ほどのhighlightマクロ(1)の問題点として,1行分の高さの文字列にハイライトを付けようとすると,キャプションと文字列との間に微妙な空隙が生じます (図2).

f:id:tobetakoyaki:20200724000203p:plain
図2. highlightマクロ(2): キャプションと文字列との間に微妙な空隙が入っている

これは如何せん見栄えが悪いので,この空隙を無くす試みをします.


コマンドの統一化

これは過去の私の記事の「\NewDocumentCommandによる自由な引数設定」の中で利用した「\IfValueT」と同様のコマンド「\IfValueTF」を使うことで解決します.こんなふうに.

\NewDocumentCommand{\highlight}{O{red}mo}{%
  \tikz[baseline=(x.base)]{%
    \IfValueTF{#3}{% True 
      \node[rectangle, rounded corners, fill=#1!10](x){#2}%
       node[below of=x, color=#1]{#3};%
    }{% False 
      \node[rectangle, rounded corners, fill=#1!10](x){#2};%
    }%
  }%
}%

3番目の引数 (=キャプション) が設定されたか否かで,設定されていたら「% True」以下の処理を,そうでなければ「% False」以下の処理を行います.


below ofとbelow

続いて,キャプションと文字列との間の空隙を無くしましょう.
ポイントは「highlightマクロ(2)」までのコマンドでキャプションの挿入位置を指定していた「below of=x」という部分にあります.これは,「直上で定義した "x" という名前のノードの下に新たにノードを設定しなさい」という意味になり,具体的にどのくらい下に設定するかを記入していません.したがって,その相対的な距離を指定すればすべてが解決します.

ただ今回はそれだけで終わりにするのではなく「below of」の代わりに*5「below」によって位置を指定してみましょう.

TikZ でノードを相対位置で配置する話 - マクロツイーターでも解説されているように,ノードが高さをもつときには,「below of」ではその中央を起点に,「below」ではその下端を起点として距離を勘定します.なぜ今回「below」を採用したかといえば,註5に記した理由のほかにも,「below」の下端を起点とする相対距離の指定法が今回は適しているからです.

さて,これを踏まえてキャプションと文字列の間の距離を「below」によって指定したマクロが次のマクロです.注意として,「below」の利用には「\usetikzlibrary{positioning}」の呼び出しが不可欠です.

\usetikzlibrary{positioning}
%% 中略 %%
\NewDocumentCommand{\highlight}{O{red}mo}{%
  \tikz[baseline=(x.base)]{%
    \IfValueTF{#3}{% True 
      \node[rectangle, rounded corners, fill=#1!10](x){#2}%
       node[below=0em of x, color=#1]{#3};%
    }{% False 
      \node[rectangle, rounded corners, fill=#1!10](x){#2};%
    }%
  }%
}%

highlightマクロ(3)を使って図2と同じ内容を出力すると,図3のようになります.

f:id:tobetakoyaki:20200724005047p:plain
図3. highlightマクロ(3): キャプションと文字列との間の空隙を除去できた

キャプションと文字列との間の空隙を取り去ることができ,見栄えが良くなりました.これで終わりです.


参考文献

1. TikZ — Tasuku Soma's webpage
2. \NewDocumentCommandによる自由な引数設定 - ト部蛸焼のブログ
3. TikZ でノードを相対位置で配置する話 - マクロツイーター


付録. 図3.の出力のコード

\DeclareMathOperator{\Enc}{Enc}%
\NewDocumentCommand{\innerproduct}{mm}{%
  \left\langle #1, #2 \right\rangle%
}%
\begin{mdframed}[roundcorner=10pt,frametitle={highlightマクロ(3)},frametitlerule=true]%
  \centering%
  $\innerproduct{\bm{v}, \Enc \left( \bm{e}_{k} \right)} = \displaystyle \bigoplus_{i=0}^{4} v[i] \otimes \Enc \left( \delta_{i, k} \right) % ここまで前座
  \highlight{%
    $=\Enc (v[k])$%
  }[%
    準同型性%
  ]$\par%
\end{mdframed}%

*1:「見せるか」ではなく「魅せるか」であることが重要.本当は良くない行為であることが知られています.

*2:鍵括弧を付したのは,「ブログに先行研究ってなんだよ」と思ったためです.

*3:この文献自体はTikZの基本的知識を説明するいい文献ですので,TikZに興味がある方は一読して損はないと思います.特に,highlightマクロの下にある「ふきだしを作る」という部分は非常に利用価値のあるマクロだと思いますので,是非試してみてください.

*4:画面での表示のために文字列のデフォルトの色を「yellow」から「red」に変えてあります.

*5:「今回は」という書き方をしましたが,今後は一貫して「below of」ではなく「below」を使うことが推奨されているようです[3].また,(x.south)などと指定すれば「below of」を用いても以下に述べるような「下端を起点とした相対距離の設定」は可能です.