Calling a shiny app from within KNIME

Hi,

Creating shiny applications to visualize plots etc. from R output is very convenient and makes things quite interactive. I am wondering whether there would be a possibility to call these apps from within KNIME using the R scripting tools.
I tried to create a minimal example for a shiny app and pasted this into the R snippet node:

knime.out <- knime.in
library(shiny)

# Define UI ----
library(shiny)

# Define UI ----
 ui <- fluidPage(
 titlePanel("Test")
      
 )

# Define server logic ----
 server <- function(input, output) {
      
}
# Run the app ----
shinyApp(ui = ui, server = server)

This gives the following error:

ERROR R Snippet            0:7        Execute failed: R evaluation failed.: "knime.tmp.ret<-NULL;printError<-function(e) message(paste('Error:',conditionMessage(e)));for(exp in tryCatch(parse(text=knime.tmp.script),error=printError)){tryCatch(knime.tmp.ret<-withVisible(eval(exp)),error=printError)
if(!is.null(knime.tmp.ret)) {if(knime.tmp.ret$visible) tryCatch(print(knime.tmp.ret$value),error=printError)}};rm(knime.tmp.script,exp,printError);knime.tmp.ret$value"

What do you think? Would it be possible to tweak the KNIME R implementation so that it just opens the app in the browser (similar to the javascript data visualization tools in KNIME).
Thanks a lot!
Cheers,
Fritz

Hi!
I’m investigating the possibility to use shiny apps in knime JS views too.

The main problem is that shiny apps use a mini-http server in R, so they run indefinitely, while a KNIME R source node need the R script to end its work.
So I considered the use of R Future library package which allows to run the http server in parallel to the main R script.
In the R script node, you can use the following skeleton for your shiny app:

library(shiny)
library(future)

ui <- fluidPage(
  titlePanel("Title"),

	#action to close the server
  actionButton("close", "Click to disconnect"),

	#your UI code...
)

server <- function(input, output) {
	#stop server, freeing resources
  observeEvent(input$close, {
    stopApp()
  })
  #your server code...  
}

#run server in parallel
plan(multisession)
app <- shinyApp(ui, server)
f <- future({  
  runApp(appDir=app, host=knime.flow.in[["host_ip"]], port=knime.flow.in[["host_port"]], launch.browser=FALSE)
})

“host_ip” and “host_port” are two flow variables, used to configure the R mini-http server . Their value can be 127.0.0.1 and 6767 respectively.
Please note the "Click to disconnect" button, which the user has to press in order to stop the shiny app in the parallel process: this is necessary to avoid the R mini-http server to run indefinitley. I haven’t found yet a better solution

In order to view the shiny app, I connected the R script node to a Generic JS node via a flow variable connector.
The Generic JS node has the following content:

var body = document.getElementsByTagName('body')[0];
var address = "http://$${Shost_ip}$$:$${Shost_port}$$"; 
var html += "<iframe src=\""+ address +"\" height=\"400\" width=\"800\"></iframe>";
body.innerHTML = html;

There are still important issues that have to be resolved here, expecially when I’m crazy enough to think the usage of shinyApps in a KNIME Server.
It’s frightening, when you think about the uncontrolled parallel R processes spawned by several KNIME jobs! The need to stop them automatically is a prority here . Moreover there would be serious security issues .

Maybe some hacking in shinApp R code might be needed…

3 Likes

Hi there,

I am sorry it took me a while to answer your post. But this is awesome I am glad to see that other people started looking into using shiny apps in KNIME.
So I tried to follow your example as good as I could (no experience with java script…) and still get an error when opening the generic java script view.
The code I used in the R snippet:

library(shiny)
library(future)

ui <- fluidPage(
  titlePanel("Title"),

	#action to close the server
  actionButton("close", "Click to disconnect")

	#your UI code...
)

server <- function(input, output) {
	#stop server, freeing resources
  observeEvent(input$close, {
    stopApp()
  })
  #your server code...  
}

#run server in parallel
plan(multisession)
app <- shinyApp(ui, server)
f <- future({  
  runApp(appDir=app, host="127.0.0.1", port="6767", launch.browser=FALSE)
})
knime.out <- knime.in

The code in the generic javascript view:

var body = document.getElementsByTagName('body')[0];
var address = "http://127.0.0.1:6767"; 
var html += "<iframe src=\""+ address +"\" height=\"400\" width=\"800\"></iframe>";
body.innerHTML = html;

The error I get:

Error in script
eval@[native code]
file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/js/base/node/viz/generic/knime-generic-view-v3.js:62:13
execCb@file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:12902
check@file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:6639
file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:9059
file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:819
file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:9516
each@file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:290
emit@file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:9487
check@file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:7196
enable@file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:9386
init@file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:5744
h@file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:4308
completeLoad@file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:12127
onScriptLoad@file:///var/folders/02/yxgp544x0m739fd1x4z735lh000qsp/T/knimeViewContainer3628/org/knime/core/require.js:5:13064

If anyone has an idea how to solve this I would be very grateful! Thanks a lot!
Cheers,
Fritz

I’m sorry, I made a typing error in the Javascript code.
I attached here a demo KNIME workflow:
TestShinyApp.knwf (8.9 KB)

Regards
Fabrizio

1 Like

Hi,
One thing that I did to avoid the server running forever is to add this line in the server function:

session$onSessionEnded(stopApp)

It automatically stops the server when the first client disconnects.
Kind regards,
Alexander

1 Like