potockan
potockan

Reputation: 4088

R `sprintf` with HTML tags gives `arguments cannot be recycled to the same length`

I have a data.frame res with 2 rows and I want to put the values in the sprintf function with the HTML tags. If I use tags$strong("some character") function I get an error. If I type <strong>some character</strong> it works. If I have 3 rows in the df both codes work. Here's a MWE with 2 row data.frame:

res <- data.frame(term = letters[1:2], p.value = c(0.567, 0.123), hazard = c(1.234, 3.421))
sprintf(
  "%s: %s %.3f %s %.3f</br>",
  res$term,
  tags$strong("p-value: "),
  res$p.value,
  tags$strong("Hazard Ratio: "),
  res$hazard
)
# Error in sprintf("%s: %s %.3f %s %.3f</br>", res$term, tags$strong("p-value: "),  : 
#  arguments cannot be recycled to the same length
sprintf(
  "%s: %s %.3f %s %.3f</br>",
  res$term,
  "<strong>p-value: </strong>",
  res$p.value,
  "<strong>Hazard Ratio: </strong>",
  res$hazard
)
# works!
# [1] "a: <strong>p-value: </strong> 0.567 <strong>Hazard Ratio: </strong> 1.234</br>" 
# [2] "b: <strong>p-value: </strong> 0.123 <strong>Hazard Ratio: </strong> 3.421</br>"

Three row data.frame:

res <- data.frame(term = letters[1:3], p.value = c(0.567, 0.123, 0.231), hazard = c(1.234, 3.421, 5.211))

sprintf(
  "%s: %s %.3f %s %.3f</br>",
  res$term,
  tags$strong("p-value: "),
  res$p.value,
  tags$strong("Hazard Ratio: "),
  res$hazard
)

sprintf(
  "%s: %s %.3f %s %.3f</br>",
  res$term,
  "<strong>p-value: </strong>",
  res$p.value,
  "<strong>Hazard Ratio: </strong>",
  res$hazard
)

The questions are:

  1. Why it doesn't work when I have 2 rows in df and it works with 3 rows?
  2. Why in the two row df it doesn't work with the tags$strong function?

Upvotes: 0

Views: 2311

Answers (1)

shosaco
shosaco

Reputation: 6165

Let us look at a minimal example to see the problem more clear. The following works

sprintf("%s: %s",
         tags$strong("Value "),
         1:3
     )

but the following doesn't:

sprintf("%s: %s",
         tags$strong("Value "),
         1:2
     )

Apparently if you try, the first works for vectors of any length that is multiple of 3 (3, 6, 9,...). All other integers do not work (except for 1, which is a special case). The solution lies in the structure of your shiny HTML tag, which is a list of length 3:

str( tags$strong("Value ") )

List of 3
 $ name    : chr "strong"
 $ attribs : list()
 $ children:List of 1
  ..$ : chr "Value "
 - attr(*, "class")= chr "shiny.tag"

It is a list of length 3, where as the String <strong>Value</strong> is a vector of length 1. R tries to reuse the tags$strong-Tag as many times as the second vector is long (res$x in your case). Sadly it is of length 3, so it cannot produce anything useful if asked to recycle only 2 times.

On the other hand, if you merely write the length-1-String <strong>Value</strong> it can be recycled any number of times, even 2.

Upvotes: 1

Related Questions