【问题标题】:Create pdf with tooltips in R在 R 中创建带有工具提示的 pdf
【发布时间】:2011-06-09 04:08:06
【问题描述】:

简单问题:有没有办法在 pdf 文件中从 R 绘制图形并包含工具提示?

【问题讨论】:

  • 这可能很有趣:jackman.stanford.edu/blog/?p=1507 这是 SVG,但它是某种东西。
  • 很好的答案,但没有一个是最新的——tikzDevice 或 pdf2 都没有得到维护。目前有什么方法吗?
  • 我认为 tikzdevice 仍然可以通过 rforge 安装?

标签: pdf r tooltip


【解决方案1】:

嗯,不是 pdf,但您可以使用 SVGAnnotationRSVGTipsDevice 包以 svg 格式包含工具提示(以及其他)。

【讨论】:

  • 谢谢,但我已经熟悉 SVGTipsDevice。我想知道 pdf,因为我更喜欢这种格式,而且这种格式确实允许工具提示。
  • @Sacha Epskamp - 抱歉,我不知道。
【解决方案2】:

简单问题:有没有办法在 pdf 文件中从 R 绘制图形并包含工具提示?

总有办法。但魔鬼在细节中,所以真正的问题是:你愿意动手吗?

PDF 确实支持某些类型的对象(例如超链接)的工具提示。因此,如果有一种方法可以插入原始 PDF 语句,指示在绘图中的某个位置应该有一个类似超链接的对象,那么就有一种方法可以弹出工具提示。

现在,我知道生成和编译原始 PDF 语句的唯一方法是使用 TeX 创建文档。肯定有其他方法可以做到这一点,但这是我熟悉的一种。以下示例使用我和 Cameron Bracken 编写的图形设备 tikzDevice,将 R 图形渲染为 LaTeX 代码。 tikzDevice 初步支持通过tikzAnnotate 函数将任意 LaTeX 代码注入图形输出流——我们将使用它来将 PDF 标注放入绘图中。

涉及的步骤是:

  1. 设置 LaTeX 宏以生成生成标注所需的 PDF 命令。
  2. 设置一个 R 函数,该函数使用 tikzAnnotate 在绘图中的特定点调用 LaTeX 宏。
  3. ???
  4. 利润!

在下面的示例中,第 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{\\rule{1mm}{1mm}}}",
    "\\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{\rule{1mm}{1mm}}}

\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 &lt;&lt; &gt;&gt;) 将“正常”注释图标 (\N) 设置为我们之前创建的空白图标。我们存储在emptyicon0 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 宏有点粗糙,但它表明这是可能的:

\usetikzlibrary{shapes.callouts}
\tikzset{tooltip/.style = {
  rectangle callout, 
  draw,
  callout absolute pointer = {(-2em, 1em)}
}}

\def\tooltiptarget{\phantom{\rule{1mm}{1mm}}}    
\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'),
  "\\usetikzlibrary{shapes.callouts}",
  "\\tikzset{tooltip/.style = {rectangle callout,draw,callout absolute pointer = {(-2em, 1em)}}}",
  "\\def\\tooltiptarget{\\phantom{\\rule{1mm}{1mm}}}",
  "\\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 显示了一个工具提示,但没有抑制工具提示图标,而是显示了一个在绘图中间看起来有点花哨的股票图标。

替代实现

cooltooltipsfancytooltips 是提供工具提示功能的 LaTeX 包,可能可以从 tikzDevice 使用。上述示例中使用的一些想法来自cooltooltips。

结论性想法

这值得吗?好吧,到最后我确实学到了两件事:

  • 我不是 PDF 专家,我必须搜索几个邮件列表并消化 700 多页规范的某些部分,才能回答“这可能吗?”这个问题。更别说想出一个实现了。

  • 我不是 SVG 专家,但我知道 SVG 中的工具提示不是“这可能吗?”的问题。而是“how sexy do you want it to look?”。

鉴于这一观察,我说现在是时候让 PDF 进入日落并采用 700 页的规范了。我们需要一种新的页面描述标记语言,我个人希望SVG Print 能够完成这项工作。如果规范足够好,我什至会接受Adobe Mars。只要给我们一个基于 XML 的格式,它可以利用当今 JavaScript 库的全部功能,然后就可以开始一些真正的创新。 LuaTeX 后端将是一个不错的奖励。


参考文献

【讨论】:

    【解决方案3】:

    pdf2 包对我来说很好用。 (https://r-forge.r-project.org/R/?group_id=193)。您可以在常规文本命令中包含一个“弹出窗口”。它不是 2.14 的最新版本,但我想他很快就会接受它。

    text(x,y,'硬拷贝文本',popup='工具提示文本')

    【讨论】:

    • 澄清:适用于您,但仅适用于旧版本的 R?可悲的是,似乎根本不适用于 2.15。
    猜你喜欢
    • 2014-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 2020-10-19
    • 1970-01-01
    相关资源
    最近更新 更多