Hatena::ブログ(Diary)

アセトアミノフェンの気ままな日常

2015-08-31

バッチファイルの技巧

いま bcpdfcrop v0.3.1 を公開。昨日書いたとおり、オプション(“/”で始まるバッチファイル引数をオプションとみなす)を順不同で指定できるようにした。このなかで曲者なのがもちろん v0.3.0 で実装したばかりの /m オプションである。この /m オプション自体が次に引数を伴うので、ほかのオプションとは少々扱いが違う。実装はなんだか技巧的な気がする… ついでに Unknown option の警告も返すようにできた。同じ方法を使えば、出力する PDF のバージョンを指定する /v オプションもその気になれば作れるんだよなあ…とこれまた悩み中。

2015-08-30

バッチファイルのリファクタリング中

いま、僕がいままで作ってきた各種バッチファイルのリファクタリング中。いま思いついているだけでも改善点が多数。

  • bcpdfcrop
    • オプションの指定順序を固定しているのが不便→どんな順序でもオプションが有効になるように変更予定。
    • 余白指定オプションが第4-第7引数になっているのが使いづらい→本家 pdfcrop ライクなオプション指定法で再実装がほぼ完了。
    • ページ範囲指定で「*」が単独で指定された場合に1ページ目だけとして扱われるのが非直感的→これを全ページとみなすように変更予定。
    • ページ範囲指定や余白指定に数字以外が指定された場合への対処:以前考えていた途中だが、これを取り入れるかどうか悩み中。
  • dvipdf

作品集は後日まとめて公開予定。

2015-08-29

dvips + gs による PDF 生成

最近 pLaTeX + dvips + gs による PDF 生成を試している…別に新しいことは何もないのだけれど、僕自身はほとんど使ったことのないスキームだったから。そこで気づいたのだが、Mac などの Unix 環境ではどうやら gs に dvips と gs をパイプで実行するシェルスクリプト「dvipdf」が入っているらしい。これは Windows ネイティブで使えないので、試してみたくなって大雑把にバッチファイルに翻訳してみた。初めて知ったのだけど、dvips はログを標準出力でなく標準エラー出力に吐くのね…なんか不思議。

いまこんなことを試しているのは、TeX2img でこの経路をサポートすることを検討しているからである。というのも、日本ではほとんど DVI 経由で (u)pLaTeX + dvipdfmx が使われている一方で、海外では LaTeX + dvipdfm(x) はほとんど使われておらず「DVI 経由といえば LaTeX + dvips + gs」という状況であることが十分想定されるからである。そして、これがおそらく、graphics のドライバがデフォルトで dvipdfmx.def でなく dvips.def を採用している所以であろう。

もちろん海外では pdfLaTeX が主流ではあるが、PSTricks や PSfrag を使うという用途に限り DVI 経由でなければならないという見方が強いようである。これらのパッケージは dvips + gs に強く依存しているので、現行の TeX2img では僕がむかし紹介した裏技 (Win/Mac) を使わない限り難しい。これが海外で TeX2img 不利の原因になりかねないことを危惧して、機能拡張を検討しているところ

いま、Mac 版が dvips + gs や dvipdf を DVIware に指定してもよいようになりつつある。Win 版も dvips + gs をとりあえずサポートしつつあるところである。

2015-08-28

chemobabel v0.9

昨日の件は、ZR さんの助言により解決。e-TeX 拡張なし・かつ余分なファイルを使わない処理になった。トリッキーな方法。



\expandafter しないといけないかと思ったよ…こわいこわい

2015-08-27

chemobabel の「verbatim な引数」について

以前から気になっていた chemobabel パッケージの変態な引数の扱いを、v0.7 でライトな LaTeX ユーザ向けに改善した。しかも、ZR さん提案の xparse パッケージを使う方法のように expl3 に依存することもない*1! 参考にしたのはここ。

ただし、今回の場合は第二・第三引数(obabel に渡す)を verbatim にしたい一方で第一引数は \includegraphics のオプション引数なので通常通り扱いたい。そこで、いったん別ファイルに \write してそれを \input する方法で乗り切った。

\newwrite\smilesobabelfile
\newcommand\@smilesobabel{%
  \begingroup
  \let\do\@makeother
  \dospecials
  \catcode`\{=1
  \catcode`\}=2
  \@@smilesobabel
}
\newcommand\@@smilesobabel[3][scale=1]{%
  \endgroup
  \immediate\write18{obabel -:"#2" -O \smilesobabelGetName.svg #3 2>\smilesobabelGetName.log
    && inkscape -f \smilesobabelGetName.svg --export-pdf=\smilesobabelGetName.pdf 2>>\smilesobabelGetName.log
    || rm -f \smilesobabelGetName.pdf}%
  \IfFileExists{\smilesobabelGetName.pdf}{% the PDF exists: include it
    \immediate\openout\smilesobabelfile=\smilesobabelGetName.tex\relax
    \immediate\write\smilesobabelfile{\string\includegraphics[#1]{\smilesobabelGetName.pdf}}%
    \immediate\closeout\smilesobabelfile
    \begingroup\catcode13=9\input{\smilesobabelGetName.tex}\endgroup%
  }{% the PDF was not created - show a warning and a hint
    \PackageWarning{chemobabel}{Processing of SMILES string failed}%
    \fbox{\begin{minipage}{0.9\textwidth}
      Error in chemobabel: the file was not compiled. Remember to run \texttt{latex}
      (\texttt{pdflatex}, \texttt{platex}, etc.) with the \texttt{-shell-escape} option.\\
      \IfFileExists{\smilesobabelGetName.log}{%
        obabel log (might be empty):
        \verbatiminput{\smilesobabelGetName.log}%
      }{%
        No log file.%
      }%
    \end{minipage}}%
  }%
  \addtocounter{smilesobabelCounter}{1}% select next name
}

このとき、\write したファイルには最後に改行が入ってしまうので、\input すると余分な空白が出てしまう。そこで、\catcode を変更して改行を無視させることにして一件落着。ただ、このいったん書き出す方法以外にも試してみたくなって、偶然みつけた以下のページを参考に \scantokens を使ってみることに:

これを使うと、上のコードのうち

    \immediate\openout\smilesobabelfile=\smilesobabelGetName.tex\relax
    \immediate\write\smilesobabelfile{\string\includegraphics[#1]{\smilesobabelGetName.pdf}}%
    \immediate\closeout\smilesobabelfile
    \begingroup\catcode13=9\input{\smilesobabelGetName.tex}\endgroup%

という4行は以下のように書き換えられる:

    \scantokens{\includegraphics[#1]{\smilesobabelGetName.pdf}}%

中間ファイルが一つ減って嬉しいのだが、\scantokens はどうやら e-TeX 拡張の一部らしい。pLaTeX が e-pTeX になったのは比較的最近 (2011?) のはずなので、うーん e-TeX 拡張を前提とするのは厳しいかなあ…

いずれにせよ、ほぼコピペに近いコードで挙動を改善できそうなことはわかって収穫だった。

追記 (2015-08-28):解決!

*1:ZR さんが僕に簡単な解決策を示したかっただけなのは理解しております…

2015-08-26

はてなブログ(メインブログ)一周年です

最近ひまがなくてめっきり更新していないのだが、いつのまにかアカウントを作ってから一年経っていた。つまり大学院入試から一年である。今見たら累計アクセス数が64449件だそうな。6万件超えてるのね…

ブログを始めた段階では思いもよらなかった出会いや変化がこの一年間にあった。新たな発見や学んだことも多い。というわけで、これからもぼちぼち続けていくつもりです。

2015-08-25

chemobabel を更新

久々に chemobabel パッケージを更新した。\catcode をユーザが使わずに済むようになった…つもり。もう少し実装を改善できないか検討中。

追記 (2015-08-27):ちょっとだけ解説

2015-08-24

ちょっとびっくり

今月 BXjscls v1.0 がリリースされて、マニュアルが充実したので使ってみようかなという気になってきた。実際のところ BXjscls のコンセプトは気に入っているし、名実共に初心者に勧めてもよい水準になったとみてよいのだろうな。でも、さすがに TeX Wiki の「LaTeX 入門」に書くには早いよな… というわけで、しばらく様子見
追記 (2015-09-04):使ってみた

そういえば、TeX2img の解説記事は先日更新しました。

2015-08-23

なりすまし流行ってますね

Twitter のなりすまし、科学系の有名ツイッタラーが最近大量に狙われているようだ。注意注意。

2015-08-22

ゆきだるま追加

最近みつけたいくつかのフォントのゆきだるまたちを紹介。メインブログの記事は更新していないが、ゆきだるまだけ紹介したい*1

f:id:acetaminophen:20150822233614p:image

Everson Mono は“シェアウェア”として公開されているもの。以前は PDF への埋め込みを見送ったものだが、まあゆきだるまくらい見せても良かろうと思って載せた。次の正調祥南行書体は「筆ぐるめ」という有料のはがき作成ソフトウェア付属のフォント。埋め込みが許可されていないので、わざわざ筆ぐるめに表示してスクリーンショットしたものを画像にはめ込んである。ほかはフリーフォントで、フォント名を検索すれば情報が得られるはず。フリーフォントはどれも個性的である*2

ついでに、先日紹介した MediBang Paint で見ることのできるゆきだるまもここに載せておこう。これらの有料フォントはログインした人限定で“クラウドフォント”として利用でき*3、それを PNG に出力して並べてある。

f:id:acetaminophen:20150822233610p:image

*1:いちいち XeLaTeX の処理結果まで載せなくてもよいだろう…

*2:個人的に Nemuke フォント(=ビットマップフォントを Potrace でアウトライン化してグリフを作ったらしい)が画期的だと思った。Potrace は以前紹介したことがあるが、よほど高精度でなければ綺麗なアウトライン化はできない。それを逆にフォントの個性として利用するという発想が新しいと思う。

*3:通常のフォントとしての利用はできないが、マンガの中に文字を入れる場合にビットマップ化された状態の文字を入れることができる機能。

2015-08-21

周期表アプリ

Twitter で仕入れたのだが、最近できた RSC の周期表アプリ (iPad) がかなり良さそう。



f:id:acetaminophen:20150822004643p:image

f:id:acetaminophen:20150822004650p:image

写真も綺麗で、データ量も豊富。元素の発見の歴史や用途、物理的性質などがよくまとまっていて、ひまなときに眺めるにも最適のようだ。いいアプリができたものだ。

2015-08-20

東京に戻ってきました

いつもどおり東筑軒のかしわめしを食べて戻ってきた。

f:id:acetaminophen:20150820210416j:image

一週間地元にいたことになる。ラボに明日持っていくお土産に悩んだ… 毎回帰省のたびに違うものを買うように自分で決めているのだけど、選択肢がだんだん狭まってきているのだ。東京から地元に持ち帰ったものは好評だったので良かったが…
それと、長期間メインブログが滞っているのでそろそろ書きます。

2015-08-19

MediBang Paint がおもしろそうなので

あまり紹介されていないようなので、ちょっとだけ。

MediBang Paint なる無料のマンガ作成ソフトがあるようだ。早速ダウンロードしてユーザ登録してみると、有料の日本語フォントが19種類も無料でマンガに使えるようになる。もちろんフォント埋め込み等はできないが、マンガを描いて吹き出しに文字を入力する程度なら事足りるように、ラスタライズされたフォントに置き換わって表示されるようだ。クラウドに接続している間だけ文字の編集ができるが、クラウドが切れても編集しない限り文字は残っているので安心。ペイントツールとしても良さげなので今度ゆっくり使ってみたい。

追記 (2015-08-22):使えるクラウドフォントのゆきだるま一覧

2015-08-18

母校でしゃべってきました

先輩による進路講演会なるもので、大学の生活についてしゃべってきた。受験勉強で何をやっていたかまでは覚えていないことが多いのだけれど、最近の研究室生活や日常生活もいろいろと。当時の先生方とも話したのだけれど、英語の先生が僕との在学中の会話を覚えていて、いまでも語り草にしているそうな。

先生「おまえ、もうこの授業の内容は聞かなくても分かるだろう、なんで一生懸命聞いてるんだ」
僕(高3)「分からないことを先生がいうかもしれないんで」

僕も覚えてはいるけど、そんなに意識してはいなかった回答で、5年たっても言われ続けて不思議な気分だった。当時の先生方は異動にともない7人くらいしか会えなかったけれど、あまり変わっていなかった。学生と接していると若いままなんだなー。

2015-08-17

化学絵文字ができたらしい

ACS Chemoji なるものができたらしい。iPhoneAndroid も持っていないのでダウンロードできないのだが、紹介画像を見る限りではどの辺が化学なのかよくわからない。もっと詳しい紹介記事を誰か書いてくれないかな?

追記:あまりおもしろいものではなさそう。

2015-08-16

新しい記事を書くよりも大変なのが…

ブログの記事を新しく書くよりも大変なのが、過去記事の改訂作業である。ブログで過去記事を改訂するという概念自体がふつうはないかもしれないが、技術系ブログならではだと思う。いま TeX2img の解説記事も改訂中で、BoundingBox 関連の記事も改訂中。こうやって記事のメンテナンスを続けることも大事だと思って粛々と。

2015-08-15

英語に翻訳…

メインブログの記事を英語に翻訳してほしいというコメントが来ている。ただでさえ日本語でも説明が難しいのに… ひまなときにぼちぼち始めるか。

2015-08-14

実家です

夜9時前に帰り着いてゴロゴロ。やっぱり畳はいいねw

2015-08-13

明日地元に帰ります

いちおう盆休み。ちょっと遅めの帰省予定で、盆明けに一つ母校訪問する用がある。いま必死に部屋を片付けていて疲れたところ…

TeX2img の Mac 版が更新されたので、コマンドライン版からぼちぼち解説記事を改訂中。Windows 版が出たら完成させて告知かな。

2015-08-12

コマンドプロンプトの大小比較を切り抜けたい

bcpdfcrop の v0.1.9 で導入して v0.2.3 で廃止した「BBOX の左下と右上の座標比較」を復活させるにはどうすればよいか考えていたのだが、一筋縄ではいかなそう…

問題の v0.1.9 以降 v0.2.2 までに入っていたコードは以下のとおり。

:: PROCBBOX の値が空にならないように初期化
  set PROCBBOX=%%%BBOX%: 0 0 0 0
:: gs による BBOX をファイルから読み込み(もしファイルが空なら初期値保持)
  set /P PROCBBOX=<"%TPX%%%i-box.txt"
:: 最初の %%BoundingBox: や %%HiResBoundingBox: を切除
  set PROCBBOX=!PROCBBOX:* =!
:: とりあえず VALIDBOX=0 で初期化
  set VALIDBOX=0
:: PROCBBOX を解析して4つの座標を各変数に格納
  for /F "tokens=1-4 delims= " %%k in ("!PROCBBOX!") do (
    set BBLLX=%%k
    set BBLLY=%%l
    set BBURX=%%m
    set BBURY=%%n
  )
:: X 座標、Y 座標を比較し、ともに左下が右上より小さければ VALIDBOX=1(正常)
  if !BBLLX! lss !BBURX! (
    if !BBLLY! lss !BBURY! (
      set VALIDBOX=1
    )
  )
:: 以下、正常ならば TeX ソースに PROCBBOX を書き込んでクロップ

これだと、例えば以下のような BBOX 値は /h モードで警告が出てしまう。

%%BoundingBox: 29 70 86 126
%%HiResBoundingBox: 29.993765 70.104810 85.672122 125.944098

昨日わかったとおり「小数点を含む値は文字列とみなされ、辞書順比較にかけられる」からである。この場合は Y 座標がアウト。

実験(1):とりあえず小数点を削除

小数がだめなら小数点を削除したくなるのが筋だろう。幸い HiResBoundingBox は小数点以下6桁と一定なので、一見問題なさそうである。というわけで、以下のコードを加えてみる。

:: X 座標、Y 座標の比較直前に加える:小数点を削除して一つの整数に
  set BBLLX=!BBLLX:.=!
  set BBLLY=!BBLLY:.=!
  set BBURX=!BBURX:.=!
  set BBURY=!BBURY:.=!
:: 確認用コード
  echo !BBLLX! !BBLLY! !BBURX! !BBURY!
:: 以下、座標比較へ

これなら先ほどアウトだった HiResBoundingBox でも「29993765 70104810 85672122 125944098」という整数値になって比較可能だが、時に数値が大きくなりすぎる。実際に

%%BoundingBox: 10000 10399 12690 13255
%%HiResBoundingBox: 10000.012406 10399.992222 12689.054267 13254.032112

という BBOX 値では /h モードの場合に11桁に膨れ上がってしまう。これは、符号付きの32ビット値*1からはみ出すので

C:\>if 1000000000 lss 1100000000 echo yes
yes                                             <= OK

C:\>if 2000000000 lss 1100000000 echo yes
                                                <= OK
C:\>if 10000000000 lss 11000000000 echo yes
                                                <= NG
C:\>if 10000000000 equ 11000000000 echo yes
yes                                             <= NG

C:\>

というように数値比較できなくなってしまう(set /A の仕様とも合致)。つまり、単純に小数点を削除するのは数値が大きなりすぎるのでダメ。

実験(2):小数点以下を切り捨てる

通常の PDF なら BBOX 座標の整数部分が同じになることはありえないだろう*2。そこで、整数部分だけを比較するように方針転換。コマンドプロンプトは整数同士の除算では小数点以下を切り捨てるのだが、小数で同様のことができないか試す。

:: X 座標、Y 座標の比較直前に加える:小数点以下切り捨て[1]
  set /A BBLLX=!BBLLX!/1
  set /A BBLLY=!BBLLY!/1
  set /A BBURX=!BBURX!/1
  set /A BBURY=!BBURY!/1
:: 確認用コード
  echo !BBLLX! !BBLLY! !BBURX! !BBURY!
:: 以下、座標比較へ

この場合、/h モードでは4回「演算子がありません。」という警告が出て「10000 10399 12689 13254」のように整数値に丸められる。

警告が出るのは嫌なので、試しに事前にドットをカンマに置換してみよう。すると嬉しいことにカンマで“別々の数値”に分解したように扱われ、一つ目の数値に対して演算子が作用する。

:: X 座標、Y 座標の比較直前に加える:小数点以下切り捨て[2]
  set /A BBLLX=!BBLLX:.=,!/1
  set /A BBLLY=!BBLLY:.=,!/1
  set /A BBURX=!BBURX:.=,!/1
  set /A BBURY=!BBURY:.=,!/1
:: 確認用コード
  echo !BBLLX! !BBLLY! !BBURX! !BBURY!
:: 以下、座標比較へ

これでめでたく警告が消える… と思いきや、BBOX 値によっては「無効な数字です。数値定数は 10 進 (17 桁)、16 進 (0x11 桁)、または 8 進 (021 桁) です。」という別の警告が出る。

  • 警告なし
    • 「317.940037 257.020023 603.439997 383.759988」→ 317 257 603 383
    • 「198.870041 228.670024 563.749998 434.789987」→ 198 228 563 434
  • 警告1回
    • 「249.900039 126.610027 393.529980 259.019992」→ 249 126 393 259
    • 「29.993765 70.004810 85.672122 125.944098」→ 29 70 85 125
  • 警告2回
    • 「80.012406 99.992222 189.094269 154.082119」→ 80 99 189 154

共通点が分かるだろうか? 正解は「小数第一位が0で、かつその下の位に8または9がある場合」に警告が出る。理由は簡単で「リーディングゼロは8進数とみなされるから」。8と9は8進数ではあり得ないのだ。

そこで、リーディングゼロを起こさないように予め小数第一位より前に1を付加してみる。

:: X 座標、Y 座標の比較直前に加える:小数点以下切り捨て[3]
  set /A BBLLX=!BBLLX:.=,1!/1
  set /A BBLLY=!BBLLY:.=,1!/1
  set /A BBURX=!BBURX:.=,1!/1
  set /A BBURY=!BBURY:.=,1!/1
:: 確認用コード
  echo !BBLLX! !BBLLY! !BBURX! !BBURY!
:: 以下、座標比較へ

これなら小数点以下は必ず1で始まるので、常に10進数と判定される。

これで一応警告なしに HiResBoundingBox の整数部分を比較できそうである…ここまでくると、もはや藝人としかいえなくなってくるw

*1:すなわち -2147483648 から 2147483647 のこと。

*2:「BBOX 座標の整数部分が同じ」ということは、よほど図が極小でなければならない。そのような PDF が仮にあったとすれば、HiRes でなければ期待どおりにクロップするのは難しいだろう。

2015-08-11

コマンドプロンプトの大小比較ではまりやすい話

ZR さんの提案に基づく方法(一昨日の実験4)は失敗だったのだが、どうやら小数点を含む数値の比較は最上位の数字にも依存している?ように見える。

C:\>if 2.3 lss 13.5 echo correct.
                                      <= ?
C:\>if 2.3 gtr 13.5 echo correct.
correct.                              <= !

C:\>if 2.3 lss 3.5 echo correct.
correct.

C:\>if 32.3 lss 43.5 echo correct.
correct.

C:\>if 32.3 lss 243.5 echo correct.
                                      <= ?
C:\>if 32.3 gtr 243.5 echo correct.
correct.                              <= !

C:\>

これが仕様であるというよりは、むしろ「コマンドプロンプトは小数に対応していないので“未定義”」とみるのが正しいと思う。

このことに気づいたので、急遽 bcpdfcrop v0.2.2 を v0.2.3 にアップデートした。というのも、v0.1.9 で導入した「BBOX 値の左下と右上の座標が逆転していないかチェック」という方法は、小数点を含む HiRes の場合に必ずしも正しく判定されないのだ… 幸い v0.1.3 で導入した方法*1なら問題ないので、とりあえずこの変更だけ元に戻してみた。別の方法を考え中。

*1:BBOX が「すべてゼロ」の場合だけ不正とみなす、かつ HiRes が小数点以下6桁であることを仮定するという限定的な方法。

2015-08-10

バッチファイルで数値かどうか判定したいので…(続きの続き)

前回まででいろいろ検討したのだが、どれもあともう一息というところでボロが出る。というわけで、チョット書いてみた。

@echo off
setlocal
set ISNUMERIC=0
set AAA=%~1
for /F "tokens=1,2 delims=0123456789" %%i in ("%AAA%") do (
  set hoge=%%i
  set fuga=%%j
)
if "%hoge%"=="." (
  if "%fuga%"=="" (
    set ISNUMERIC=1
  )
) else (
  if "%hoge%"=="" (
    set ISNUMERIC=1
  )
)
if %ISNUMERIC% equ 1 (echo Numeric.) else (echo Not numeric.)

基本的に実験2の発展編。

  1. とりあえず数字を delims に指定して文字列を分解し、そのうち一つ目と二つ目を hoge と fuga に格納する。
  2. hoge はドット一つか空のいずれかでなければアウト。
  3. hoge がドット一つの場合は、fuga が空でなければアウト。

以上で、ドットが連続していることもドットが複数あることも排除できる。引数が空の場合を許さない状況(=初期値あり)で使えば、引数が数値かどうかを正しく判定できるはずである。手元ではうまくいっているようだが、いかがだろう?

都合の良いことに、上記のバッチファイルは整数か小数かも見分けることができる。

  • hoge が「.」・fuga が空→小数
  • hoge が空なら整数

ということが容易にわかる。したがって、ISNUMERIC の値を1と2とに振り分ければ、整数かどうかの判定にも応用できる。

2015-08-09

バッチファイルで数値かどうか判定したいので…(続き)

先日の実験の続き。

実験3:正規表現に頼る

正規表現を使うのがプログラミングの王道ともいうべき方法かもしれない。「数値かどうか」を判定する正規表現こんな風に書くはずである (Ruby):

/^[+-]?[0-9]+$/               <= 整数
/^[+-]?[0-9]*[\.]?[0-9]+$/    <= 整数または小数
/^[+-]?[0-9]*[\.]?[0-9]*$/    <= 整数または小数または未入力

しかし、コマンドプロンプトでは

* 0回以上の繰り返し
+ 1回以上の繰り返し
? 0回または1回の繰り返し

のうち“*”しか使えない。というわけで、未入力がありえない(=初期値を与えた)場合に数値かどうか判定するには以下のように書かざるを得ないだろう。

@echo off
setlocal
set ISNUMERIC=0
set AAA=%~1
echo %AAA%| findstr /x /r "^[+-]*[0-9]*[\.]*[0-9]*$" 1>nul
if %ERRORLEVEL% equ 0 set ISNUMERIC=1
if %ISNUMERIC% equ 1 (echo Numeric.) else (echo Not numeric.)
echo AAA=%AAA%

このバッチファイルでは「指定した正規表現に合致する値ならば %ERRORLEVEL% が0、そうでなければ %ERRORLEVEL% が1」になることを利用している*1。これを実行すると

C:\>isnum 123
Numeric.
AAA=123

C:\>isnum abcde
Not numeric.
AAA=abcde

C:\>isnum a12b
Not numeric.
AAA=a12b

C:\>isnum 1a2b
Not numeric.
AAA=1a2b

C:\>isnum 1.23
Numeric.
AAA=1.23

C:\>isnum 1.2.3
Not numeric.
AAA=1.2.3

C:\>

となり、状況は改善したようだ。ただし、この方法は?や+を*に変えたせいでボロが出やすい。たとえば

C:\>isnum 1..23
Numeric.
AAA=1..23

C:\>

要するに、一回しか繰り返してほしくないドットが2回繰り返されることを容認してしまう。この場合もやはり bcpdfcrop では pdfTeX に警告を吐かせてしまう。

実験4:TeX 言語プログラミングからの類推

まず ZR さんがつぶやいていた方法。“TeX 言語プログラミングの常識”だという「引数#1が単一の文字トークンであるという前提で、それが数字であるかを判定する方法」すなわち

\ifnum 2<1#1(真)\else(偽)\fi

から類推した方法なのだが、これをやると

というわけで、小数が入った場合になぜか期待どおりにならない。

@echo off
setlocal
set ISNUMERIC=0
set AAA=%~1
if 2 lss 1%AAA% set ISNUMERIC=1
if %ISNUMERIC% equ 1 (echo Numeric.) else (echo Not numeric.)
echo AAA=%AAA%

実行すると

C:\>isnum 123
Numeric.
AAA=123

C:\>isnum abcde
Not numeric.
AAA=abcde

C:\>isnum a12b
Not numeric.
AAA=a12b

C:\>isnum 1a2b
Not numeric.
AAA=1a2b

C:\>isnum 1.23
Not numeric.
AAA=1.23

C:\>

小数は演算できないという実験1と本質的には同じだろうか? 現状の bcpdfcrop は、整数値だけでなく正常な小数値の余白も pdfTeX がそのとおりに扱ってくれるので、その機能が失われるのはもったいなくて使いたくない。

続く

*1:なお、echo %aaa% の後にパイプの | を空白抜きで続けないと文字列が期待どおりにならないという仕様にもしばらくハマってしまった…

2015-08-08

テクノサイエンスカフェ

今日はテクノサイエンスカフェとかいう小中学生にラボの実験を体験してもらう企画だった。でも普段ラボ見学に来てもらうのとは違って、初めて行く場所で初めて使う顕微鏡を使い、前日に調製した試薬やタンパク質を持って行って実験してもらうという不利な条件で TA である僕らも勝手がわからず…

結局予想以上に実験がうまくいかなかった。そもそもピペットの使いかたから教えるのが難しい。僕らがラボで実験していてもたまに失敗するくらいのものを、初めての小学生にやらせるのはちょっと無茶だったかなあ。成功例を見てもらえなくて申し訳ないのと、こちらも残念。次につながるといいね*1

*1:研究の厳しさみたいなのが伝わったという意味ではいい経験になったかも…

2015-08-07

ラボ飲みのあと

教授とか助教とかみんなでラボ飲みのあと、なんと同期の音ゲー好きの人について行って、大勢でプレイを鑑賞した。僕は2回目だったんだけど、世界が違うからみんなで面白がってた。15人くらいで取り囲んでいてさぞ怪しかったろうw

2015-08-06

バッチファイルで数値かどうか判定したいので…

いま例の bcpdfcrop で「ページ範囲指定」や「余白指定」に数字以外が与えられた場合に対処できないか考えているのだが、どうやら厄介そうだ…

ググって出てきたのがこの辺とかこの辺。前者は「値が数値なら式を計算し、そうでなければ値を無効にする」という感じの仕様を巧みに使い、判定し、後者は強引に「数字と空白文字をすべて消して空になれば数値」と判定している。これらは一度試してみる価値がある。

実験1:とにかく値にゼロを足してみる

まずは前者の方法に倣ってみよう。記事からの類推で「元の値が数値ならばゼロを足しても値は不変・英字ならばゼロを足すと値が変わる」と予想したので、以下のバッチファイル「isnum.bat」を作ってみた:

@echo off
setlocal
set ISNUMERIC=0
set AAA=%~1
set /A BBB=%AAA%+0
if "%AAA%"=="%BBB%" set ISNUMERIC=1
if %ISNUMERIC% equ 1 (echo Numeric.) else (echo Not numeric.)
echo AAA=%AAA%, BBB=%BBB%

最後の行は確認のための出力。これを実行すると例えば

C:\>isnum 123
Numeric.
AAA=123, BBB=123

C:\>isnum abcde
Not numeric.
AAA=abcde, BBB=0

C:\>

ここまでは期待どおり「ゼロを足せば数字の場合は元の値が維持され、英字の場合は破棄されて0が入る」ように見える。これは使えるかもと思ったら

C:\>isnum 1.23
演算子がありません。
Not numeric.
AAA=1.23, BBB=1

C:\>isnum a12b
Not numeric.
AAA=a12b, BBB=0

C:\>isnum 1a2b
無効な数字です。数値定数は 10 進 (17 桁)、16 進 (0x11 桁)、
または 8 進 (021 桁) です。
Not numeric.
AAA=1a2b, BBB=

C:\>

まず、小数の演算はできないらしい。さらに、英字で始まる文字列は英字とみなす一方で、数字で始まる文字列は数字とみなしたがっているようだ… この場合、エラーが出て BBB に値をセットすることに失敗している。

実験2:数字をすべて消してみる

後者の方法に倣うと

@echo off
setlocal
set ISNUMERIC=0
set AAA=%~1
if "%AAA%" NEQ "" set AAA=%AAA:0=%
if "%AAA%" NEQ "" set AAA=%AAA:1=%
if "%AAA%" NEQ "" set AAA=%AAA:2=%
if "%AAA%" NEQ "" set AAA=%AAA:3=%
if "%AAA%" NEQ "" set AAA=%AAA:4=%
if "%AAA%" NEQ "" set AAA=%AAA:5=%
if "%AAA%" NEQ "" set AAA=%AAA:6=%
if "%AAA%" NEQ "" set AAA=%AAA:7=%
if "%AAA%" NEQ "" set AAA=%AAA:8=%
if "%AAA%" NEQ "" set AAA=%AAA:9=%
if "%AAA%"=="" set ISNUMERIC=1
if %ISNUMERIC% equ 1 (echo Numeric.) else (echo Not numeric.)
echo AAA=%AAA%

となるわけだが、もう少し簡潔にかつ小数にも対応できるように書くならドットも消すべきで、以下のようになるだろう*1

@echo off
setlocal
set ISNUMERIC=0
set AAA=%~1
for /F "tokens=1 delims=.0123456789" %%i in ("%AAA%") do set BBB=%%i
if "%BBB%"=="" set ISNUMERIC=1
if %ISNUMERIC% equ 1 (echo Numeric.) else (echo Not numeric.)
echo AAA=%AAA%, BBB=%BBB%

これを実行すると

C:\>isnum 123
Numeric.
AAA=123, BBB=

C:\>isnum abcde
Not numeric.
AAA=abcde, BBB=abcde

C:\>isnum a12b
Not numeric.
AAA=a12b, BBB=a

C:\>isnum 1a2b
Not numeric.
AAA=1a2b, BBB=a

C:\>isnum 1.23
Numeric.
AAA=1.23, BBB=

C:\>

ここまでは期待どおりであり、一歩前進。しかし

C:\>isnum 1.2.3
Numeric.
AAA=1.2.3, BBB=

C:\>

ドットが複数あると bcpdfcrop の場合は pdfTeX のソース処理中に警告が出て、余分な文字(今回は .3 のこと)がページに出力されてしまう。このような場合に対処するには不十分だ。

検討は続く…

コマンドプロンプトで数値かどうか判断する方法として検索に引っかかった方法はまだ満足できるものではなかった。というわけで、他の方法(正規表現の利用*2など)も検討してみることにする→次回

ところで、正規表現を使えば16進数は0xで始まるので排除できるが、8進数は0で始まるので排除できない。別にいいんだけど、例えば余白に020とか書くと10進数の「20」ではなく8進数の「20」すなわち10進数の16になってしまうのであまり直感的でない。このリーディングゼロが8進数になってしまうことへの対処がこことかに凄い方法で書かれていて驚き。そんなことしないといけないのか…

*1:もちろん delims で分割した最初の要素だけを取り出しているので“数字を消す”とは処理が異なる。とはいえ、今回の“要素が消えること”を目的としていれば差はほとんどない。

*2:そもそもこの辺とかこの辺とかを見て、正規表現で検索できる findstr というコマンドがあることを初めて知った…

2015-08-05

凸五角形

記事をゆっくり読めないまま忘れそうなので、ここでちょっとメモ…もう一週間も前のニュースだけど、読む余裕がない…

2015-08-04

TeX2img for Mac 1.9.6

TeX2img の Mac 版が更新された。先日の bcpdfcrop の修正を機に始まった「白紙が含まれる場合にどう画像化するか」という部分を詰めた (#21) のと、Windows 版 1.5.2 で新設されたコンパイル中断機能 (#16) が主で、ユーザに見える変更は細かいエディタ周りの拡張 (#22) くらいというアップデートだが、内部処理の変更を相当行ったため、たぶん一番大変だったはず… Windows 版も近々、白紙の処理を改善してリリースされる予定。
追記 (2015-08-05):TeX2img for Mac 1.9.6 には少々バグが混入していたので、急遽 1.9.7 がリリースされた。

Mac 版は画像変換スキーム(メインブログ参照)の分岐が複雑で、その一つ一つに白紙への例外処理を加えた。

  • 余白が0に指定された場合は、gs の bbox デバイスが BoundingBox を 0 0 0 0 と返してくるので、キャンバスサイズが0となってしまうためエラーを返す
  • 余白が縦横ともに0より大きい値で指定された場合は、真っ白なキャンバスが存在できるので画像化を継続する

ということなのだが、スキームが多い分(PDF のアウトライン化とテキスト保持、ビットマップ画像の画質優先モードと速度優先モード、etc.)見落としのないように細かくテストする必要があった。また、中断機能の実装ではコンパイル実行中に GUI 操作が可能となるようにマルチスレッド化する必要があり、全体を精査して一つ残らず分離作業を行っていただいたことになる。というわけで、見た目をはるかに上回る苦労の成果です。

中断機能が役に立つのは、たとえば

 \def\hoge{\hoge}\hoge

のような制御綴の展開で無限ループに陥った場合など。Mac 版では Command + . という Excel マクロや AppleScript の中断と同じショートカットキーが割り当てられた(Windows 版ではタイプセットと同じく Ctrl + T であり、これは TeXworks と類似している)。

さらに、以前問題になっていた「少々のエラーは無視して画像化を強行する」については非推奨ラベルを付けるようになっていた (#15) が、さらに実際にエラーを無視して強行した場合は警告を出すようにした。これで意図しない画像が出てもそれは画像化を強行したからだと気づきやすくなり、誤解を防げるはず。
追記 (2015-08-05):よく誤解されるが、TeX2img はあらゆる LaTeX ソースを画像化するためのツールである。上記の画像化強行によるおかしな画像は数式環境に入れていなかったために起きたわけだが、このように「数式だけ画像化したい」場合は TeX2img FAQ に書いてある方法もしくは bxenclose パッケージを使うとよい。

ちなみに、バッチ藝人のほうは…

Windows バッチファイルで pdfcrop できる「bcpdfcrop」の開発は、なんだか楽しくなってしまったのでちょこちょこ更新している。GitHub に開発場所を移して以来、毎日のように何かしらテストして気になったところを直しているので、だいぶ安定したはず。オリジナルの Perl スクリプトに比べてできることは少ないが

  • Perl 処理系をインストールせずに済む
  • ページ範囲指定ができる
  • 複数ページの場合に分割出力ができる(/s オプション)

というメリットがあるので、PDF の余白を楽に切り取りたい人にとっては本家より使いやすいかもしれない(!?)と期待。僕自身はもともと本家 pdfcrop を使っていたのだが、最近は上に挙げた追加機能が案外便利だと思えてきたので自作 bcpdfcrop に乗り換えてしまった。Windows の方は是非。

2015-08-03

「円グラフ」について

「円グラフは安易に使うべきではない」の話

そういえば、先日これまた拡散されてきた天野由貴さんの「情報デザインを意識したスライド作成入門」(PDF file) に対しても*1、円グラフに関する記述があったことに対して意見が出ていた気がする。今回の「円グラフを安易に使ってはいけない」の記事について思うところがあったので、つぶやいてみた。

そういいながら、僕自身は円グラフをほとんど使っていない。確かに、円グラフをみて順序関係を角度で判断するのは難しいし、極端に大きなものと極端に小さなものがあれば区別がつく程度である。しかし、例の記事で「円グラフを棒グラフに」とした記述に疑問があった。円グラフを棒グラフに直す際の注意点が書かれていないのだ。



円グラフの長所(?)は、よほど捏造しないかぎり「全体を足せば100%*2」になるということである。これはデータの数値を書き変えないかぎり、誤魔化しようがない。なので、棒グラフのかきかたを知らないのであれば、むしろ円グラフのほうがよい(マシだ)と思うのだ。例の記事ではこの点に触れず、円グラフのすべての要素を素直に棒グラフに置き換えている。これならばまあ良い。
f:id:acetaminophen:20150803230720p:image
ただし、円グラフのほうも棒グラフのほうも「その他」すなわち少数の製品の足し合わせを途中に割り込ませているので、ここは問題だと思う。「その他」は割合の大小にかかわらず、最後に配置すべきであろう:
f:id:acetaminophen:20150803234314p:image
しかし、同じデータを使ったとしても、たとえば HDD レコーダー担当者が「我が社の売り上げの実に16%を HDD レコーダーが占めており…」などと言って次の赤枠内のようなグラフだけを示したとするとどうだろう。
f:id:acetaminophen:20150803234927p:image
普通の人はわざわざ割合を足して100%になるかどうか計算しないかもしれない。そうすると、冷蔵庫や洗濯機に比べて HDD レコーダーが重要であるという情報だけを見せられていることになり、大きな「その他」が隠されてしまう。当然ながら「その他」があまりに大きいと調査方法自体が適切なのかどうか疑われかねないが、気づかなければ占めたものと考える人ならば印象操作のためにこのようなグラフを示す場合があるかもしれない。上の例は相当極端だが、下のような場合に(「その他」にテレビ関連をすべて丸め込んでみたり、さらに進んで赤枠内だけを示したりとか)とするともはや気づく人は少なくなるだろう。
f:id:acetaminophen:20150804004203p:image
さらに印象操作しようと思ったならば、棒グラフなら下端を0でなくずらすことだってできてしまう。これはしばしば小さな差を誇大に示すためによく用いられる手法であるが、よくない。
f:id:acetaminophen:20150804000100p:image
棒グラフがこのように容易に“捏造とはいえない印象操作”ができてしまう一方、そういう点では円グラフのほうが印象操作しづらい。円にするためには確実に100%が必要であるし、数値をいじらないかぎり100%でないのに全体らしく見せることはできないはずだ。そういうわけで、棒グラフを正しくかけないのであれば、円グラフのほうがまだマシといえよう。

よって、円グラフを棒グラフにしようというだけでは不十分で

対象とすべき項目をすべて列挙し、0を起点にして順位にしたがって棒を並べる(「その他」は最後に端に置く;できれば「その他」は第一位の項目より小さい方が好ましい)

という原則が必要ではなかろうか。この点に触れずして円グラフを排除しようとするのはいかがなものか。棒グラフのかきかたは、Excel のグラフ機能が勝手に起点を0にしないデフォルトが働いたりすることもあって誤りやすい(円グラフなら知識がなくてもグラフ自体はふつう問題なくかけてしまう)。そのような過ちを犯すことのないよう、注意して使うべきである。

僕の一連のツイートは別に円グラフを好んで使うべきと主張したものではないので、誤解しないでいただきたい。データを可視化することは有意義であるが、情報をありのままに伝えるのに適切な表しかたはその都度考えるべきである。円グラフは「賛成」「反対」「どちらでもない」のような過半数を示すときにはむしろわかりやすいし、要素が増えすぎると感覚がつかみづらいのは確かである。どのグラフをかく場合も、その正しいかきかた(特に「割合」なら全部の要素を列挙することを忘れずに)を身につけなければならない。

ちなみに、3D 円グラフや 3D 棒グラフは(例の記事と同意で)まったくもって論外である。これは遠近法を悪用した印象操作以外の何物でもない。というわけで、3D 円グラフや 3D 棒グラフを見かけた場合は、まず最初に「あっ印象操作だ!」と思うようにしましょう。例の記事の感想で気になったのは、見受けられた感想の多くは「円グラフは印象操作なので、使ってはいけないんだな!」というものだった。印象操作に使われるのは 3D グラフ(3D 円グラフ・3D 棒グラフ)であって、2D 円グラフが良くない理由は「割合の違いがパッと見て分かりにくいから」である。円グラフ=印象操作のような短絡的な感想は持たないでいただきたい。

参考になる奥村先生のブログも挙げておこう:

*1:あの資料は僕も素晴らしいと思う。一見の価値あり。

*2:もちろん四捨五入の関係で99%とか102%になることはあるが、それは誤差の範囲である。

2015-08-02

一日出かけていました

日曜日はほぼ一日じゅう外にいたので、メールは全く読めていないし、Twitter もほとんどタイムラインを見ていなかった。というわけで大量のメールを今読んでいる…

2015-08-01

bcpdfcrop の安定化へ向けて

最近毎日更新している bcpdfcrop.bat だが、予想以上にエラーハンドリングが甘い気がしてきた。今日とりあえず v0.1.4 で「必要なプログラムが実行されなかった場合」にエラーを吐いて終了するように変更。
特に問題だったのが、rungs が実行できなかった場合に勝手にバッチが落ちる現象。そもそも gs が BoundingBox 情報を標準エラー出力に吐くのが曲者で

  • gs が実行できたら標準エラー出力に gs のBBOX 情報が入る
  • gs が実行できなかったら標準エラー出力に OS からのエラーメッセージが入る

という状態である。ゆえに、これを標準出力にリダイレクトしてパイプで find する*1と、結果は

  • gs が実行できたらパイプで一時ファイルに BBOX 情報だけ抜き出される
  • gs が実行できなかったらパイプが切断されて落ちる

となる。これは良くないので、パイプを使わずに一旦標準エラー出力をファイルに吐き、それを type して find することに。こうすれば落ちる心配はない。で、「BBOX 情報の抜き出しが空」かつ「標準エラーのファイルサイズが0でない場合」というのはきっと OS のエラーか gs のエラーが返っているはずなので、これを type で表示してバッチを抜ければ、エラーメッセージを見せることができる。

ただ、pdfTeX は必須だけれど、ほかのプログラムの失敗を理由にバッチを終了させるのには疑問がある。extractbb は必ずしも必要とは言えない*2し、gs で BBOX 値を取得できなかったとしても、そのまま継続すれば pdftk ライクなページ抽出ができそうだと思う。というわけで、そちらの方向で実装してもいいかもしれないと考え中。

*1:BoundingBox と HiResBoundingBox の使い分けのために、tcpdfcrop v0.9 で標準出力にリダイレクト (2>&1) して find するようにしたわけだ。

*2:PDF のバージョンとか前ページ数とかの規定値さえ予め与えておけば、わざわざバッチを抜けて終わらせるほど致命的ではない。