灯火阑珊处

谢益辉 2010-12-24

我回忆了好半天,还是想不起当初我为什么对LyX留下了一个错误的印象:它生成的LaTeX文档的前四行是无效的。即这样的代码:

\batchmode
\makeatletter
\def\input@path{\string"path/to/some where/\string"/}
\makeatother

当年我并没有仔细研究第三行,但凭感觉,它是用来定义文档中的外部文件的输入路径的,比如\includegraphics{}的根路径。这个感觉并没有错,但当年阴差阳错失败了。我发现LyX的文件名弄乱机制(filename mangling)是因为当时想在Sweave中输出动画,因而需要使用animate包和\animategraphics{}命令,但是死活由于找不到输入文件而报错,我花了好几天时间,终于发现原来有这么个机制,以及LyX的编译过程(先复制到临时文件夹再编译)。于是我只好想办法把动画文件先复制到临时文件夹再编译,这当然不是个好办法。还有Sweave,我都是用R脚本把需要的文件复制到LyX的临时文件夹下再让LyX编译,比如需要读入的数据和需要引用的图片文件等。这都是为了让LyX不要抱怨找不到文件。

今天在考虑animation包中的saveLatex()如何在Sweave中使用,于是再度看了一下LaTeX的animate宏包的文档,看着看着,突然见到其中有个单词“Important”可以闪动,于是好奇它是怎么做到的,自然也就把源文档找出来看;打开源文档,无意看到这么一句:

\graphicspath{files/}

凭直觉,我觉得这是指定图片文件的根路径,即:文档中的图片引用都以files/为基准,在这个文件夹下去寻找。抬手Google了一下,没错,是这样。我想,这不就是我很久以来想要的东西么,只要定义了图片的输入路径,就不必发愁在LyX文档目录和临时文件目录下拷来拷去了。试了一下,对图片\includegraphics{}的确管用,但由于我用pgfSweave,图片都是用\input{}的方式,这招不管用。

恍惚间,想起了本文开头的那几行命令,琢磨着为什么它们不管用呢,难道有bug?再在LyX中输入了几行LaTeX代码试了试,\includegraphics{}\input{}都不写绝对路径,只写相对于LyX文档的相对路径,编译,居然成功了!这简直是个灵异事件。

这下R代码中可以setwd()到文档目录了,解决了许久以来的一大麻烦——这是跟人说不清道不明的麻烦。缓存也有了(包括R对象的缓存和图片的缓存),代码高亮也有了,这下可以理直气壮说pgfSweave好用了。

———————–过了一天的分割线———————–

灯火阑珊处之二:路径的问题解决之后本以为天下太平了,结果新的问题来了。如果使用external = TRUE来让pgfSweave缓存图片,那么它会将tikz图片转化为PDF图片(以便下次编译的时候直接引用PDF而不必重新生成一遍tikz,这就是图片能够被缓存的原理),而这些tikz文件默认不是UTF-8编码的,而且我也没有办法控制它的编码。研究了半天,只好用R把tikz读进来用iconv()手工转一下编码,于是中文的图片文件也可以正确生成了。但由编码问题导致的悲剧还不只是图片,highlight包对R代码高亮的时候如果遇到中文也死翘翘,关于这一点,实在太难找出原因,因为这个过程中同时涉及到pgfSweave包、highlight包和依赖的包——当错误来源有多种可能的时候查错就很可怕了。最初我以为是我的tidy.source()函数有问题,改了半天,未果;然后发现把关掉高亮highlight = FALSE之后中文文档可以跑pgfSweave,这说明不是tidy.source()的问题;经过艰苦卓绝的追逐,终于发现问题来自parser包的parser()函数,它里面涉及到代码读写进出文件,这个问题就像我的formatR包一样,在读写文件过程中,文本的编码信息就丢失了,所以需要在读写之前把编码改成自然编码options(encoding = "native.enc")。搞了半天,原来是个老问题。给作者提交了一个patch文件,不知下一个版本是否会更新。

——————–现在的pgfSweave+LyX状态——————–

说实话,我一直以来并没有理解图片的缓存是怎么回事。这两天鼓起勇气打开那七百多页的pgf手册瞄了两眼,才真的明白了。现在我的自动配置脚本已经做了大幅度更新,就速度而言基本上已经优化到最佳状态,例如设置默认图形设备为空设备(这样相比起默认的无用的PDF设备要更节约时间);将tikz字形字典的目录固定到了文档目录下,这样tikz设备也不必每次都去不同的地方查询字形信息;大量减少了文件的复制,编译的时候只有少数几个文件需要在当前目录和临时目录下互拷;等等。现在的LyX/Sweave(中文)文档,终于完全自由了。