4

I want to change knitr's behavior when it creates a figure environment in LaTeX to call a different LaTeX command than \label{}, e.g, \alabel{} where I define \alabel to run \label{foo} as well as \hypertarget{foo}{} using the hyperref LaTeX package. I'm doing this so that I can construct a URL in a web browser to get to a specific place in the .pdf document built with pdflatex, e.g. http://.../my.pdf#nameddest=foo.

How can I either override \label{} or emit an additional \hypertarget{same label used by \label{} in the figures?

This is in the context of a .Rnw file. I'd like the anchor to appear inside the figure environmentfor optimal positioning of the cursor when jumping into the.pdf` document.

UPDATE

In rethinking this I think it's best not to generate hypertarget anchors but to write an R function that parses the LaTeX aux file to retrieve the page number of the reference (\newlabel lines) to generate the needed URL to the pdf file. In the .Rnw or .Rmd file I can call this function from within a sentence to insert the computed URL.

UPDATE

I've decided after all to go with @werner's excellent method, which works flawlessly. For anyone interested in the R-based approach that doesn't require the use of hypertarget, here is the LaTeX code needed to set up for it - this handles the case where physical page numbers do not match logical page numbers (e.g., using logical numbers such as chapter number - page within chapter.

% Creates .pag file mapping absolute page numbers to logical page
% numbers; works with R function latexRef

\newwrite\pgfile
\immediate\openout\pgfile=\jobname .pag
\newcounter{abspage}
\setcounter{abspage}{0}

\useackage{everypage}
\AddEverypageHook{%
  \addtocounter{abspage}{1}
  \immediate\write\pgfile{\thepage, \theabspage}%
}
\AtEndDocument{\clearpage\immediate\closeout\pgfile}

Here's the R function that does the lookups in the .aux, .pag files:

## Create hyperlink to appropriate physical page in a pdf document
## created by pdflatex given the .aux and .pag file.  Absolute and
## named page numbers are store in the .pag file created by hslide.sty

latexRef <- function(label, base, name, path='doc/',
                     blogpath='/home/harrelfe/R/blog/blogdown/static/doc/',
                     lang=c('markdown', 'latex')) {
  lang <- match.arg(lang)
  aux <- paste0(blogpath, base, '.aux')
  if(! file.exists(aux))
    stop(paste('no file named', aux))
  path <- paste0(path, base, '.pdf')
  pag  <- paste0(blogpath, base, '.pag')
  pagemap <- NULL
  if(file.exists(pag)) {
    p <- read.table(pag, sep=',')
    pagemap        <- trimws(p[[2]])
    names(pagemap) <- trimws(p[[1]])
  }

  r <- readLines(aux)
  w <- paste0('\\\\newlabel\\{', label, '\\}')
  i <- grepl(w, r)
  if(! any(i)) stop(paste('no label =', label))
  r <- r[i][1]
  r <- gsub('\\{', ',', r)
  r <- gsub('\\}', ',', r)
  x <- scan(text=r, sep=',', what=character(0), quiet=TRUE)
  section <- x[5]
  if(section != '') section <- paste0(' Section ', section)
  page    <- trimws(x[7])
  if(length(pagemap)) page <- pagemap[page]
  url     <- paste0('http://fharrell.com/', path, '#page=', page)
  switch(lang,
         markdown = paste0('[', name, section, '](', url, ')'),
         latex    = paste0('\\href{', url, '}{', name, section, '}')
         )
  }
Frank Harrell
  • 1,954
  • 2
  • 18
  • 36
  • 1
    Close voter: This question is about the R package `knitr` (on topic), not about LaTeX. – CL. Jan 18 '18 at 13:54
  • I think you'll have to modify `hook_plot_tex`, in particular the way how `fig2` is constructed. See [`hooks-latex.R`](https://github.com/yihui/knitr/blob/7386aa3960e8126f8accaa35341b578b7af44277/R/hooks-latex.R). Sorry, I don't have the time to fiddle with this right now, but I wish you good luck. – CL. Jan 18 '18 at 14:01
  • Does the `\alabel` have to be inside the `figure` environment? If not, editing the plot hook like in https://stackoverflow.com/a/48321490/1777111 could help. – Martin Schmelzer Jan 18 '18 at 16:07
  • 1
    I guess the answer would be different depending on whether you are using Rnw or R Markdown documents. Either way, it will be great if you can provide a minimal example. (To close voters: [can't you just wait for a second?](https://yihui.name/en/2017/12/so-bounties/)) – Yihui Xie Jan 18 '18 at 17:20
  • I clarified the Rnw context and wish to be inside `figure` environment. I'm not clear on votes to close - I tried to be honest in my tags. `LaTeX` users may wish to find this someday. – Frank Harrell Jan 18 '18 at 18:53

1 Answers1

2

You could add the following to your LaTeX preamble a global replacement of \label with a combination of \label-and-\hypertarget in the following way:

---
title: 'A title'
author: 'An author'
date: 'A date'
output: 
  pdf_document:
    keep_tex: true
header-includes:
  - \AtBeginDocument{
      \let\oldlabel\label
      \renewcommand{\label}[1]{\oldlabel{#1}\hypertarget{#1}{}}
    }
---

See Figure \ref{fig:figure}.

\begin{figure}
  \caption{A figure caption}
  \label{fig:figure}
\end{figure}
Werner
  • 14,324
  • 7
  • 55
  • 77
  • I tried a slight variation of that with https://tex.stackexchange.com/questions/47351 using the `letltxmacro` package but `pdflatex` ignored it. I wonder if there is something special about `label`. But I'm going with the method in the Update to the original question, I think. Thanks. – Frank Harrell Jan 19 '18 at 16:40
  • @FrankHarrell: `\label` is *sensitive*, specifically because you're also using [`hyperref`](//ctan.org/pkg/hyperref). That's why I used `\AtBeginDocument` in order to delay the redefinition until the document actually starts. – Werner Jan 19 '18 at 16:42
  • Got it. Great to know that. – Frank Harrell Jan 19 '18 at 16:46