PlantUMLのテーブルを極める

# はじめに

かつて Qiita の markdown でテーブル（表）を記載すると偶数行・奇数行に応じて自動的に色分けが行われていた。便利といえば便利だが，これを回避したいときもあるので下記の記事を投稿したこともある。

https://qiita.com/TETSURO1999/items/df1e3a9d9e5abbe414da

:::note warn

しかし，現在は Qiita の仕様が変わって色分けは行われないようになった。これも便利といえば便利だが，今度は色分けをしたい場合に困るようになった。


2024年5月28日現在，色分けが復活したようです。本記事は Qiita の仕様変更（バグ？）に右往左往されたくない方がお読み下さい。
:::

# じゃあどうするの？

結論を先に書くと（すでに記事のタイトルでネタばれしているが）PlantUMLの機能を使う。

# markdown によるテーブル

まずは比較対象となるべきサンプルを示そう。

|暦法|選者|実施期間|
|:--|:--|:--|
|開皇暦|張賓|594～596年(13年間)|
|皇極暦|劉焯|未実施|
|大業暦|張冑玄|597～618年(22年間)|
|戊寅暦|傅仁均|619～664年(46年間)|
|麟徳暦|李淳風|665～728年(64年間)|
|大衍暦|僧一行|729～761年(33年間)|
|五紀暦|郭獻之|762～783年(22年間)|
|正元暦|徐承嗣、楊景風|784～806年(23年間)|
|観象暦|徐昻|807～821年(15年間)|
|宣明暦|徐昻|822～892年(71年間)|
|崇玄暦|辺岡|893～938年(46年間)|

markdown の記述はこんな感じになる。

```markdown:markdown によるテーブル
|暦法|選者|実施期間|
|:--|:--|:--|
|開皇暦|張賓|594～596年(13年間)|
|皇極暦|劉焯|未実施|
|大業暦|張冑玄|597～618年(22年間)|
|戊寅暦|傅仁均|619～664年(46年間)|
|麟徳暦|李淳風|665～728年(64年間)|
|大衍暦|僧一行|729～761年(33年間)|
|五紀暦|郭獻之|762～783年(22年間)|
|正元暦|徐承嗣、楊景風|784～806年(23年間)|
|観象暦|徐昻|807～821年(15年間)|
|宣明暦|徐昻|822～892年(71年間)|
|崇玄暦|辺岡|893～938年(46年間)|
```

二行目で左寄せ，中央揃い，右寄せなどの水平位置を指定する。

# HTML タグによるテーブル

Qiita の markdown では HTML タグを直接記入するテーブル記法も許可されている。

<table>
<caption>表１　隋唐時代の暦法一覧</caption>
<thead>
<tr><th>暦法</th><th>選者</th><th>実施期間</th></tr>
</thead>
<tbody>
<tr><td>開皇暦</td><td>張賓</td><td>594～596年(13年間)</td></tr>
<tr><td>皇極暦</td><td>劉焯</td><td>未実施</td></tr>
<tr><td>大業暦</td><td>張冑玄</td><td>597～618年(22年間)</td></tr>
<tr><td>戊寅暦</td><td>傅仁均</td><td>619～664年(46年間)</td></tr>
<tr><td>麟徳暦</td><td>李淳風</td><td>665～728年(64年間)</td></tr>
<tr><td>大衍暦</td><td>僧一行</td><td>729～761年(33年間)</td></tr>
<tr><td>五紀暦</td><td>郭獻之</td><td>762～783年(22年間)</td></tr>
<tr><td>正元暦</td><td>徐承嗣、楊景風</td><td>784～806年(23年間)</td></tr>
<tr><td>観象暦</td><td>徐昻</td><td>807～821年(15年間)</td></tr>
<tr><td>宣明暦</td><td>徐昻</td><td>822～892年(71年間)</td></tr>
<tr><td>崇玄暦</td><td>辺岡</td><td>893～938年(46年間)</td></tr>
</tbody>
</table>

HTML の記述は以下のようになる。

```html:HTMLによるテーブル
<table>
<caption>表１　隋唐時代の暦法一覧</caption>
<thead>
<tr><th>暦法</th><th>選者</th><th>実施期間</th></tr>
</thead>
<tbody>
<tr><td>開皇暦</td><td>張賓</td><td>594～596年(13年間)</td></tr>
<tr><td>皇極暦</td><td>劉焯</td><td>未実施</td></tr>
<tr><td>大業暦</td><td>張冑玄</td><td>597～618年(22年間)</td></tr>
<tr><td>戊寅暦</td><td>傅仁均</td><td>619～664年(46年間)</td></tr>
<tr><td>麟徳暦</td><td>李淳風</td><td>665～728年(64年間)</td></tr>
<tr><td>大衍暦</td><td>僧一行</td><td>729～761年(33年間)</td></tr>
<tr><td>五紀暦</td><td>郭獻之</td><td>762～783年(22年間)</td></tr>
<tr><td>正元暦</td><td>徐承嗣、楊景風</td><td>784～806年(23年間)</td></tr>
<tr><td>観象暦</td><td>徐昻</td><td>807～821年(15年間)</td></tr>
<tr><td>宣明暦</td><td>徐昻</td><td>822～892年(71年間)</td></tr>
<tr><td>崇玄暦</td><td>辺岡</td><td>893～938年(46年間)</td></tr>
</tbody>
</table>
```

大きな特徴としては下記の通り。
- テーブルのタイトルを付けられる。`<caption>...</caption>` タグを使う。
- セルを結合できる。`colspan` および `rowspan` オプションを使用できる。
- セルごとに左右方向位置を指定できる。`style="text-align:..."` を指定できる。
- テーブルの中にテーブルを置ける。

# PlantUML によるテーブル

上記のサンプルに限りなく寄せたのが下記のテーブルである。

```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontSize: 17;
  fontStyle: normal;
}
</style>
skinparam padding 12
title
表１　隋唐時代の暦法一覧
<#FFFFFF,#CCCCCC>|=暦法|=選者|=実施期間|
|開皇暦|張賓|594～596年(13年間)|
|皇極暦|劉焯|未実施|
|大業暦|張冑玄|597～618年(22年間)|
|戊寅暦|傅仁均|619～664年(46年間)|
|麟徳暦|李淳風|665～728年(64年間)|
|大衍暦|僧一行|729～761年(33年間)|
|五紀暦|郭獻之|762～783年(22年間)|
|正元暦|徐承嗣、楊景風|784～806年(23年間)|
|観象暦|徐昻|807～821年(15年間)|
|宣明暦|徐昻|822～892年(71年間)|
|崇玄暦|辺岡|893～938年(46年間)|
end title
@enduml
```

PlantUML の記述は下記のようになる。

````markdown:PlantUML によるテーブル
```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontSize: 17;
  fontStyle: normal;
}
</style>
skinparam padding 12
title
表１　隋唐時代の暦法一覧
<#FFFFFF,#CCCCCC>|=暦法|=選者|=実施期間|
|開皇暦|張賓|594～596年(13年間)|
|皇極暦|劉焯|未実施|
|大業暦|張冑玄|597～618年(22年間)|
|戊寅暦|傅仁均|619～664年(46年間)|
|麟徳暦|李淳風|665～728年(64年間)|
|大衍暦|僧一行|729～761年(33年間)|
|五紀暦|郭獻之|762～783年(22年間)|
|正元暦|徐承嗣、楊景風|784～806年(23年間)|
|観象暦|徐昻|807～821年(15年間)|
|宣明暦|徐昻|822～892年(71年間)|
|崇玄暦|辺岡|893～938年(46年間)|
end title
@enduml
```
````

大きな特徴としては下記の通り。
- PlantUML 全体が「図」として挿入されるのでテーブルの外側に枠線ができてしまう。またテーブルの中のテキストをコピーできない。
- テーブル本体の前にずらずらとスタイルシートを記載できる。面倒といえば面倒だが，逆に豊富な表現力の源でもある。
- 先頭行がヘッダとは限らない。先頭文字を等号(=)にするとヘッダ扱い（太字）になる。
- 水平位置の指定がないというか水平位置を指定出来ない。
- テーブルの先頭行の左端にある色指定 `<#FFFFFF,#CCCCCC>` は先頭行の背景色とテーブル全体の境界線の色を意味する。

# PlantUML 応用編その１

偶数行と奇数行を塗り分ける例を示す。

```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontSize: 17;
  fontStyle: normal;
}
</style>
skinparam padding 12
title
表１　隋唐時代の暦法一覧
<#FFFFFF,#CCCCCC>|=暦法|=選者|=実施期間|
<#EEEEEE>|開皇暦|張賓|594～596年(13年間)|
|皇極暦|劉焯|未実施|
<#EEEEEE>|大業暦|張冑玄|597～618年(22年間)|
|戊寅暦|傅仁均|619～664年(46年間)|
<#EEEEEE>|麟徳暦|李淳風|665～728年(64年間)|
|大衍暦|僧一行|729～761年(33年間)|
<#EEEEEE>|五紀暦|郭獻之|762～783年(22年間)|
|正元暦|徐承嗣、楊景風|784～806年(23年間)|
<#EEEEEE>|観象暦|徐昻|807～821年(15年間)|
|宣明暦|徐昻|822～892年(71年間)|
<#EEEEEE>|崇玄暦|辺岡|893～938年(46年間)|
end title
@enduml
```

二行目以降，左端の色指定 `<#EEEEEE>` はその行内の背景色の指定になる。

````markdown
```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontSize: 17;
  fontStyle: normal;
}
</style>
skinparam padding 12
title
表１　隋唐時代の暦法一覧
<#FFFFFF,#CCCCCC>|=暦法|=選者|=実施期間|
<#EEEEEE>|開皇暦|張賓|594～596年(13年間)|
|皇極暦|劉焯|未実施|
<#EEEEEE>|大業暦|張冑玄|597～618年(22年間)|
|戊寅暦|傅仁均|619～664年(46年間)|
<#EEEEEE>|麟徳暦|李淳風|665～728年(64年間)|
|大衍暦|僧一行|729～761年(33年間)|
<#EEEEEE>|五紀暦|郭獻之|762～783年(22年間)|
|正元暦|徐承嗣、楊景風|784～806年(23年間)|
<#EEEEEE>|観象暦|徐昻|807～821年(15年間)|
|宣明暦|徐昻|822～892年(71年間)|
<#EEEEEE>|崇玄暦|辺岡|893～938年(46年間)|
end title
@enduml
```
````

# PlantUML 応用編その２

特定のセルだけ色をつけることもできる。

```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontSize: 17;
  fontStyle: normal;
}
</style>
skinparam padding 12
title
表１　隋唐時代の暦法一覧
<#FFFFFF,#CCCCCC>|=暦法|=選者|=実施期間|
|開皇暦|張賓|594～596年(13年間)|
|皇極暦|劉焯|未実施|
|大業暦|張冑玄|597～618年(22年間)|
|戊寅暦|傅仁均|619～664年(46年間)|
|麟徳暦|<#FFFF00>李淳風|665～728年(64年間)|
|大衍暦|僧一行|729～761年(33年間)|
|五紀暦|郭獻之|762～783年(22年間)|
|正元暦|徐承嗣、楊景風|784～806年(23年間)|
|観象暦|徐昻|807～821年(15年間)|
|宣明暦|徐昻|822～892年(71年間)|
|崇玄暦|辺岡|893～938年(46年間)|
end title
@enduml
```

セル内で色指定 `<#FFFF00>` すると当該セル内の背景色の指定になる。

````markdown
```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontSize: 17;
  fontStyle: normal;
}
</style>
skinparam padding 12
title
表１　隋唐時代の暦法一覧
<#FFFFFF,#CCCCCC>|=暦法|=選者|=実施期間|
|開皇暦|張賓|594～596年(13年間)|
|皇極暦|劉焯|未実施|
|大業暦|張冑玄|597～618年(22年間)|
|戊寅暦|傅仁均|619～664年(46年間)|
|麟徳暦|<#FFFF00>李淳風|665～728年(64年間)|
|大衍暦|僧一行|729～761年(33年間)|
|五紀暦|郭獻之|762～783年(22年間)|
|正元暦|徐承嗣、楊景風|784～806年(23年間)|
|観象暦|徐昻|807～821年(15年間)|
|宣明暦|徐昻|822～892年(71年間)|
|崇玄暦|辺岡|893～938年(46年間)|
end title
@enduml
```
````

# まとめ

以上，三つのテーブル記法の機能を比較すると以下のようになる。

<table>
<caption>テーブル記法の機能比較</caption>
<thead>
<tr><th style="text-align:center">機能</th>
    <th style="text-align:center">markdown</th>
    <th style="text-align:center">HTML</th>
    <th style="text-align:center">PlantUML</th></tr>
</thead>
<tbody>
<tr><td>タイトル文字列</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">○</td>
    <td style="text-align:center">○</td></tr>
<tr><td>ヘッダ指定</td>
    <td style="text-align:center">先頭行のみ</td>
    <td style="text-align:center">セル単位に指定可</td>
    <td style="text-align:center">セル単位に指定可</td></tr>
<tr><td>左右位置</td>
    <td style="text-align:center">列単位に指定可</td>
    <td style="text-align:center">セル単位に指定可</td>
    <td style="text-align:center">左揃い固定</td></tr>
<tr><td>上下位置</td>
    <td style="text-align:center">中央揃い固定</td>
    <td style="text-align:center">中央揃い固定</td>
    <td style="text-align:center">上揃い固定</td></tr>
<tr><td>枠色指定</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">○</td></tr>
<tr><td>背景色指定</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">テーブル・行・<br>セル単位で可能</td></tr>
<tr><td>セル内改行</td>
    <td style="text-align:center"><code>&lt;br&gt;</code></td>
    <td style="text-align:center"><code>&lt;br&gt;</code></td>
    <td style="text-align:center"><code>\n</code></td></tr>
<tr><td>セル内余白指定</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center"><code>skinparam padding</code></td></tr>
<tr><td>文字色指定</td>
    <td style="text-align:center"><code>&lt;font color=xxx&gt;</code></td>
    <td style="text-align:center"><code>&lt;font color=xxx&gt;</code></td>
    <td style="text-align:center"><code>&lt;color:xxx&gt;</code></td></tr>
<tr><td>文字サイズ指定</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center"><code>&lt;size:n&gt;</code></td></tr>
<tr><td>フォント指定</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center"><code>&lt;font:xxx&gt;</code></td></tr>
<tr><td>背景色指定</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center"><code>&lt;back:xxx&gt;</code></td></tr>
<tr><td>セル内コード</td>
    <td style="text-align:center"><code>`...`</code> <code>&lt;code&gt;</code></td>
    <td style="text-align:center"><code>&lt;code&gt;</code></td>
    <td style="text-align:center">△（おまけ参照）</td></tr>
<tr><td>セル内数式</td>
    <td style="text-align:center"><code>$...$</code></td>
    <td style="text-align:center"><code>$...$</code></td>
    <td style="text-align:center"><code>&lt;math&gt;</code> <code>&lt;latex&gt;</code></td></tr>
<tr><td>テキストのコピー</td>
    <td style="text-align:center">○</td>
    <td style="text-align:center">○</td>
    <td style="text-align:center">×</td></tr>
<tr><td>テーブルの中の<br>テーブル</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">○</td>
    <td style="text-align:center">×</td></tr>
<tr><td>セルの結合</td>
    <td style="text-align:center">×</td>
    <td style="text-align:center">○</td>
    <td style="text-align:center">×</td></tr>
<tr><td>オーバーフロー時</td>
    <td style="text-align:center">セル内折り返し</td>
    <td style="text-align:center">セル内折り返し</td>
    <td style="text-align:center">テーブル全体を<br>縮小表示</td></tr>
    </tbody>
</table>

# おまけ
セル内コードについては（固定幅）フォント指定と背景色指定ができるので両者の組み合わせでそれっぽく見せることはできる。

```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontSize: 17;
  fontStyle: normal;
}
</style>
skinparam padding 12
title
PlantUML で無理やりコードスパンっぽく見せる方法
<#FFFFFF,#CCCCCC>|=機能|=markdown|=HTML|=PlantUML|
|セル内改行|<back:#EEEEEE><font:monospaced><size:15>~<br></size></font></back>|<back:#EEEEEE><font:monospaced><size:15>~<br></size></font></back>|<back:#EEEEEE><font:monospaced><size:15>\\n</size></font></back>|
|セル内余白指定|×|×|<back:#EEEEEE><font:monospaced><size:15>skinparam padding</size></font></back>|
|文字色指定|<back:#EEEEEE><font:monospaced><size:15>~<font color=xxx></size></font></back>|<back:#EEEEEE><font:monospaced><size:15>~<font color=xxx></size></font></back>|<back:#EEEEEE><font:monospaced><size:15>~<color:xxx></size></font></back>|
end title
@enduml
```

小なり記号 `<` を入力するためには直前にチルダ `~` を入れれば良いようだ。大なり記号 `>` の前には必要ないので文字列 `<...>` 全体をタグと認識させないためのエスケープ記号というべきだろうか。

一方，改行コード `\n` を入力するためにはバックスラッシュ `\` を重ね打ちする。ちなみに縦棒 `|` を入力するときにもバックスラッシュ `\` を入れる。このあたりの記法（ルール）は洗練されてない感じがする。 

````markdown
```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontSize: 17;
  fontStyle: normal;
}
</style>
skinparam padding 12
title
PlantUML で無理やりコードスパンっぽく見せる方法
<#FFFFFF,#CCCCCC>|=機能|=markdown|=HTML|=PlantUML|
|セル内改行|<back:#EEEEEE><font:monospaced><size:15>~<br></size></font></back>|<back:#EEEEEE><font:monospaced><size:15>~<br></size></font></back>|<back:#EEEEEE><font:monospaced><size:15>\\n</size></font></back>|
|セル内余白指定|×|×|<back:#EEEEEE><font:monospaced><size:15>skinparam padding</size></font></back>|
|文字色指定|<back:#EEEEEE><font:monospaced><size:15>~<font color=xxx></size></font></back>|<back:#EEEEEE><font:monospaced><size:15>~<font color=xxx></size></font></back>|<back:#EEEEEE><font:monospaced><size:15>~<color:xxx></size></font></back>|
end title
@enduml
```
````

:::note
フォント指定は機種依存性があるので非推奨かもしれない。
そもそも `<font:xxx>` タグは PlantUML の隠し機能っぽい。
　※マニュアルには一応記載されているのを確認した。
:::

# チェス盤を作ってみた

試しにチェス盤を作ってみた。本当は盤面をもう少し正方形に近づけたかったところだ。

```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontStyle: normal;
  fontSize: 32;
}
</style>
skinparam padding 8
title
<#FFFFFF,CCCCCC>|♜|<#EEEEEE>♞|♝|<#EEEEEE>♛|♚|<#EEEEEE>♝|♞|<#EEEEEE>♜|
|<#EEEEEE>♟|♟|<#EEEEEE>♟|♟|<#EEEEEE>♟|♟|<#EEEEEE>♟|♟|
| |<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> |
|<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> | |
| |<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> |
|<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> | |
| |<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> |
|<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> | |<#EEEEEE> | |
|♙|<#EEEEEE>♙|♙|<#EEEEEE>♙|♙|<#EEEEEE>♙|♙|<#EEEEEE>♙|
|<#EEEEEE>♖|♘|<#EEEEEE>♗|♕|<#EEEEEE>♔|♗|<#EEEEEE>♘|♖|
end title
@enduml
```