Displaying HTML that is stored in a character vector

1,884 views
Skip to first unread message

David McGarry

unread,
Jun 6, 2013, 10:06:23 PM6/6/13
to shiny-...@googlegroups.com

I am trying to build a quick application that displays a random HTML page  but am running into problems with displaying the HTML. I believe this is related to R storing the character vectors with escape characters and shiny expecting non-escaped HTML, but I'm not positive on that.

I have a static data frame consisting of HTML page IDs and the corresponding HTML content that looks like this: 

> str(dat)
'data.frame':	61 obs. of  2 variables:
 $ msgid: chr  "msgids..." 
 $ html : chr  "html content..."

I also have a reactiveValue object that stores, among other things, the current email:

  servervar <- reactiveValues()

And a function that grabs a random email to view, that looks like this:

  grab.msg <- function() {
    servervar[["msg"]] <- dat[sample(nrow(dat),1),]
  }

I want to pass the html in my "servervar" reactiveValue object to UI so it can be printed (among other things). To do this I I'm using a renderText() function to return the html content:

output$msghtml <- renderText(function(){
    servervar$msg[["html"]])
    })
  
And then in the ui.R file I am attempting to display this html content via:

wellPanel(htmlOutput("msghtml"))

This almost works, but isn't quite there. The problem is that my html content has a bunch of escape characters from R and thus is not formed correctly. For example this HTML:

        <HTML>
            <p>some content</p>
            <p> some more content </p>
        </HTML>

Looks like this:

"\t\t<HTML>\t\t\t<p>some content</p>\t\t  \t<p> some more content </p>\t\t</HTML>"

The escape characters are actually a bigger deal than just tabs (like in the example above), because some image links are broken completely and for some HTML pages Shiny throws a Javascript error and breaks down (the html pages load just fine when dragging into a browser). Does anyone have an idea about how to get around this issue? I tried using textOutput() instead of htmlOutput() in the ui.R file, but doesn't seem to work either.

Thanks!

Ramnath Vaidyanathan

unread,
Jun 6, 2013, 10:28:46 PM6/6/13
to shiny-...@googlegroups.com
Just wrap it inside an HTML call.

output$msghtml <- renderUI(function(){
    HTML(servervar$msg[["html"]]))
 })

David McGarry

unread,
Jun 6, 2013, 11:24:43 PM6/6/13
to shiny-...@googlegroups.com
That doesn't seem to be working for me. What would the corresponding grab in the ui.R file? htmlOutput() is acting exactly the same and textOutput() is simply printing the raw HTML text on the page.


--
You received this message because you are subscribed to a topic in the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/shiny-discuss/0KdGnRYR9Kg/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to shiny-discus...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Ramnath Vaidyanathan

unread,
Jun 7, 2013, 7:14:44 AM6/7/13
to shiny-...@googlegroups.com
Can you try renderText, instead of renderUI? The other possibility is to move the HTML function out of renderText into htmlOutput

David McGarry

unread,
Jun 7, 2013, 10:20:27 AM6/7/13
to shiny-...@googlegroups.com
I had already tried just about every permutation of those options and had no luck. Although it does work if I change the workflow from making a data frame with the HTML content and instead create an HTML file for each message and then read them in  via: 

HTML(paste(scan(file="<html page>",what=character(),sep="\n")),collapse="")

That isn't the approach that I wanted to take originally, but it should work for me.

Ramnath Vaidyanathan

unread,
Jun 7, 2013, 10:52:05 AM6/7/13
to shiny-...@googlegroups.com
Can you post a small subset of your data frame? It would be easier to test that way.

David McGarry

unread,
Jun 7, 2013, 11:20:16 AM6/7/13
to shiny-...@googlegroups.com
Unfortunately I cannot post any of my actual data, do it's sensitivity.

David McGarry

unread,
Jun 7, 2013, 12:49:32 PM6/7/13
to shiny-...@googlegroups.com
This actually isn't working for me it. It's really odd, if I hardcode the file in the ui.R file it works perfectly but I cannot seem to pass the file link from the server.R file and have it load correctly. For example this works in the ui.R file:

      wellPanel(HTML(paste(scan(file=<file name>,what=character(),sep="\n")),collapse="")) 

But this does not work:
ui.R:
wellPanel(htmlOutput("msghtml"))

*also tried: textOutput and uiOutput

server.R:
   output$msghtml <- renderText(function(){
      HTML(paste(scan(file=<file name>,what=character(),sep="\n")),collapse="")  
    })

*also tried: renderUI


Is there someway that I can simply pass the file name from the server.R to ui.R and then plug that into the working command at the top? For example, is there there I way I could reference the output object formed in server.R to do something like this in the ui.R file:

wellPanel(HTML(paste(scan(file=output$filename,what=character(),sep="\n")),collapse="")) 

Ramnath Vaidyanathan

unread,
Jun 7, 2013, 1:00:27 PM6/7/13
to shiny-...@googlegroups.com
includeHTML

Joe Cheng

unread,
Jun 7, 2013, 1:22:17 PM6/7/13
to shiny-...@googlegroups.com
If the only problem is your HTML has extra R escaping in it, then it's possible to undo that escaping.

unescape <- function(text) {
  parsed <- parse(text=text)
  if (length(parsed) != 1 || length(parsed[[1]]) != 1 || typeof(parsed[[1]]) != "character")
    stop("Invalid R literal string")
  as.character(parsed[[1]])
}

output$msghtml <- renderText({
  unescape(paste0('"', servervar$msg[["html"]], '"'))
})

However it'd be much, much better not to have that extra R escaping in the strings in the first place, as this approach is quite fragile; if servervar$msg[["html"]] doesn't contain a string that is parseable by R, you'll get a parse error.

I'm sure R is not inherently adding the escaping for you. R doesn't escape strings when it reads them, only when you print to the console (you can confirm this by using cat instead of print). If I were you I'd really focus in on how that escaping is getting into your data frame in the first place.


You received this message because you are subscribed to the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this group and stop receiving emails from it, send an email to shiny-discus...@googlegroups.com.

David McGarry

unread,
Jun 7, 2013, 1:23:27 PM6/7/13
to shiny-...@googlegroups.com
I'm sorry can you please provide a few more details? What would the full call be in the ui.R and server.R files? I've tried just about every combination that I can think of and am getting the error:

 addFileDependency was called at an unexpected time (no cache context found)

This is what I tried:

ui.R
shinyUI(bootstrapPage(
  wellPanel(uiOutput("msghtml"))
))

*also tried: htmlOutput and textOutput

server.R
    output$msghtml <- renderUI(function(){
        includeHTML(<file path>)
    })

*also tried: renderText

David McGarry

unread,
Jun 7, 2013, 1:30:45 PM6/7/13
to shiny-...@googlegroups.com
@Joe - I honestly don't know if escaping is the issue or not. All that I know is that everything works great when I reference a hardcoded file in ui.R but that everything breaks once I try to read in that file from the server.R and pass that character vector to ui.R. I was just looking on your documentation and saw that there is the ability to have global variables via global.r, so I may try to figure out how to simply define a global variable for the file path, so that I can simply reference the file-path directly in the ui.R file. 

David McGarry

unread,
Jun 7, 2013, 3:13:04 PM6/7/13
to shiny-...@googlegroups.com
I've found an example HTML message that can I can safely share so others can create a reproducible example. Consider a file named "test.msg", stored here (due to its length):  https://www.dropbox.com/s/spxglwjuced134b/test.msg

Also consider a data.table (or data.frame) named "dat" that has two columns, "msgid" and "msglink", where the "msglink" contains links to messages files. So, for example, dat[2,msgid] will return "test.msg", which references the html message above.

Now everything works when I reference this hardcoded from the ui.R file. So for example this works perfectly:

ui.R
shinyUI(bootstrapPage(
  wellPanel(HTML(readLines(dat[2,msglink])))
))

server.R
shinyServer(function(input, output) {
})

However the problem with this is that I would like to be able to randomly select a random message from the "dat" object reference and display and I will need to reference the "msgid" of that message within server.R to do some extra things. With this in mind I am attempting to pass the message from server.R to ui.R but have not had any luck. I've tried everything already discussed in this thread, but for further reference none of these approaches has worked:

ui.R
shinyUI(bootstrapPage(
  wellPanel(uiOutput("msghtml"))
))


server.R
shinyServer(function(input, output) {
  output$msghtml <- renderText(function(){
      HTML(readLines(dat[1,msglink]))
  })
})

OR

ui.R
shinyUI(bootstrapPage(
  uiOutput("msghtml")
))

server.R
shinyServer(function(input, output) {
  output$msghtml <- renderUI({
    wellPanel(HTML(readLines(dat[2,msglink])))
  })
})


In the above examples you can pretty safely assume I've tried basically every combination of using subbing out a command for: textOutput, htmlOutput and includeHTML. 

Any ideas on anyway to work around this issue?

Winston Chang

unread,
Jun 7, 2013, 3:22:45 PM6/7/13
to shiny-...@googlegroups.com
I think you can do something like this. Just make sure the renderText expression returns the raw HTML as a string:


ui.R
shinyUI(bootstrapPage(
  wellPanel(htmlOutput("raw_html"))
))

server.R
shinyServer(function(input, output) {
  output$raw_html <- renderText({
    # Replace this with the desired HTML
    "<div><b>Bold text</b> Regular text</div>"
  })
})

-Winston



--
You received this message because you are subscribed to the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this group and stop receiving emails from it, send an email to shiny-discus...@googlegroups.com.

David McGarry

unread,
Jun 7, 2013, 3:30:41 PM6/7/13
to shiny-...@googlegroups.com
I'm sorry Winston but am I misreading something? I do not see how that differs from what I posted was not working. It sounds like you are suggesting:

ui.R
shinyUI(bootstrapPage(
  wellPanel(htmlOutput("raw_html"))
))

server.R
shinyServer(function(input, output) {
  output$raw_html <- renderText({
      readLines("test.msg")
  })
})

That does not work for me with the test.msg file I linked to my previous post.

Ramnath Vaidyanathan

unread,
Jun 7, 2013, 3:36:41 PM6/7/13
to shiny-...@googlegroups.com
readLines does not return a character string. It returns a vector. You can do

paste(readLines('test.msg'), collapse = '\n'))

David McGarry

unread,
Jun 7, 2013, 3:39:38 PM6/7/13
to shiny-...@googlegroups.com
Sorry, for not being more clear. I had testing collapsing character vectors into a single string via scan() a while ago and that did not make a difference. Just doubled checked with that exact line and it did not work.

Winston Chang

unread,
Jun 7, 2013, 3:57:10 PM6/7/13
to shiny-...@googlegroups.com
With this code:
ui.R
shinyUI(bootstrapPage(
  wellPanel(htmlOutput("raw_html"))
))

server.R
shinyServer(function(input, output) {
  output$raw_html <- renderText({
      paste(readLines("test.msg"), collapse = "\n")
  })
})

and with the particular file that you sent, I see this in the Javascript console (in Chrome):
  WebSocket connection to 'ws://localhost:8100/' failed: Could not decode a text frame as UTF-8. 

So it may have something to do with character encodings:

I'm not sure what the best solution is just yet..

-Winston


David McGarry

unread,
Jun 7, 2013, 4:30:39 PM6/7/13
to shiny-...@googlegroups.com
Thanks for the tip! That makes sense to me, although I'm also not sure how to get around the issue. I just find it really odd how it works when directly called from ui.R

Joe Cheng

unread,
Jun 7, 2013, 5:04:50 PM6/7/13
to shiny-...@googlegroups.com
Ah, that's exactly it. The data in test.msg appears to be corrupted. There are non-ASCII characters where it looks like they do not belong, for example on line 80 immediately following "http://links.insider.opentable.com/ctt?kn". In fact, all over the documented the string "?kn" is always followed by corruption of one kind or another (either non-ASCII characters, or, an ASCII character that doesn't make sense in that context).

So forget the escaping, none of that has anything to do with anything at this point. Sorry but I misread your earlier e-mails, I thought the text was appearing in the Shiny app both ways, just with extra characters or whatever. Now that I see that the whole app is failing with an error, it's obvious that this is the problem.

When you pass a non-ASCII string as an output to Shiny, it attempts to convert it to UTF-8 as that is the only kind of encoding that WebSockets support. Not only that, but the WebSockets standard says that if invalid UTF-8 data is encountered, then this is an error that causes the socket to be closed.

The same is not true when a browser loads a webpage in the normal way, over HTTP; for better or worse, the traditional behavior is to be very tolerant of invalid stuff in HTML pages. That's why ui.R works (it is loaded like a normal webpage) but not server.R (it is communicated over websocket).

You could fix this by processing your HTML string to strip out the invalid characters. But a better question, again, would be how those characters are getting in there in the first place.

David McGarry

unread,
Jun 7, 2013, 7:06:14 PM6/7/13
to shiny-...@googlegroups.com
Thanks Joe that does make sense. I'll see if I can trip the characters out, but do you have any idea why they display without issues when directly referenced from the ui.R? I certainly don't understand the backend of how Shiny works, but that just really confuses me.

David McGarry

unread,
Jun 7, 2013, 7:14:22 PM6/7/13
to shiny-...@googlegroups.com
I'm sorry, I've had a long day... I just re-read your message and now understand your section about why it loads from ui.R. Thanks for all of your help. If you know of workaround to be able to display these messages directly from ui.R (for example simply passing a an index from server.R to ui.R that can be used to call-up the desired msg) that would be much appreciated, but even if I can't use Shiny for this purpose it's great knowing why it isn't working (and Shiny has worked great for me when dealing with more traditional and cleaner data).

Thanks again!

David McGarry

unread,
Jun 7, 2013, 7:44:42 PM6/7/13
to shiny-...@googlegroups.com
Sorry for the spam of messages, but just wanted to let you know that the problem was definitely with encoding. I just ran the messages through some encoding to fix it up and everything appears to be working right now. Thanks again for all of your help!

Joe Cheng

unread,
Jun 10, 2013, 11:58:06 AM6/10/13
to shiny-...@googlegroups.com
Great, glad to hear it all worked out!
Reply all
Reply to author
Forward
0 new messages