LoginSignup
0
0

More than 1 year has passed since last update.

【言語学者向け】エクセルの調査票からpdfの調査票を作成する (Python + TeX)

Last updated at Posted at 2022-10-29

想定読者

フィールド調査をする言語学者

目的

エクセルに記入した調査票から、調査時に文字を書き入れるためのpdfの調査票を作る。

できること

こんな感じのエクセルから
スクリーンショット 2022-10-29 21.32.47.png

#こんな感じのpdfを生成する
スクリーンショット 2022-10-29 22.11.13.png

背景

多くの研究者は、フィールドワークの準備としてエクセルで調査票を管理することが多いと思う。また、共同プロジェクトで共通の調査票を用いる場合、エクセルで調査票が配布されることがほとんどである。

調査時にPCでエクセルにそのまま書き込むスタイルを取る人であれば問題ないが、

  • 目の前でパソコンをカタカタされるのを好まない被調査者がいる
  • 音声記号や超分節要素が打ちにくい
  • マイクに打鍵音が入る
  • 追加の情報を入れづらい
    などの問題があるので、私は紙のノートやタブレットに調査メモを書き込むようにしている。

しかし、調査票のエクセルファイルをそのまま印刷してしまうと、

  • 余白が少なすぎる
  • ページレイアウトが綺麗でない

などの問題がある。

そこで、

  • 元のエクセルファイルのデータ構造は変更したくない
  • 十分な余白をとって適切にレイアウトした書き込み用の調査票がほしい

という需要が発生する。

これを解決するために、エクセル形式の調査票からpdf形式でレイアウトされた調査票を出力する方法を紹介する。

環境

  • Python 3系
    • pandas
  • TeX (今回はpLaTeX)

手順

おおまかな手順を紹介する。

  1. Pythonのpandasモジュールを使ってエクセルファイルを読み込む
  2. 表を一行ずつ処理し、.texファイルを生成する
  3. あらかじめ.texのメインファイルを作っておき、先程生成した.texファイルをインプットする
  4. TeXで組版する

手順1: 必要なファイルを用意する

ファイル構成

root
├── make_questionnaire.py
├── questionnaire.xlsx
└── tex
    ├── questionnaire.tex
    └── questionnaire_main.tex

フォルダの中にquestionnaire.xlsx(調査票の元エクセルファイル)、./tex/questionnaire.tex(処理するTeXファイル)、make_questionnaire.py(Pythonスクリプト)を用意する。

ファイルの用意

questionnaire.xlsx

スクリーンショット 2022-10-29 21.32.47.png

こんな感じの内容にする。今回は「ID」列と「例文」列しか使わないが、他の列があってもいい。行は何行でもOK。questionnaire.py(後述)で列名を指定して処理しているので、「ID」列と「例文」列の列名は変えないこと(列名を変えるならquestionnaire.pyの処理を適宜変えること)。

questionnaire_main.tex

questionnaire_main.texは組版処理を行うためのメインファイル。ここにプリアンブル、\input命令、document環境などを書き込んでいく。
最小構成は以下のような感じ。
プリアンブルで、各例文を整形するための\entryというマクロを定義しておく。

questionnaire_main.tex
\documentclass{article}
\newcommand{\entry}[2]{\noindent #1: #2 \vspace{20zw}}

\begin{document}
\input{questionnaire.tex}
\end{document}

手順2: Pythonの処理

ここからPythonの処理を書いていく。
手順としては、

エクセルファイル読み込み

make_questionnaire.py
import pandas as pd
df = pd.read_excel("questionnaire.xlsx")

pandasモジュールをpdという名前でインポートする。
pandasのread_excel()という関数でエクセルファイルを読み込み、dfという変数に格納する。

一行ずつ処理して文字列型のオブジェクトにする

make_questionnaire.py
tex_text = ""
for index, row in df.iterrows():
    tex_text += f"\\entry{{{row['ID']}}}{{{row['例文']}}}\n\n"

pandas.DataFrameiterrows()メソッドを使うと、(行名, その行のデータ(Series))を一行ずつ取り出せる。これをforで一行ずつ処理していく。ここではこれらをindex, row という名前にしているので、row['列名']とすると、その行の'列名'列のデータが取り出せる。

まずtex_textという空の文字列を用意し、そこに一行ずつTeXで予め定義した\entry命令を書き込んでいく。つまり、調査票の各行について

\entry{ID}{例文}

という命令を書き込む。
f"\\entry{{{row['ID']}}}{{{row['例文']}}}\n\n"はフォーマット済みリテラルなので、{}で囲まれた部分は文字列として扱われず、オブジェクトを直接書き込める。
要するに、

tex_text = tex_text + "\\entry{" + row['ID'] + "}{" + row['例文'] + "}" 

とするのと同じ。
これでtex_textという変数に全ての行の\entry命令が入ったことになる。

.texファイルとして書き込み

make_questionnaire.py
with open("./tex/questionnaire.tex", mode="w") as f:
    f.write(tex_text)

with構文の中で書き込みモードでopen()関数を使い、./tex/questionnaire.texというファイルにtex_textの中身を書き込む。
これで.texファイルの生成は終了

TeXの組版

これで必要なファイルは全部そろったので、TeXを組版する。TeXエディタを起動して組版してもいいし、VSCodeとかを使っている人ならそこから組版してもいいが、せっかくなのでPythonからシェルを叩いてTeXを組版する。

make_questionnaire.py
import glob
import os
import subprocess

def delete_ext():
    ext_list = ["aux", "dvi", "log"]
    for ext in ext_list:
        file_to_delete = glob.glob(f"*.{ext}")
        for f in file_to_delete:
            os.remove(f)

os.chdir("tex")
delete_ext()
subprocess.call(["platex questionnaire_main.tex"],shell=True)
delete_ext()

delete_ext()で余計な中間ファイルを削除する関数を定義している。
その後は、./texに移動し、中間ファイルを削除し、subprocess.call()でシェルを実行してTeXを組版している。

アウトプット

スクリーンショット 2022-10-29 22.11.13.png
こんな感じのpdfが生成される。間隔を調整したい場合は\entryの定義の\vspaceを適宜調整する。

最終的なコード

make_questionnaire.py
import glob
import os
import subprocess
import pandas as pd

def delete_ext():
    ext_list = ["aux", "dvi", "log"]
    for ext in ext_list:
        file_to_delete = glob.glob(f"*.{ext}")
        for f in file_to_delete:
            os.remove(f)

df = pd.read_excel("questionnaire.xlsx")
tex_text = ""

for index, row in df.iterrows():
    tex_text += f"\\entry{{{row['ID']}}}{{{row['例文']}}}\n\n"

with open("./tex/questionnaire.tex", mode="w") as f:
    f.write(tex_text)

os.chdir("tex")
delete_ext()
subprocess.call(["platex questionnaire_main.tex"],shell=True)
delete_ext()
questionnaire_main.tex
\documentclass{article}
\newcommand{\entry}[2]{\noindent #1: #2 \vspace{20zw}}

\begin{document}
\input{questionnaire.tex}
\end{document}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0