はじめに
SDAPSはマークシート専用紙を必要としない、一般的なコピー用紙とドキュメントスキャナを使用してアンケートの質問票作成、集計を行なうOMR(光学式マーク読取)ソフトウェアです。
厳密な精度が求められる入学試験のような用途には不適切ですが、塗り潰す必要がない(これはcheckmode=fillで塗り潰しに変更可能)、専用用紙を準備する必要がない、などのメリットがあります。
オリジナルのSDAPSは日本語をサポートしていないため、日本語テキストを含む質問票を作成し、レポートを出力することができるように改造したsdapsコマンドを実行するDockerイメージを作成してみました。
作成したDockerイメージはDockerHubにて、Dockerfileや変更部分はGitHubにて公開しています。
成果物
変更部分などは下記のGithub, DockerHubにて公開しています。
- 【GitHub】YasuhiroABE/docker-sdaps-ja
- 【DockerHub】yasuhiroabe/sdaps-ja
- 【GitHub】日本語の質問票を作成するためサンプルプロジェクト
最後のコード一式をdockerコマンドが利用できる環境(※)に展開すれば、質問票の作成を除けば、簡単なコマンド入力で作業を進めることができます。
参考資料
この記事を書く際に参考にしたURLをリストにしています。
- https://sdaps.org/
- http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/
- https://qiita.com/YasuhiroABE/items/75639f4b95731171b894
開発環境
開発環境をUbuntu 22.04に変更したため、コンテナも合わせて更新しました。
- ホストOS
- Ubuntu 22.04.3 on VMware Workstation 17 Pro
- Docker
- docker-ce (20.10.23, rootless-mode, buildx)
- SDAPS
jammyではstable版と違いがなさそうなので特に意識せずにunstable版のPPAを利用していますが、将来変更するかもしれません。
テスト環境
以下の環境で、質問票の作成・TIFFイメージの読取・修正ができることをテストしています。
【2022/03/11】Apple Silicon環境でのテストは限定的です。
- Linux Distribution
- Xubuntu Desktop 22.04.3 amd64版
- Windows11 (22H2) amd64bit版
- WSL2 + Docker Desktop for Windows (24.0.6)
- Windows Terminal
- 【非対応】macOS (M1, Apple Silicon)、Raspberry Pi等ARM系CPU
- PPAパッケージがarm64に対応していないためコンテナの構築ができません。必要な場合は docker.io/yasuhiroabe/sdaps-ja:ub2004-5 を利用してください。
質問票の印刷、読み取りには以下のような機材を使用しています。
- レーザープリンター (OKI B841)
- 一般的なPPC用紙 (白色普通紙)
- 印刷品位 - 高精細 (1200x1200)
- ドキュメントスキャナ (Brother ADS-3600W)
- 設定 - TIFFマルチページ・300dpi・モノクロ・長辺とじ
コピー(複写)機の利用について
いまのところ質問票を準備するために複写機は積極的に使用していませんが、利用できている事例はあります。
機種によってはPDF出力がJPEG画像を変換したのかと思われるほどに、マルチページTIFF出力と比較して明らかに劣化している場合があったので事前の動作確認は必須です。
使い方
コマンド実行時には、Dockerのvolume機能を利用して、回答票のTeXファイルとプロジェクト・ディレクトリを配置する作業用ディレクトリを作成し、必ずコンテナ内の/projにマウントするようにしてください。カレント・ワーキングディレクトリも/projになります。
- Dockerコンテン内の作業用ディレクトリ: /proj
作業の流れ
おおまかには次のような順序で利用しています。
- 作業用ディレクトリを作成する (e.g. mkdir proj/)
- 質問票のTeXファイルを作成 (e.g. proj/example.tex)
- setupコマンドを実行し、プロジェクト・ディレクトリを作成
- 記入済みの質問票をスキャンし、TIFFファイルを作業用ディレクトリに配置 (e.g. proj/01.tiff, proj/02.tiff,...)
- addコマンドを繰り返し実行し、TIFFファイルを登録
- recognizeコマンドを実行し、データを抽出
- report_texコマンドでreportファイルを作成 (e.g. proj/work/report_1.pdf)
- csvコマンドで生データを抽出 (e.g. proj/work/data_1.csv)
準備作業
使用するDockerイメージはコマンド実行前にpullしておきます。
$ docker pull docker.io/yasuhiroabe/sdaps-ja:ub2204-20231004
作業用ディレクトリについて
参考までに最終的なproj/ディレクトリの様子を掲載します。
$ tree proj/
proj
├── 01.tiff
├── example.tex
└── work
├── 1.tif
├── data_1.csv
├── info
├── info~
├── log
├── questionnaire.aux
├── questionnaire.log
├── questionnaire.out
├── questionnaire.pdf
├── questionnaire.sdaps
├── questionnaire.tex
├── report_1.pdf
├── report_2.pdf
├── sdapsarray.sty
├── sdapsbase.sty
├── sdapsclassic.cls
├── sdapscode128.tex
├── sdapslayout.sty
├── sdaps.opt
├── sdapspdf.sty
├── sdapsreport.cls
├── survey.sqlite
├── translator-sdaps-dictionary-Brazilian.dict
├── translator-sdaps-dictionary-Dutch.dict
├── translator-sdaps-dictionary-English.dict
├── translator-sdaps-dictionary-Finnish.dict
├── translator-sdaps-dictionary-French.dict
├── translator-sdaps-dictionary-German.dict
├── translator-sdaps-dictionary-Italian.dict
├── translator-sdaps-dictionary-Norsk.dict
├── translator-sdaps-dictionary-Polish.dict
├── translator-sdaps-dictionary-Portuguese.dict
├── translator-sdaps-dictionary-Romanian.dict
├── translator-sdaps-dictionary-Sinhala.dict
├── translator-sdaps-dictionary-Spanish.dict
├── translator-sdaps-dictionary-Swedish.dict
└── translator-sdaps-dictionary-Ukrainian.dict
1 directory, 39 files
日本語質問票のサンプルの準備
テストのために使用したファイルを掲載していますが、オリジナルからコメントやコンテンツの一部を削除しています。
\documentclass[
english,
a4paper,
checkmode=check,
pagemark,
stamp]{sdapsclassic}
\usepackage[utf8]{inputenc}
% For demonstration purposes
\usepackage{multicol}
\usepackage{xltxtra}
\setmainfont{IPAPMincho}
\setsansfont{IPAPGothic}
\setmonofont{IPAGothic}
\XeTeXlinebreaklocale "ja"
\author{作者}
\title{タイトル}
\begin{document}
\begin{questionnaire}
\begin{info}
\texttt{info}環境を利用することで、任意のテキストを追加することができます。
\end{info}
\addinfo{Date}{10.03.2013}
\section{5段階評価}
\singlemark{どのくらいの頻度でSDAPSを利用していますか?}{ほとんどない}{毎日}
\end{questionnaire}
\end{document}
あらかじめ定義されている定型文の一部についても置換が可能です。
\ProvidesDictionary{translator-sdaps-dictionary}{English}
\providetranslation{infotext}{記入方法/Instructions to fill out the form.}
\providetranslation{standard-deviation}{Standard-Deviation}
\providetranslation{info-cross}{マーク例/Check}
\providetranslation{info-correct}{修正例/Uncheck to correct}
\providetranslation{answers}{Answers}
\providetranslation{questionnaireid}{Questionnaire-ID:}
\providetranslation{surveyid}{Survey-ID:}
\providetranslation{draft}{draft}
\providetranslation{info-mark}{For questions with a range (1-5) choose the answer the mark that fits best.}
\providetranslation{info-select}{満足度などについては、5段階で 1つにマークしてください。}
\providetranslation{mean}{Mean}
example.texとtranslator-sdaps-dictionary-English.dictを、作業用ディレクトリ(dev.proj1)に配置した様子は次のようになります。
$ tree proj/
proj/
├── example.tex
└── translator-sdaps-dictionary-English.dict
0 directories, 2 files
【補足】オリジナルの translator-sdaps-dictionary-English.dict の入手方法
Ubuntuなどでパッケージからインストールできる場合は、/usr/share/sdaps/tex/ からコピーすれば良いのですが、それができない場合にDockerイメージから抽出する方法をメモしておきます。
"docker cp"はイメージからのファイル抽出には使えないので、少々面倒ですが、次のような方法でオリジナルのファイルを抽出することができます。
## sdapsコマンドを実行する("-rm"オプションは付けない)
$ docker run yasuhiroabe/sdaps-ja:ub2204-20231004
## コンテナIDを確認する
$ docker ps -a |grep sdaps-ja
a9e5dcb2a026 yasuhiroabe/sdaps-ja:ub2204-20231004 "/run.sh --help" 17 seconds ago Exited (0) 16 s
econds ago eloquent_haibt
## コンテナIDを利用して必要なファイルをコピーする
$ docker cp a9e5dcb2a026:/usr/share/sdaps/tex/translator-sdaps-dictionary-English.dict my-translator.dict
setupコマンド
回答票のTeXファイルを作成したら、sdapsコマンドにプロジェクト・ディレクトリを作成させます。事前にプロジェクト名でディレクトリを作成するとエラーになります。
$ docker run --rm \
-v `pwd`/proj:/proj \
--name sdaps-ja \
yasuhiroabe/sdaps-ja:ub2204-20231004 \
setup \
--add translator-sdaps-dictionary-English.dict \
work/ example.tex
This is XeTeX, Version 3.14159265-2.6-0.999991 (TeX Live 2019/Debian) (preloaded format=xelatex)
restricted \write18 enabled.
entering extended mode
This is XeTeX, Version 3.14159265-2.6-0.999991 (TeX Live 2019/Debian) (preloaded format=xelatex)
restricted \write18 enabled.
entering extended mode
...
Running xelatex now multiple times to generate the questionnaire.
Running xelatex now multiple imes to generate the questionnaire.
タイトル
Author: 作者
Date: 10.03.2013
指定したプロジェクト・ディレクトリ(dev.proj1/work/)の中に、questionnaire.pdf が配置されます。
addコマンド
質問票をスキャンし、TIFFマルチページ形式のファイル(この例では01.tif)をプロジェクト・ディレクトリに配置してから、addを実行します。
$ docker run --rm \
-v `pwd`/proj:/proj \
yasuhiroabe/sdaps-ja:ub2204-20231003 add work/ 01.tiff
Processing 01.tiff
Done
使用している機材では1ファイルに25ページ分の回答しか格納できないので、これを越える場合は複数回、addコマンドを実行します。
recognizeコマンド
回答シートの登録が終った時点で、その登録したシートを解析するフェーズです。
$ docker run --rm \
-v `pwd`/dev.proj1:/proj \
yasuhiroabe/sdaps-ja:ub2204-20231003 \
recognize work/
Connection Error (Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory)
Connection Null
...
Warning: 1.tif, 1: Matrix not recognized.
Warning: No page number for page 1.tif, 1 exists.
Warning: Got a wrong survey ID (1.tif, 1)! It is None, but should be 2449560734.
Warning: 1.tif, 3: Matrix not recognized.
Warning: No page number for page 1.tif, 3 exists.
Warning: Got a wrong survey ID (1.tif, 3)! It is None, but should be 2449560734.
4 sheets
Processed 4 of 4 sheets, took 1.852894 seconds
‘‘‘
## report texコマンド
解析した結果を元にレポートPDFファイルを抽出するために使用します。
```bash:report_tex実行例
$ docker run --rm \
-v `pwd`/proj:/proj \
yasuhiroabe/sdaps-ja:ub2204-20231003 \
report tex work/
Unable to init server: Could not connect: Connection refused
Unable to init server: Could not connect: Connection refused
This is XeTeX, Version 3.14159265-2.6-0.999991 (TeX Live 2019/Debian) (preloaded format=xelatex)
restricted \write18 enabled.
entering extended mode
...
Running xelatex now multiple times to generate the report.
処理が終るとプロジェクト・ディレクトリ(dev.proj1/work/)の中に、report_.pdfファイルが生成されています。
report_texコマンドのオプションに、--create-tex*オプションがあり、TeXファイルを抽出する機能がありますが、これは/tmpに途中経過を出力するため、もし利用する場合には、適当なディレクトリを/tmpにマウントしてください。この例はGNUmakefile内の、proj2-reporttexタスクに記載しています。
report_1.pdfには次のように結果が出力されます。"Answers:", "Mean:", "Standard-Deviation:"などを日本語化したい場合には、translator-sdaps-dictionary-English.dict を変更してください。
report reportlabコマンド
Pythonのreportlabライブラリを利用して直接出力を得ることも可能です。
LaTeXと比較すると出力されるレポートの品質が少し異なります。
$ docker run --rm \
-v `pwd`/proj:/proj \
yasuhiroabe/sdaps-ja:ub2204-20231003 \
report reportlab work/
csvコマンド
生データをCSV形式で抽出したい場合に利用します。レポートの内容が正しいか検証するために使用します。
Excelで偏差などを計算すると誤差の処理方法の違いから、微妙に違う値が表示されるなどするかもしれません。
$ docker run --rm \
-v `pwd`/proj:/proj \
yasuhiroabe/sdaps-ja:ub2204-20231003 \
export csv work/
生成されたCSVファイルは、プロジェクト・ディレクトリの data_*.csv に出力されています。
questionnaire_id,global_id,empty,valid,recognized,review,verified,1_review,1_1_review,1_1
None,None,0,1,1,,0,,,3
None,None,1,0,1,,0,,,-1
None,None,0,1,1,,0,,,4
None,None,1,0,1,,0,,,-1
主な利用例は以上です。
作業中に発生した問題
最後に作業中に遭遇した問題についてメモを残しておきます。興味のある方はどうぞ。
sdaps reportを実行するとエラーが発生する
コンテナの中から実行した時だけ、"Unable to init server: Could not connect: Connection refused"というメッセージが表示されます。
## あらかじめ dev.proj2/ には、質問票のTeXファイルと回答をsdaps addした20200310_survey/ディレクトリを配置しています
$ docker run --rm -v `pwd`/dev.proj2:/proj \
--name sdaps-ja \
sdaps-ja report tex 20200310_survey/
エラーのタイミングが不明だったので、起動スクリプトを作成し、straceで処理の様子を観察しました。
#!/bin/bash
cd "${WORKING_DIR}"
strace sdaps "$@"
そこでメッセージが出力される
connect(6, {sa_family=AF_UNIX, sun_path=@"/home/sdaps/.cache/broadway1.socket"}, 38) = -1 ECONNREFUSED (Connection refused)
どうやら裏で画像イメージを処理するかなにかでロードしているライブラリが初期化処理で、Xサーバーに接続しようとして失敗しているように見えます。
sdapsがちゃんと実行できるローカル環境でもDISPLAY環境変数を稼動していない方に向けると失敗します。
$ env DISPLAY="" sdaps report 20200310_survey
------------------------------------------------------------------------------
- SDAPS -- report
------------------------------------------------------------------------------
Unable to init server: Could not connect: Connection refused
Unable to init server: Could not connect: Connection refused
このため、DISPLAY環境変数をdocker runの際に--envオプションで追加することにしました。
Ubuntu 20.04のX serverはunix domain socketのみを開いているので(6000番ポートは閉じている)、/tmp/.X11-unixをmountしています。この辺りは、lsofの出力と参考情報にあるリンク先を参考にしています。
それでもDBus周りのエラーは残っていますが、とりあえずスルーすることにします。
$ docker run --rm \
-e DISPLAY=:0.0 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v `pwd`/dev.proj2:/proj \
--name sdaps-ja \
sdaps-ja \
report tex 20200310_survey/
(sdaps:1): dbind-WARNING **: 13:41:40.375: Couldn't connect to accessibility bus: Failed to connect to socket
/tmp/dbus-5MKrJQOOU3: Connection refused
なおX serverに接続しなくても、エラーのまま処理は正常に終了しているので、実際の利用時にはこれらの変数は設定していません。