在R中使用工具提示创建pdf [英] Create pdf with tooltips in R

查看:96
本文介绍了在R中使用工具提示创建pdf的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一个简单的问题:是否有办法从pdf文件中的R中绘制图形并包含工具提示?

Simple question: Is there a way to plot a graph from R in a pdf file and include tooltips?

推荐答案

一个简单的问题:是否有办法从pdf文件中的R中绘制图形并包含工具提示?

Simple question: Is there a way to plot a graph from R in a pdf file and include tooltips?

总有办法.但是魔鬼在细节上,所以真正的问题是:你愿意弄脏你的手吗?

There's always a way. But the devil is in the details, so the real question is: are you willing to get your hands dirty?

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

PDF does support tooltips for certain kinds of objects such as hyperlinks. So, if there is a way to insert raw PDF statements indicating there should be a hyperlink-like object at some position in your plot, then there is a way to pop up a tooltip.

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

Now, the only way I know of to generate and compile raw PDF statements is to create the document using TeX. There are definitely other ways to do it, but this is the one I am familiar with. The following examples use a graphics device that Cameron Bracken and I wrote, the tikzDevice, to render R graphics to LaTeX code. The tikzDevice has preliminary support for injecting arbitrary LaTeX code into the graphics output stream through the tikzAnnotate function---we will be using this to drop PDF callouts into the plot.

涉及的步骤是:

  1. 设置LaTeX宏以生成产生标注所需的PDF命令.
  2. 设置一个R函数,该函数使用tikzAnnotate在图中的特定点调用LaTeX宏.
  3. ???
  4. 利润!
  1. Set up a LaTeX macro to generate the PDF commands required to produce a callout.
  2. Set up an R function that uses tikzAnnotate to invoke the LaTeX macro at specific points in the plot.
  3. ???
  4. Profit!

在下面的示例中,第2步附加了一个主要警告.所使用的坐标计算仅适用于基础图形,不适用于ggplot2之类的网格图形.

In the examples that follow, one major caveat is attached to step 2. The coordinate calculations used will only work with base graphics, not grid graphics such as ggplot2.

tikzDevice允许您创建R图形,其中包括执行任意LaTeX命令.通常,这样做是为了将诸如$\alpha$之类的内容插入情节标题中,以生成希腊字母,α或复杂方程式.在这里,我们将使用此功能来调用一些原始的PDF伏都教.

The tikzDevice allows you to create R graphics that include the execution of arbitrary LaTeX commands. Usually this is done to insert things like $\alpha$ into plot titles to generate greek letters, α, or complex equations. Here we are going to use this feature to invoke some raw PDF voodoo.

在tikzDevice图形生成期间希望使用的任何LaTeX宏都需要通过设置tikzLatexPackages选项预先定义.在这里,我们将向该声明添加一些内容:

Any LaTeX macros that you wish to be available during the generation of a tikzDevice graphic need to be defined up-front by setting the tikzLatexPackages option. Here we are going to append some stuff to that declaration:

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代码,则它看起来像这样:

If all that quoted nonsense were to be written out as LaTeX code by someone who cared about readability, it would look like this:

\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可能会变得很奇怪- -尤其是当您下山的时候):

For those programmers who have never taken a walk on the wild side and done some "programming" in TeX, here's a blow-by-blow for the above code (as I understand it anyway, TeX can get very weird---especially when you get down in the trenches with it):

  • 第1行:定义对象tooltiptarget,该对象是不可见的(幻像),并且是1mm x 1mm的矩形(规则).这是我们将用来检测鼠标悬停的屏幕区域.

  • Line 1: Define an object, tooltiptarget, which is non-visible (a phantom) and is a 1mm x 1mm rectangle (a rule). This will be the onscreen area which we will use to detect mouseovers.

第2行:创建一个新框,就像排版材料的页面片段"一样.可以容纳几乎所有东西,包括其他盒子(类似于R列表).称为tempboxa.

Line 2: Create a new box, which is like a "page fragment" of typset material. Can contain pretty much anything, including other boxes (sort of like an R list). Call it tempboxa.

第3行:分配tempboxa的内容以包含一个空框,该框使用水平布局排列其内容(不重要,可以使用vbox或其他框) .

Line 3: Assign the contents of tempboxa to contain an empty box that arranges its contents using a horizontal layout (which is unimportant, could have used a vbox or other box).

第4行:使用tempboxa的内容创建PDF表单XObject. PDF文件可以使用Form XObject来存储可能反复使用的图形(如徽标).在这里,我们创建了一个空白图标",以后可以用来减少视觉混乱. TeX会延迟输出操作(例如将对象写入PDF文件),直到满足某些条件(例如,页面已满)为止.立即确保不延迟此操作.

Line 4: Create a PDF Form XObject using the contents of tempboxa. A Form XObject can be used by PDF files to store graphics, like logos, that may be used over and over. Here we are creating a "blank icon" that we can use later to cut down on visual clutter. TeX defers output operations, like writing objects to a PDF file, until certain conditions have been met---such as a page has filled up. Immediate makes sure this operation is not deferred.

第5行:该行捕获一个整数值,该值用作对我们刚刚创建的PDF XObject的引用,并将其命名为emptyicon.

Line 5: This line captures an integer value that serves as a reference to the PDF XObject we just created and assigns it the name emptyicon.

第6行:开始定义一个名为tooltip的新宏,该宏接受1个参数,该参数在宏的主体中称为#1.宏中的每一行都以注释字符%结尾,以防止TeX注意到为提高可读性而添加的换行符(换行符在宏内部可能产生奇怪的影响).

Line 6: Starts the definition of a new macro called tooltip that takes 1 argument which is referred to in the body of the macro as #1. Each line in the macro ends with a comment character, %, to keep TeX from noticing the newlines that have been added for readability (newlines can have strange effects inside macros).

第7行:输出原始PDF命令(pdfstartlink).这开始创建一个新的PDF注释对象(\Type \Annot),该对象大约有20种不同的子类型,其中包括超链接.此行之后的每一行都包含带有两个TeX宏的原始PDF标记.

Line 7: Output raw PDF commands (pdfstartlink). This begins the creation of a new PDF annotation object (\Type \Annot) of which there are about 20 different subtypes---among them are hyperlinks. Every line following this contains raw PDF markup with a couple of TeX macros.

第8行:声明我们将要使用的注释子类型.在这里,我要使用纯文本注释,例如注释或便笺.

Line 8: Declare the annotation subtype we are going to use. Here I am going with a plain Text annotation such as a comment or sticky note.

第9行:声明注释的内容.这将是工具提示的内容,并将其设置为工具提示宏的参数#1.

Line 9: Declare the contents of the annotation. This will be the contents of our tooltip and is set to #1, the argument to the tooltip macro.

第10-12行:通常,文本注释由图标(例如便笺)标记,以突出显示它们在文本中的位置.如果我们允许它在整个图形中散布一些小便笺,则此行为将导致视觉混乱.在这里,我们使用外观数组(\AP << >>)将常规"注释图标(\N)设置为我们之前创建的空白图标.我们与0 R一起存储在emptyicon中的整数构成了对我们在第4行使用空框形成的Form XObject的引用.

Lines 10-12: Normally text annotations are marked by an icon, such as a sticky note, to highlight their location in the text. This behavior will cause a visual mess if we allow it to splatter little sticky notes all over our graphs. Here we use an appearance array (\AP << >>) set the "normal" annotation icon (\N) to be the blank icon we created earlier. The integer we stored in emptyicon along with 0 R forms a reference to the Form XObject we made on Line 4 using an empty box.

第14行::如果我们要创建普通的超链接,则此处将文本/图像/所有内容用作链接正文.相反,我们插入tooltiptarget这个不可见的幻像对象,该对象不会显示在屏幕上,但会对鼠标悬停做出反应.

Line 14: If we were making a normal hyperlink, here is where the text/image/whatever would go that would serve as the link body. Instead we insert tooltiptarget, our invisible phantom object which does not show up on the screen but does react to mouseovers.

好吧,现在我们已经告诉LaTeX如何创建工具提示,现在是时候使它们在R中可用了.这涉及编写一个函数,该函数将在我们的图形上获取坐标,例如(1,1),并转换它们转换为画布或设备"坐标.在tikzDevice的情况下,所需的测量值为距绘图区域绝对左下角的"TeX点"(1/72.27英寸).幸运的是,对于基本图形,有一些方便的函数可以为我们计算此值.网格图形的工作方式不同,因此此处示例中采用的方法不适用于它们.

Allright, now that we have told LaTeX how to create tooltips, it is time to make them usable from R. This involves writing a function that will take coordinates on our graph, such as (1,1), and convert them into canvas or "device" coordinates. In the case of the tikzDevice the required measurement is "TeX points" (1/72.27 of an inch) from the absolute bottom left of the plotting area. Fortunately for base graphics, there are handy functions to calculate this for us. Grid graphics work differently, so the approach taken in the examples here won't work for them.

R函数的最后一项任务是调用tikzAnnotate,以将TikZ节点"插入位于我们计算出的坐标的输出流中.节点可以包含任意TeX命令,在这种情况下,我们将调用tooltip.

The final task for our R function is to call tikzAnnotate to insert a TikZ "node" into the output stream that is located at the coordinates we computed. Nodes can contain arbitrary TeX commands, in this case we will be calling upon tooltip.

这是一个R函数,其中包含上述功能:

Here is an R function that contains the above functionality:

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()

}

步骤3

在剧情上试用:

Step 3

Try it out on a plot:

# 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)

步骤4

观察结果(下载pdf ):

那么,既然我们已经有了一些简单的工具提示,为什么不将其提高到11?在前面的示例中,我们使用了一个空的hbox来摆脱工具提示图标.但是,如果我们在该框中放了一些东西,例如文本或绘图,该怎么办?如果有一种方法可以使图标仅在鼠标悬停事件中出现,该怎么办?

So, now that we have simple tooltips out of the way, why not crank it to 11? In the previous example, we used an empty hbox to get rid of the tooltip icon. But what if we had put something in that box, like text or a drawing? And what if there was a way to make it so that the icon only appeared during mouseover events?

以下TeX宏的边缘有些粗糙,但这表明这是可能的:

The following TeX macro is a little rough around the edges, but it shows that this is possible:

\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%
}

与简单标注相比,进行了以下修改.

The following modifications have been made compared to the simple callout.

  • 已加载shapes.callouts库,其中包含供TikZ在绘制标注框时使用的模板.

  • The shapes.callouts library is loaded which contains templates for TikZ to use when drawing callout boxes.

定义了tooltip样式,其中包含一些TikZ图形样板.它指定一个可见的矩形标注框(draw). callout absolute pointer业务是一个黑客,因为到此为止我已经喝了太多啤酒,无法弄清楚如何使用动态生成的PDF原语放置注释图标.这依赖于图标左上角的默认锚定,因此将标注框的指针拉向该位置.结果是这些框将始终显示在指针的右下角,并且如果标注文本足够长,它们将看起来不正确.

A tooltip style is defined which contains some TikZ graphics boilerplate. It specifies a rectangular callout box that is to be visible (draw). The callout absolute pointer business is a hack because I've had too many beers by this point to figure out how to place annotation icons using dynamically generated PDF primitives. This relies on the default anchoring of icons at their upper left corner and so pulls the pointer of the callout box toward that location. The result is that the boxes will always appear to the lower right of the pointer and if the callout text is long enough, they won't look right.

在宏中,使用一键式tikz命令生成工具提示,该命令填充到tooltipcallout宏中. XObject表单是从tooltipcallout生成的,并分配给tooltipicon.

Inside the macro, the tooltip is generated using a one-shot tikz command that is stuffed into the tooltipcallout macro. A form XObject is generated from tooltipcallout and assigned to tooltipicon.

emptyicon.这是必需的,因为默认图标的大小显然设置了可用于翻转图标的视口.

emptyicon is also dynamically generated by evaluating tooltipcallout inside of phantom. This is required because the size of the default icon apparently sets the viewport available for the rollover icon.

在生成PDF命令时,将使用tooltipicon引用的XObject将新行添加到/R数组(/R)以进行翻转.

When generating PDF commands, a new row is added to the /AP array, /R for rollover, that uses the XObject referenced by tooltipicon.

准备使用的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}"
))

步骤2

R级代码不变.

Step 2

The R-level code is unchanged.

让我们尝试一个稍微复杂一些的图:

Let's try a slightly more complicated graph:

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)

步骤4

结果(下载PDF ):

如您所见,工具提示和标注均存在问题.设置\Contents ()以便工具提示具有空字符串将无济于事.可以通过使用其他注释类型来解决此问题,但此刻我将不再花费更多时间.

As you can see, there is an issue with both the tooltip and the callout being displayed. Setting \Contents () so that the tooltip has an empty string won't help anything. This can probably be solved by using a different annotation type, but I'm not going to spend any more time on it at the moment.

  • 很多TeX命令都包含反斜杠,在用R代码表达内容时,您需要将反斜杠加倍.

  • Lots of TeX commands contain backslashes, you will need to double the backslashes when expressing things in R code.

某些字符是TeX的特殊字符,例如_^%此处的完整列表,您需要确保在使用tikzDevice时正确地将它们转义.

Certain characters are special to TeX, such as _, ^, %, complete list here, you will need to ensure these are properly escaped when using the tikzDevice.

尽管PDF应该被认为优于HTML,因为它在各个平台上都具有一致的呈现效果,但是根据所使用的查看器的不同,您的工作量也会有很大不同.屏幕截图是在OS X的Acrobat 8​​中拍摄的,预览版也做得不错,但没有呈现过渡标注.在Linux上,xpdf不会呈现任何内容,而okular会显示工具提示,但不会取消显示工具提示图标,并显示在情节中间看上去有点扎眼的股票图标.

Even though PDF is supposed to be superior to HTML in that it has a consistant rendering across platforms, your mileage will vary significantly depending on which viewer is being used. The screenshots were taken in Acrobat 8 on OS X, Preview also did a passable job but did not render the rollover callout. On Linux, xpdf didn't render anything and okular showed a tooltip, but did not suppress the tooltip icon and displayed a stock icon that looked a little garish in the middle of a plot.

cooltooltips

cooltooltips and fancytooltips are LaTeX packages that provide tooltip functionality that could probably be used from the tikzDevice. Some ideas used in the above examples were taken from cooltooltips.

这值得吗?好吧,到今天结束时,我确实学到了两件事:

Was this worth it? Well, by the end of the day I did learn two things:

  • 我不是PDF专家,我不得不搜索几个邮件列表,并消化700多页规范的某些部分,甚至回答这可能吗?"这个问题.更不用说实现了.

  • I am not a PDF expert and I had to search a couple mailing lists and digest some parts of a 700+ page specification to even answer the question "is this possible?" let alone come up with an implementation.

我不是SVG专家,但我知道SVG中的工具提示不是这可能吗?"的问题.而是"您希望它看起来如何性感?".

I am not a SVG expert and yet I know that tooltips in SVG is not a question of "is this possible?" but rather "how sexy do you want it to look?".

考虑到这一点,我想说是时候让PDF踏入夕阳了,并带走700页的规格.我们需要一种新的页面描述标记语言,我个人希望 SVG打印将会完成足以胜任这项工作.如果该规范足够适用,我什至会接受 Adob​​e Mars .只要给我们提供一种基于XML的格式,该格式可以利用当今JavaScript库的全部功能,然后就可以开始一些真正的创新.一个LuaTeX后端将是一个不错的奖励.

Given that observation, I say that it is getting to be time for PDF to ride off into the sunset and take it's 700 page spec with it. We need a new page description markup language and personally I'm hoping SVG Print will be complete enough to do the job. I would even accept Adobe Mars if the specification is accesible enough. Just give us an XML-based format that can exploit the full power of today's JavaScript libraries and then some real innovation can begin. A LuaTeX backend would be a nice bonus.

  • tikzDevice: A device for outputting R graphics as LaTeX code.
  • comp.text.tex: Source of much insight into esoteric TeX details. Posts by Herbert Voß and Mycroft provided implementation ideas.
  • The pdfTeX manual: Source of information concerning TeX commands that can generate raw PDF code, such as \pdfstartlink
  • TeX by Topic: Go-to manual for low-level TeX details such as how \immediate actually works.
  • The Adobe PDF Specification: The lair of details concerning PDF primitives.
  • The TikZ Manual: Quite possibly the finest example of open source documentation ever written.

这篇关于在R中使用工具提示创建pdf的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆