Shiny application on multiple browser windows

2,255 views
Skip to first unread message

federico....@gmail.com

unread,
Jun 4, 2015, 5:11:30 PM6/4/15
to shiny-...@googlegroups.com
Hi all,

First of all thanks and congrats for developing Shiny, it's really an amazingly powerful tool.

I was wondering if there is any way to have an application controlling multiple browser windows. The scenario is the following... I have a pretty complex UI that is used to browse some data. I would like to select some pieces of data and generate some plots on a separate browser window. The reason why I need multiple windows is that the UI is already pretty cluttered and the plot region simply doesn't fit in it.

Thanks in advance for your help,

Federico


Dean Attali

unread,
Jun 4, 2015, 6:58:00 PM6/4/15
to shiny-...@googlegroups.com
Are you sure you want to use multiple *browser windows*? That's quite complicated, but it sounds like what you want is simply tabbed content, have you thought about using tabs?
Check out these two shiny examples

federico....@gmail.com

unread,
Jun 4, 2015, 7:27:56 PM6/4/15
to shiny-...@googlegroups.com
Hi Dean,

Thanks for the suggestion, I am familiar with tabsets and navbars. The problem is that I don't want the user to deal with switching back and forth between tabs. The UI allows the interactive manipulation of a graph and I want the user to be able to plot node/vertex data in a separate window.

Federico

Dean Attali

unread,
Jun 4, 2015, 8:28:19 PM6/4/15
to shiny-...@googlegroups.com
Hmmm.. I was able to get something working, but it's pretty hacky and I'm not sure I'd recommend using it.  I've never tried doing something like this, hopefully someone more experienced will chime in. My main idea was to have a button on the main app that opens another window with a certain GET param. If that param in the URL is set, then the UI will hide all the inputs and only show the plot; otherwise, show the inputs and hide the plot. I created a reactive value outside of the server function so that it will be shared among the open sessions. When the input changes, it updates the reactive value, and the other window listens to that reactive value for plotting.

To facilitate with showing/hiding the UI elements, I'm using (disclaimer: I wrote this package) `shinyjs` package.

The code isn't too messy but the concept itself isn't very clean, that's just my first idea off the top of my head. There's probably better solutions.

library(shinyjs)

values <- reactiveValues(num = NULL)

runApp(shinyApp(
  ui = fluidPage(
    useShinyjs(),
    hidden(
      div(
        id = "inputsWindow",
        numericInput("num", "Number", 10),
        tags$a("Open plot window", href = "?plot=true", target = "_blank")
      ),
      div(
        id = "plotWindow",
        plotOutput("plot")
      )
    )
  ),
  server = function(input, output, session) {
    observe({
      query <- parseQueryString(session$clientData$url_search)
      if (is.null(query[['plot']])) {
        show("inputsWindow")
      } else {
        show("plotWindow")
      }
    })
    
    observeEvent(input$num, {
      values$num <- input$num
    })
    
    output$plot <- renderPlot({
      plot(seq(values$num))
    })
  }
))

federico....@gmail.com

unread,
Jun 5, 2015, 1:46:06 PM6/5/15
to shiny-...@googlegroups.com
Thank you very much for your help Dean! I'll definitely try this out and I'll let you know what happens.


Federico

Joe Cheng

unread,
Jun 5, 2015, 2:03:03 PM6/5/15
to federico....@gmail.com, shiny-...@googlegroups.com
This will create two independent sessions though--the inputs in the main page won't be connected to the output in the newly spawned window.

I don't think there's a way to do this that doesn't involve quite a bit of JavaScript (window.open)...

--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/shiny-discuss/440a7cde-0e83-4de8-8e40-bfd02e9e0d2d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

federico....@gmail.com

unread,
Jun 5, 2015, 9:14:50 PM6/5/15
to shiny-...@googlegroups.com
Ok I have slightly modified Dean's approach and I am getting closer. I want to put this up on Github as an example but I am stuck with a final last detail

Basically I am using the idea illustrated here


which involves leveraging localStorage to pass data between two tabs. From the control window I am grabbing the img src data, storing it in the local storage, and broadcasting a message. The tab that receives the message then fetches the data from the local storage and displays it. I am using jQuery throughout to manipulate the DOM.

I can trigger the whole process correctly by manually broadcasting the message but I need to find a way to automatically broadcast the message after shiny updates the plot when the input control is changed. I have tried to use $("img").on("load") to capture the fact that shiny has updated the plot but it is not working.

Is there a way to execute a piece of javascript when shiny finishes updating an output? I know I could create a new outputBinding but I was wondering if there is an easier way.

Thanks again,

Federico

federico....@gmail.com

unread,
Jun 9, 2015, 7:21:19 PM6/9/15
to shiny-...@googlegroups.com, federico....@gmail.com
Hi again,

I've put up an example app on github here


It's rather convoluted but I tried to keep things as invisible to shiny as possible. A couple of observations:

1) It would be nice to have the possibility to register javascript callbacks to be executed immediately before/after shiny updates an element.
2) Is there any way to modify the scope argument that is passed to the "find" function of custom output elements (http://shiny.rstudio.com/articles/building-outputs.html)? I think the best approach for multiple windows would be to have a way to pass a window handle to the "find" function of a custom output element. 

Thanks everyone for your help,

Federico


On Friday, June 5, 2015 at 11:03:03 AM UTC-7, Joe Cheng [RStudio] wrote:

Dean Attali

unread,
Jun 9, 2015, 8:43:09 PM6/9/15
to federico gherardini, shiny-...@googlegroups.com
Cool, I see you did use my idea, nice to see it in action. I just want to note that you won't be able to have two separate sessions using this approach - if you load the main app in multiple tabs, the latest session will be the one that writes the plot to all open plot tabs

--
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/DNlnC3JGNBI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to shiny-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/shiny-discuss/3d70bdbd-e386-45a6-a86c-4a1a1a584547%40googlegroups.com.

Dean Attali

unread,
Jun 14, 2015, 8:39:36 PM6/14/15
to shiny-...@googlegroups.com, federico....@gmail.com
I just found out about shinyStore package by Jeff Allen

It's using HTML5 local storage, might be worth looking into
To unsubscribe from this group and all its topics, send an email to shiny-discuss+unsubscribe@googlegroups.com.

Ehson Ghandehari

unread,
Nov 29, 2017, 1:54:05 AM11/29/17
to Shiny - Web Framework for R
Hi Federico,

Thanks for working on this challenge. I am interested to plot a plotly object in a separate browser tab.
I ran the code that you provided on the GitHub link below. However, after clicking on the "Open Plot Window," button, only a blank window pops up.
In other words, I cannot see the plot in the new popped up window.

Would you please guide me through how to solve this issue?

Thanks.

Luke Rogers

unread,
Oct 17, 2018, 5:07:12 PM10/17/18
to Shiny - Web Framework for R
Ehson-

To get it to work you need to change the event listener from DOMNodeInserted to DOMAttrModified in the window_communication.js file:

document.addEventListener("DOMAttrModified", function(e) {
  //This event is fired when shiny updates the plot. Listen for it
  //and call plot_send which will store the image in the local storage  console.log('DOMAttrModified');
  if(e.target && e.target.parentNode.id == "plot") {
    plot_send();
 }
});
Reply all
Reply to author
Forward
0 new messages