Подтвердить что ты не робот

Создать pdf с подсказками в R

Простой вопрос: есть ли способ построить график из R в pdf файле и включить всплывающие подсказки?

4b9b3361

Ответ 1

Простой вопрос: есть ли способ построить график из R в pdf файле и включить всплывающие подсказки?

Всегда есть путь. Но дьявол находится в деталях, поэтому реальный вопрос: готовы ли вы замарать руки?

PDF поддерживает подсказки для определенных типов объектов, таких как гиперссылки. Итак, если есть способ вставить исходные инструкции PDF, указывающие, что в вашем месте должен быть объект с гиперссылкой в ​​какой-то позиции на вашем графике, тогда есть способ всплывать всплывающая подсказка.

Теперь единственный способ создать и скомпилировать необработанные инструкции PDF - создать документ с помощью TeX. Есть определенные способы сделать это, но это тот, с которым я знаком. В следующих примерах используется графическое устройство, которое Кэмерон Брэкен и я написали, tikzDevice, чтобы отобразить R-графику в коде LaTeX. У tikzDevice есть предварительная поддержка для инъекции произвольного кода LaTeX в поток вывода графики через функцию tikzAnnotate --- мы будем использовать это, чтобы сбросить вычеты PDF в график.

Этапы:

  • Настройте макрос LaTeX для создания команд PDF, необходимых для создания выноски.
  • Настройте функцию R, которая использует tikzAnnotate для вызова макроса LaTeX в определенных точках графика.
  • ???
  • Profit!

В следующих примерах к шагу 2 прилагается одно важное предостережение. Используемые расчеты координат будут работать только с базовой графикой, а не с сеткой, такой как ggplot2.


Простые подсказки

Шаг 1

TikzDevice позволяет создавать графики R, которые включают в себя выполнение произвольных команд LaTeX. Обычно это делается для вставки таких вещей, как $\alpha$, в заголовки сюжетов для генерации греческих букв, α или сложных уравнений. Здесь мы собираемся использовать эту функцию для вызова некоторого необработанного PDF voodoo.

Любые макросы LaTeX, которые вы хотите получить во время генерации графического изображения tikzDevice, необходимо определить заранее, установив параметр 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, который невидимый (a phantom) и прямоугольник 1 мм x 1 мм (правило). Это будет экранная область, которую мы будем использовать для обнаружения мышелов.

  • Строка 2: Создайте новый флажок, который похож на "фрагмент страницы" материала typset. Может содержать почти все, включая другие поля (вроде списка R). Назовите его tempboxa.

  • Строка 3: Назначьте содержимое tempboxa для размещения пустого поля, которое упорядочивает его содержимое с использованием горизонтального макета (что неважно, возможно, использовало vbox или другое поле).

  • Строка 4: Создайте PDF-форму XObject, используя содержимое tempboxa. Форма XObject может использоваться файлами PDF для хранения графики, например логотипов, которые могут использоваться снова и снова. Здесь мы создаем "пустой значок", который мы можем использовать позже, чтобы сократить визуальный беспорядок. TeX отменяет операции вывода, такие как запись объектов в файл PDF, до тех пор, пока не будут выполнены определенные условия - например, страница заполнена. Немедленно убедитесь, что эта операция не отложена.

  • Строка 5: Эта строка фиксирует целочисленное значение, которое служит ссылкой на только что созданный XObject PDF и присваивает ему имя emptyicon.

  • Строка 6: Запускает определение нового макроса, называемого подсказкой, которая принимает один аргумент, который в теле макроса упоминается как #1. Каждая строка макроса заканчивается символом комментария %, чтобы TeX не заметил новые строки, которые были добавлены для чтения (новые строки могут иметь странные эффекты внутри макросов).

  • Строка 7: Вывод исходных команд PDF (pdfstartlink). Это начинает создание нового объекта аннотации PDF (\Type \Annot), из которого имеется около 20 различных подтипов --- среди них есть гиперссылки. Каждая строка, следующая за ней, содержит сырую PDF-разметку с несколькими макросами TeX.

  • Строка 8: Объявите подтип аннотации, который мы будем использовать. Здесь я собираюсь с простой текстовой аннотацией, такой как комментарий или заметка.

  • Строка 9: Объявить содержание аннотации. Это будет содержимое нашей всплывающей подсказки и будет установлено в #1, аргумент макроса всплывающей подсказки.

  • Строки 10-12: Обычно текстовые аннотации помечены значком, например заметкой, чтобы выделить их местоположение в тексте. Такое поведение вызовет визуальный беспорядок, если мы позволим ему разбрызгивать маленькие липкие заметки по всем нашим графикам. Здесь мы используем массив внешнего вида (\AP << >>), который обозначает "обычный" значок аннотации (\N) как пустой значок, который мы создали ранее. Целое число, которое мы сохранили в emptyicon вместе с 0 R, формирует ссылку на объект формы XObject, который мы сделали в строке 4, используя пустой ящик.

  • Строка 14: Если мы создаем нормальную гиперссылку, вот где будет текст/изображение/все, что будет служить телом связи. Вместо этого мы вставляем tooltiptarget, наш невидимый объект phantom, который не отображается на экране, но реагирует на наведение.

Шаг 2

Хорошо, теперь, когда мы сказали LaTeX, как создавать всплывающие подсказки, пришло время сделать их пригодными для использования R. Это включает в себя запись функции, которая будет принимать координаты на нашем графике, например (1,1), и преобразовывать их в холст или координаты "устройства". В случае tikzDevice требуемое измерение - "точки TeX" (1/72,27 дюйма) от абсолютного нижнего левого края области печати. К счастью для базовой графики, есть удобные функции для расчета этого для нас. Графическая графика работает по-разному, поэтому подход, использованный в примерах здесь, не будет работать для них.

Последняя задача нашей R-функции - вызвать tikzAnnotate, чтобы вставить TikZ "node" в выходной поток, который находится в координатах, которые мы вычислили. Узлы могут содержать произвольные команды 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()

}

Шаг 3

Попробуйте на сюжете:

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

Screenshot of a simple tooltip


Расширенные подсказки

Шаг 1

Итак, теперь, когда у нас есть простые всплывающие подсказки, почему бы не перекрутить его до 11? В предыдущем примере мы использовали пустой hbox, чтобы избавиться от значка всплывающей подсказки. Но что, если бы мы что-то вложили в это окно, например текст или рисунок? И что, если бы был способ сделать так, чтобы значок появлялся только во время событий mouseover?

Следующий макрос 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 для использования при рисовании ящиков.

    Стиль
  • A tooltip определен, который содержит некоторый графический шаблон TikZ. Он указывает прямоугольное поле выноски, которое должно быть видимым (draw). Бизнес callout absolute pointer - это взлом, потому что к этому моменту у меня было слишком много пива, чтобы выяснить, как размещать значки аннотаций, используя динамически создаваемые примитивы PDF. Это зависит от привязки значков по умолчанию в их верхнем левом углу и, таким образом, тянет указатель окна выноса к этому месту. В результате ящики всегда будут отображаться в правом нижнем углу указателя, и если текст выноса будет достаточно длинным, они не будут выглядеть правильно.

  • Внутри макроса всплывающая подсказка создается с помощью команды one-shot tikz, которая заполняется макросом tooltipcallout. Форма XObject создается из tooltipcallout и назначается tooltipicon.

  • emptyicon также динамически генерируется путем оценки tooltipcallout внутри phantom. Это необходимо, потому что размер значка по умолчанию, по-видимому, устанавливает видимость для значка опрокидывания.

  • При создании команд PDF новая строка добавляется в массив /AP, /R для опрокидывания, который использует объект XObject, на который ссылается 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 не изменяется.

Шаг 3

Попробуйте немного более сложный график:

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

Screenshot of a tooltip with custom callout box

Как вы можете видеть, есть проблема с отображением всплывающей подсказки и выноски. Установка \Contents (), чтобы всплывающая подсказка имела пустую строку, ничего не поможет. Вероятно, это можно решить, используя другой тип аннотации, но я не собираюсь тратить на него больше времени.


Предостережения

  • Многие команды TeX содержат обратную косую черту, вам нужно удвоить обратную косую черту при выражении вещей в R-коде.

  • Некоторые символы являются особыми для TeX, например _, ^, %, полный список здесь, вам нужно будет убедиться, что они правильно экранированы при использовании tikzDevice.

  • Несмотря на то, что PDF, как предполагается, превосходит HTML, поскольку он имеет согласованный рендеринг между платформами, ваш пробег будет значительно отличаться в зависимости от того, какой из зрителей используется. Скриншоты были сделаны в Acrobat 8 ​​на OS X, Preview также выполнил проходимую работу, но не отобразил выноску опрокидывания. В Linux xpdf ничего не отображал, и okular показывал всплывающую подсказку, но не подавлял значок всплывающей подсказки и отображал значок запаса, который выглядел немного ярко в середине графика.

Альтернативные реализации

cooltooltips и fancytooltips являются пакетами LaTeX, которые предоставляют функциональные возможности всплывающих подсказок, которые, вероятно, могут использоваться из tikzDevice. Некоторые идеи, использованные в приведенных выше примерах, были взяты из cooltooltips.

Заключительные мысли

Было ли это того стоит? Ну, к концу дня я узнал две вещи:

  • Я не эксперт по PDF, и мне пришлось искать пару списков рассылки и переваривать некоторые части спецификации более 700 страниц, чтобы даже ответить на вопрос "возможно ли это?". не говоря уже о реализации.

  • Я не эксперт по SVG, и все же я знаю, что всплывающие подсказки в SVG - это не вопрос "возможно ли это?". а скорее "как сексуально вы хотите, чтобы он выглядел? ".

Учитывая это замечание, я говорю, что настало время для PDF, чтобы отправиться на закат и взять с собой 700 страниц. Нам нужен новый язык разметки описания страницы, и лично я надеюсь, что SVG Print будет достаточно полным, чтобы выполнить эту работу. Я бы даже принял Adobe Mars, если спецификация достаточно доступная. Просто дайте нам формат на основе XML, который может использовать всю мощь сегодняшних библиотек JavaScript, а затем можно начать некоторые реальные инновации. Бэкэндом LuaTeX будет хороший бонус.


Ссылки

  • tikzDevice: Устройство для вывода графики R в виде кода LaTeX.
  • comp.text.tex: Источник многого понимания эзотерических данных TeX. Сообщения Herbert Voß и Майкрофт предоставили идеи внедрения.
  • Руководство pdfTeX: Источник информации о командах TeX, которые могут генерировать необработанный PDF-код, например \pdfstartlink
  • TeX по теме: Перейти к руководству для низкоуровневых данных TeX, таких как \immediate фактически работает.
  • Спецификация Adobe PDF: Логово деталей относительно примитивов PDF.
  • Руководство TikZ: Возможно, самый лучший пример документации с открытым исходным кодом, когда-либо написанной.

Ответ 2

Ну, а не pdf, но вы можете включить всплывающие подсказки (среди прочих) в формате svg с SVGAnnotation или RSVGTipsDevice.

Ответ 3

Пакет pdf2 отлично подходит для меня. (Https://r-forge.r-project.org/R/?group_id=193). Вы можете просто включить "всплывающее окно" в обычной текстовой команде. Это не актуально с 2.14, но я полагаю, что он дойдет до него слишком долго.

text (x, y, 'copy copy', popup = 'tooltip text')