TeXを利用してネームプレートを作成する方法について(2): 当日のプレート作成

前回からのブリッジ

(意気揚々と文章を書こうと思っていたら,今年のネームプレートで”13th”を”13rd”と書くという凡ミスをしてしまったことが判明して少し凹んでるのですが,書くべきことは書こうということで.)

前回は,TeXを利用してネームプレートの雛形を作るという話をしました. ここでは,当日どのようにしてネームプレートが作成されるかについて説明します. とくに,pythonやrubyなどのスクリプト言語とテンプレートエンジンを利用した「差し込み印刷用スクリプト」について触れていきたいと思います.

ネームプレートの作成方法について

大会前から当日までのネームプレートに関する流れについて簡単に述べましょう.

  • (資材準備会にて)各画用紙に順位面だけを貼り付けておく.名前の面は当日貼り付ける.
  • (ここから当日)マークシートの読取と集計を行う.(ここは私の管轄外で,私は結果のデータをもらうだけです.)
  • 結果のデータを元にして,ネームプレートの名前面の作成を行う.
  • 名前面のpdfをUSBメモリに入れ,コンビニ印刷にて印刷する.
  • できあがった名前面を,(既に順位面だけ貼り付けてある)画用紙に貼り付けて完成.

このうち,3番目の作業がメインになります.前回提示したTeXソースの中では,

\AssignName{<順位>}{<名前>}{<学校>}{<学年>}

という命令で名前面の割付をするのですが, これを60人分手打ちするのはどう考えても時間が足りないわけです. ですから,これを自動化する「差し込み印刷スクリプト」が必要になります.

テンプレートエンジンTenjinを利用した差し込み印刷スクリプト

どういうことがやりたいかと言うと,例えば,

11111,西園寺公望,東京大,大3,1,さいおんじきんもち,140
22222,桂太郎,京都大,大4,2,かつらたろう,139

という感じのcsvファイル(左から,エントリーNo.,名前,学校,学年,順位,名前読み,点数)から,

\AssignName{1}{西園寺公望}{東京大}{大3}
\AssignName{2}{桂太郎}{京都大}{大4}

という感じの内容のTeXソースファイルを生成したいわけです. これをやるためのスクリプトなのですが,今回はテンプレートエンジンの一つであるTenjinを利用しました. Tenjinはいくつかの言語で実装されていて, 今回はpython版(pyTenjin)を利用することとしました.

今回は以下のテンプレートファイルとpythonスクリプトを用意しました.

まずテンプレートファイル(nameplate.pytex)について説明します. このファイルは前回のサンプルをベースにしており, Tenjinのテンプレートとしての本質的な部分は以下の部分に集約されます.

<?py for member in members: ?>
\AssignName{${member['order']}}{${member['name']}}{${member['school']}}{${member['grade']}}
<?py #endfor ?>
\end{document}

pyTenjinでは,${...}<?py ... ?>で囲むことでテンプレート内にpythonのステートメントを導入することができます.(ただし,上のようにfor文を導入する際は,pythonではインデントでブロックを認識するのが基本なので,どこでforブロックが終わるのか識別させるために,<?py #endfor ?>という書き方をします.pyTenjinのマニュアルを参照してください.)

membersは辞書の配列で,そこから一つずつ辞書を取り出して,\AssignNameの引数として挿入していきます.極めて単純明快なものです.

このテンプレートの変数membersにデータをバインドさせて,実際に文書を作るのがinsert.pyになります.一部を抜き出します.

memberlist = []
with open('dat/result.csv','r') as f:
    reader = csv.reader(f)
    for row in reader:
        mem = {
			'order': row[4],
            'name': row[1],
            'school': row[2],
            'grade': row[3],
        }
        memberlist.append(mem)

print(memberlist)

context = {
    'members': memberlist
}

engine = tenjin.Engine(path=['template'])
tex = engine.render('nameplate.pytex',context)

with open('src/nameplate.tex','w') as f:
    f.write(tex)

冒頭に挙げたタイプのcsvファイルからデータを読み取り,これを辞書の配列(memberlist)にして, それをnameplate.pytexmembersにバインドさせるのが,engine.render(...)という部分です. ここもあまり工夫はせず,素直なプログラムの積み重ねになってます.

汎用性の高い「差し込み印刷スクリプト」

賢明な読者の方なら,このスクリプトはネームプレートを作るだけのものではないと思われるでしょう. 実際,これとほぼ同じようなスクリプトを,敗者復活の問題用紙作成にも用いています. 実際のところ,この問題用紙作成の方がこのスクリプトの有用性は高いです.というのも,今回の場合668人の問題用紙を作成する必要があるからです.

さらに言うと,今回は用いませんでしたが,このスクリプトは150問4択ペーパーの問題用紙作成にも使えます. 問題のデータをcsvにして,texで雛形を作って,同じようにスクリプトとテンプレートを作って流しこめばいいのです.実際,昨年開催された「あにわん!」では,このようにして問題用紙を作成しました.ただしこの場合,「1ページを25問に収める」などの調整が必要なので,できたtexファイルに微調整をする必要があります.しかし,その手間があるからと言って,差し込み印刷スクリプトの有用性が無くなるわけではありません.

最後に: ネームプレート今昔

本格的にabcのネームプレート作成に関わったのは8thのときでしたが,7thのときもお手伝いをしました. その頃は参加者が増加している真っ最中で,しかしながら事前エントリーもないという状況でした. ですので,「参加しそうな参加者の名前面を事前に全部作成しておき,当日追加分はその場で印刷」という手法を取りました. さらにそのときは諸事情あって全部手入力で行ってました.

そのあと,事前エントリーが導入されたことでtexを使った事前処理が可能になりました. しかしそれでも,「全参加者の名前面を事前作成する」ということをずっと続けていて,1回の大会の度にKinko’sでひたすら印刷作業をするのが恒例になっていました. ただ,当たり前ですが,この名前面のうち使用するのは48枚のみなので,90%以上の紙は無駄になってしまいます. それを改善するため,13thから現在の仕組みを導入しています.

考えてみれば,もっと早くから導入していい仕組みだったと思うのですが, どうしてもその仕組みを導入するための初期コストとか, 成功するかどうかの不安などがあって,なかなか一歩が踏み出せませんでした.

こういう仕組みを導入するためには,「楽をするにはどうすればいいか」ということを必死になって考えることが重要だと個人的に思います. 私の場合,「コツコツやる」ということが非常に苦手な人間なので,面倒を回避するためにどういう初期投資をすればよいかをまず考えています.特にabcは規模が大きい大会ですから,今後こういう考え方がますます重要になるのではないかと思います.