在 R 中创建带有工具提示的 pdf
Posted
技术标签:
【中文标题】在 R 中创建带有工具提示的 pdf【英文标题】:Create pdf with tooltips in R 【发布时间】:2011-06-09 04:08:06 【问题描述】:简单问题:有没有办法在 pdf 文件中从 R 绘制图形并包含工具提示?
【问题讨论】:
这可能很有趣:jackman.stanford.edu/blog/?p=1507 这是 SVG,但它是某种东西。 很好的答案,但没有一个是最新的——tikzDevice 或 pdf2 都没有得到维护。目前有什么方法吗? 我认为 tikzdevice 仍然可以通过 rforge 安装? 【参考方案1】:嗯,不是 pdf,但您可以使用 SVGAnnotation 或 RSVGTipsDevice 包以 svg 格式包含工具提示(以及其他)。
【讨论】:
谢谢,但我已经熟悉 SVGTipsDevice。我想知道 pdf,因为我更喜欢这种格式,而且这种格式确实允许工具提示。 @Sacha Epskamp - 抱歉,我不知道。【参考方案2】:简单问题:有没有办法在 pdf 文件中从 R 绘制图形并包含工具提示?
总有办法。但魔鬼在细节中,所以真正的问题是:你愿意动手吗?
PDF 确实支持某些类型的对象(例如超链接)的工具提示。因此,如果有一种方法可以插入原始 PDF 语句,指示在绘图中的某个位置应该有一个类似超链接的对象,那么就有一种方法可以弹出工具提示。
现在,我知道生成和编译原始 PDF 语句的唯一方法是使用 TeX 创建文档。肯定有其他方法可以做到这一点,但这是我熟悉的一种。以下示例使用我和 Cameron Bracken 编写的图形设备 tikzDevice,将 R 图形渲染为 LaTeX 代码。 tikzDevice 初步支持通过tikzAnnotate
函数将任意 LaTeX 代码注入图形输出流——我们将使用它来将 PDF 标注放入绘图中。
涉及的步骤是:
-
设置 LaTeX 宏以生成生成标注所需的 PDF 命令。
设置一个 R 函数,该函数使用
tikzAnnotate
在绘图中的特定点调用 LaTeX 宏。
???
利润!
在下面的示例中,第 2 步附有一个主要警告。所使用的坐标计算仅适用于基本图形,不适用于 ggplot2 等网格图形。
简单的工具提示
步骤 1
tikzDevice 允许您创建包含执行任意 LaTeX 命令的 R 图形。通常这样做是为了将$\alpha$
之类的内容插入到绘图标题中,以生成希腊字母、α 或复杂方程。在这里,我们将使用此功能来调用一些原始 PDF 巫术。
您希望在生成 tikzDevice 图形期间可用的任何 LaTeX 宏都需要通过设置 tikzLatexPackages
选项预先定义。在这里,我们将在该声明中添加一些内容:
require(tikzDevice) # So that default options are set
options(tikzLatexPackages = c(
getOption('tikzLatexPackages'), # The original contents: required stuff
# Avert your eyes for a sec, all will be explained below
"\\def\\tooltiptarget\\phantom\\rule1mm1mm",
"\\newbox\\tempboxa\\setbox\\tempboxa=\\hbox\\immediate\\pdfxform\\tempboxa \\edef\\emptyicon\\the\\pdflastxform",
"\\newcommand\\tooltip[1]\\pdfstartlink user/Subtype /Text/Contents (#1)/AP <</N \\emptyicon\\space 0 R >>\\tooltiptarget\\pdfendlink"
))
如果所有引用的废话都由关心可读性的人写成 LaTeX 代码,它看起来像这样:
\def\tooltiptarget\phantom\rule1mm1mm
\newbox\tempboxa
\setbox\tempboxa=\hbox
\immediate\pdfxform\tempboxa
\edef\emptyicon\the\pdflastxform
\newcommand\tooltip[1]%
\pdfstartlink user%
/Subtype /Text
/Contents (#1)
/AP <<
/N \emptyicon\space 0 R
>>
%
\tooltiptarget%
\pdfendlink%
对于那些从未涉足过并在 TeX 中进行过一些“编程”的程序员,这里是对上述代码的逐个介绍(无论如何,据我所知,TeX 会变得非常奇怪—— - 尤其是当你带着它进入战壕时):
第 1 行: 定义一个不可见的对象 tooltiptarget
,它是一个 1mm x 1mm 的矩形(规则)。这将是我们将用来检测鼠标悬停的屏幕区域。
第 2 行: 创建一个新框,类似于排版材料的“页面片段”。可以包含几乎任何东西,包括其他框(有点像 R 列表)。叫它tempboxa
。
第 3 行: 分配 tempboxa
的内容以包含一个使用水平布局排列其内容的空框(这并不重要,可以使用 vbox 或其他框) .
第 4 行: 使用 tempboxa
的内容创建 PDF 表单 XObject。 PDF 文件可以使用 Form XObject 来存储可以反复使用的图形,例如徽标。在这里,我们正在创建一个“空白图标”,稍后我们可以使用它来减少视觉混乱。 TeX 推迟输出操作,例如将对象写入 PDF 文件,直到满足某些条件——例如页面已填满。立即确保此操作不会被延迟。
第 5 行:该行捕获一个整数值,用作对我们刚刚创建的 PDF XObject 的引用,并将其命名为 emptyicon
。
第 6 行: 开始定义一个名为 tooltip 的新宏,该宏接受 1 个参数,该参数在宏主体中称为 #1
。宏中的每一行都以注释字符 %
结尾,以防止 TeX 注意到为便于阅读而添加的换行符(换行符在宏中可能会产生奇怪的效果)。
第 7 行: 输出原始 PDF 命令 (pdfstartlink)。这开始创建一个新的 PDF 注释对象 (\Type \Annot
),其中大约有 20 种不同的子类型——其中包括超链接。其后的每一行都包含带有几个 TeX 宏的原始 PDF 标记。
第 8 行: 声明我们将要使用的注释子类型。在这里,我将使用纯文本注释,例如评论或便笺。
第 9 行: 声明注释的内容。这将是我们工具提示的内容,并设置为#1
,即工具提示宏的参数。
第 10-12 行:通常文本注释用图标(例如便笺)标记,以突出它们在文本中的位置。如果我们允许它在我们的图表上飞溅小便签,这种行为将导致视觉混乱。这里我们使用外观数组 (\AP << >>
) 将“正常”注释图标 (\N
) 设置为我们之前创建的空白图标。我们存储在emptyicon
和0 R
中的整数构成了对我们在第4 行使用空框创建的Form XObject 的引用。
第 14 行: 如果我们要创建一个普通的超链接,这里是文本/图像/任何可以用作链接正文的地方。相反,我们插入tooltiptarget
,这是我们不可见的幻像对象,它不会显示在屏幕上,但会对鼠标悬停做出反应。
第二步
好的,既然我们已经告诉 LaTeX 如何创建工具提示,是时候让它们在 R 中可用了。这涉及编写一个函数,该函数将获取我们图形上的坐标,例如 (1,1),然后将它们转换进入画布或“设备”坐标。在 tikzDevice 的情况下,所需的测量是绘图区域绝对左下角的“TeX 点”(1/72.27 英寸)。幸运的是,对于基本图形,有一些方便的函数可以为我们计算。网格图形的工作方式不同,因此此处示例中采用的方法不适用于它们。
R 函数的最后一项任务是调用tikzAnnotate
将 TikZ“节点”插入到位于我们计算的坐标处的输出流中。节点可以包含任意 TeX 命令,在这种情况下,我们将调用 tooltip
。
这是一个包含上述功能的 R 函数:
place_PDF_tooltip <- function(x, y, text)
# Calculate coordinates
tikzX <- round(grconvertX(x, to = "device"), 2)
tikzY <- round(grconvertY(y, to = "device"), 2)
# Insert node
tikzAnnotate(paste(
"\\node at (", tikzX, ",", tikzY, ") ",
"\\tooltip", text, ";",
sep = ''
))
invisible()
第三步
在情节上尝试一下:
# standAlone creates a complete LaTeX document. Default output makes
# stripped-down graphs ment for inclusion in other LaTeX documents
tikz('tooltips_ahoy.tex', standAlone = TRUE)
plot(1,1)
place_PDF_tooltip(1,1, 'Hello, World!')
dev.off()
require(tools)
texi2dvi('tooltips_ahoy.tex', pdf = TRUE)
第四步
看结果(download a pdf):
高级工具提示
步骤 1
既然我们已经有了简单的工具提示,为什么不把它调到 11 呢?在前面的示例中,我们使用了一个空的hbox
来去除工具提示图标。但是如果我们在那个盒子里放了一些东西,比如文字或图画呢?如果有办法让图标仅在鼠标悬停事件期间出现怎么办?
下面的 TeX 宏有点粗糙,但它表明这是可能的:
\usetikzlibraryshapes.callouts
\tikzsettooltip/.style =
rectangle callout,
draw,
callout absolute pointer = (-2em, 1em)
\def\tooltiptarget\phantom\rule1mm1mm
\newbox\tempboxa
\newcommand\tooltip[1]%
\def\tooltipcallout\tikz\node[tooltip]#1;%
\setbox\tempboxa=\hbox\phantom\tooltipcallout%
\immediate\pdfxform\tempboxa%
\edef\emptyicon\the\pdflastxform%
\setbox\tempboxa=\hbox\tooltipcallout%
\immediate\pdfxform\tempboxa%
\edef\tooltipicon\the\pdflastxform%
\pdfstartlink user%
/Subtype /Text
/Contents (#1)
/AP <<
/N \emptyicon\space 0 R
/R \tooltipicon\space 0 R
>>
%
\tooltiptarget%
\pdfendlink%
与简单标注相比,做了以下修改。
shapes.callouts
库已加载,其中包含 TikZ 在绘制标注框时使用的模板。
定义了一个 tooltip
样式,其中包含一些 TikZ 图形样板。它指定一个可见的矩形标注框 (draw
)。 callout absolute pointer
业务是一个 hack,因为此时我已经喝了太多啤酒,无法弄清楚如何使用动态生成的 PDF 原语放置注释图标。这依赖于图标在其左上角的默认锚定,因此将标注框的指针拉向该位置。结果是这些框将始终显示在指针的右下方,如果标注文本足够长,它们将看起来不正确。
在宏内部,工具提示是使用填充到tooltipcallout
宏中的一次性tikz
命令生成的。从tooltipcallout
生成一个表单XObject 并分配给tooltipicon
。
emptyicon
也是通过评估 phantom
内部的 tooltipcallout
动态生成的。这是必需的,因为默认图标的大小显然设置了可用于翻转图标的视口。
生成 PDF 命令时,会在 /AP
数组中添加一个新行,/R
用于翻转,它使用 tooltipicon
引用的 XObject。
准备消费的R版本是:
require(tikzDevice)
options(tikzLatexPackages = c(
getOption('tikzLatexPackages'),
"\\usetikzlibraryshapes.callouts",
"\\tikzsettooltip/.style = rectangle callout,draw,callout absolute pointer = (-2em, 1em)",
"\\def\\tooltiptarget\\phantom\\rule1mm1mm",
"\\newbox\\tempboxa",
"\\newcommand\\tooltip[1]\\def\\tooltipcallout\\tikz\\node[tooltip]#1;\\setbox\\tempboxa=\\hbox\\phantom\\tooltipcallout\\immediate\\pdfxform\\tempboxa\\edef\\emptyicon\\the\\pdflastxform\\setbox\\tempboxa=\\hbox\\tooltipcallout\\immediate\\pdfxform\\tempboxa\\edef\\tooltipicon\\the\\pdflastxform\\pdfstartlink user/Subtype /Text/Contents (#1)/AP <</N \\emptyicon\\space 0 R/R \\tooltipicon\\space 0 R>>\\tooltiptarget\\pdfendlink"
))
第二步
R级代码不变。
第三步
让我们尝试一个稍微复杂一点的图表:
tikz('tooltips_with_callouts.tex', standAlone = TRUE)
x <- 1:10
y <- runif(10, 0, 10)
plot(x,y)
place_PDF_tooltip(x,y,x)
dev.off()
require(tools)
texi2dvi('tooltips_with_callouts.tex', pdf = TRUE)
第四步
结果(download a PDF):
如您所见,显示的工具提示和标注都存在问题。设置\Contents ()
使工具提示有一个空字符串不会有任何帮助。这可能可以通过使用不同的注释类型来解决,但我现在不会花更多的时间。
注意事项
很多 TeX 命令都包含反斜杠,在 R 代码中表达内容时需要将反斜杠加倍。
某些字符是 TeX 的特殊字符,例如_
、^
、%
、complete list here,您需要确保在使用 tikzDevice 时正确转义这些字符。
尽管 PDF 应该优于 html,因为它具有跨平台的一致呈现,但根据使用的查看器,您的工作量会有很大差异。屏幕截图是在 OS X 上的 Acrobat 8 中拍摄的,Preview 也做得还不错,但没有呈现翻转标注。在 Linux 上,xpdf 不渲染任何内容,并且 okular 显示了一个工具提示,但没有抑制工具提示图标,而是显示了一个在绘图中间看起来有点花哨的股票图标。
替代实现
cooltooltips 和 fancytooltips 是提供工具提示功能的 LaTeX 包,可能可以从 tikzDevice 使用。上述示例中使用的一些想法来自cooltooltips。
结论性想法
这值得吗?好吧,到最后我确实学到了两件事:
我不是 PDF 专家,我必须搜索几个邮件列表并消化 700 多页规范的某些部分,才能回答“这可能吗?”这个问题。更别说想出一个实现了。
我不是 SVG 专家,但我知道 SVG 中的工具提示不是“这可能吗?”的问题。而是“how sexy do you want it to look?”。
鉴于这一观察,我说现在是时候让 PDF 进入日落并采用 700 页的规范了。我们需要一种新的页面描述标记语言,我个人希望SVG Print 能够完成这项工作。如果规范足够好,我什至会接受Adobe Mars。只要给我们一个基于 XML 的格式,它可以利用当今 javascript 库的全部功能,然后就可以开始一些真正的创新。 LuaTeX 后端将是一个不错的奖励。
参考文献
tikzDevice: 一种将 R 图形输出为 LaTeX 代码的设备。 comp.text.tex: 深入了解深奥的 TeX 细节的来源。 Herbert Voß 和 Mycroft 的帖子提供了实施思路。 The pdfTeX manual: 可以生成原始 PDF 代码的 TeX 命令的信息来源,例如\pdfstartlink
TeX by Topic: 低级 TeX 详细信息的入门手册,例如 \immediate
的实际工作原理。
The Adobe PDF Specification: 有关 PDF 原语的大量细节。
The TikZ Manual: 很可能是有史以来最好的开源文档示例。
【讨论】:
【参考方案3】:pdf2 包对我来说很好用。 (https://r-forge.r-project.org/R/?group_id=193)。您可以在常规文本命令中包含一个“弹出窗口”。它不是 2.14 的最新版本,但我想他很快就会接受它。
text(x,y,'硬拷贝文本',popup='工具提示文本')
【讨论】:
澄清:适用于您,但仅适用于旧版本的 R?可悲的是,似乎根本不适用于 2.15。以上是关于在 R 中创建带有工具提示的 pdf的主要内容,如果未能解决你的问题,请参考以下文章