I am trying to use Shiny as an assessment tool for multiple choice items. As such, in some cases I would like to have an image as a choice. Instead, the raw HTML is shown. Can this be done in Shiny?
library(shiny)
choices <- c('\\( e^{i \\pi} + 1 = 0 \\)' = 'equation',
'<img src="Rlogo.png">' = 'logo')
ui <- shinyUI(fluidPage(
withMathJax(),
img(src='Rlogo.png'),
fluidRow(column(width=12,
radioButtons('test', 'Radio buttons with MathJax choices',
choices = choices, inline = TRUE),
br(),
h3(textOutput('selected'))
))
))
server <- shinyServer(function(input, output) {
output$selected <- renderText({
paste0('You selected the ', input$test)
})
})
shinyApp(ui = ui, server = server)
You will have to put the R logo in the www
directory where you place this app.r
script. Here is a direct link to the logo: http://i1.wp.com/www.r-bloggers.com/wp-content/uploads/2016/02/Rlogo.png?resize=300%2C263
The img
is not displayed in the radio buttons because the names are held in span
and generated using tags$span
so all HTML is escaped.
If you only have to do this once, you can copy the output of radioButtons('test', 'Radio buttons with MathJax choices', choices = choices, inline = TRUE)
, place it in a tags$div
, and add the image:
fluidRow(column(width=12,
tags$div(HTML('<div id="test" class="form-group shiny-input-radiogroup shiny-input-container shiny-input-container-inline">
<label class="control-label" for="test">Radio buttons with MathJax choices</label>
<div class="shiny-options-group">
<label class="radio-inline">
<input type="radio" name="test" value="equation" checked="checked"/>
<span>\\( e^{i \\pi} + 1 = 0 \\)</span>
</label>
<label class="radio-inline">
<input type="radio" name="test" value="logo"/>
<span><img src="http://i1.wp.com/www.r-bloggers.com/wp-content/uploads/2016/02/Rlogo.png?resize=300%2C263"/></span>
</label>
</div>
</div> ')),
br(),
h3(textOutput('selected'))
))
If you need to do this many times, you can define a radioButtons_withHTML
function:
radioButtons_withHTML <- function (inputId, label, choices, selected = NULL, inline = FALSE,
width = NULL)
{
choices <- shiny:::choicesWithNames(choices)
selected <- if (is.null(selected))
choices[[1]]
else {
shiny:::validateSelected(selected, choices, inputId)
}
if (length(selected) > 1)
stop("The 'selected' argument must be of length 1")
options <- generateOptions_withHTML(inputId, choices, selected, inline,
type = "radio")
divClass <- "form-group shiny-input-radiogroup shiny-input-container"
if (inline)
divClass <- paste(divClass, "shiny-input-container-inline")
tags$div(id = inputId, style = if (!is.null(width))
paste0("width: ", validateCssUnit(width), ";"), class = divClass,
shiny:::controlLabel(inputId, label), options)
}
generateOptions_withHTML <- function (inputId, choices, selected, inline, type = "checkbox")
{
options <- mapply(choices, names(choices), FUN = function(value,
name) {
inputTag <- tags$input(type = type, name = inputId, value = value)
if (value %in% selected)
inputTag$attribs$checked <- "checked"
if (inline) {
tags$label(class = paste0(type, "-inline"), inputTag,
tags$span(HTML(name)))
}
else {
tags$div(class = type, tags$label(inputTag, tags$span(HTML(name))))
}
}, SIMPLIFY = FALSE, USE.NAMES = FALSE)
div(class = "shiny-options-group", options)
}
The difference with the original one is calls generateOptions_withHTML
to create the names of the buttons, and I added the HTML()
function around name
in the tags$span
to prevent the escaping. You can put these functions in another file and use source
.
You can then use radioButtons_withHTML('test', 'Radio buttons with MathJax choices',choices = choices, inline = TRUE)
to create your radioButtons
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With