Interactive graphics displayed in a web browser. Very easy to create. Our task – create an interactive volcano plot for viewing the output of differential expression analysis.
Create a folder for our project; call it Volcano
. Now add two
plain-text files ui.R
and server.R
.
|-- Volcano
|-- ui.R
|-- server.R
Add the following code to ui.R
. This specifies the 'user interface'
to be a page with a side-bar. The page will have a header at the top,
a side bar panel, and a main panel.
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Volcano!"),
sidebarPanel(),
mainPanel()
))
Now add the following code to server.R
. This doesn't do anything!
library(shiny)
shinyServer(function(input, output) {
})
OK, now, start R and run the following commands. Make sure the
argument to runApp
is the path to the folder you created.
library(shiny)
runApp("Volcano")
That's it! Not very exciting.
Keep your R session and web browser running.
a. Let's ask the user to identify themselves by editing ui.R
…
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Volcano!"),
sidebarPanel(
textInput("name", "Your name:")),
mainPanel()
))
Return to your browser, re-load the page, and check out what you can
do! See an error? Probably you forgot a comma at the end of a line or
made another mistake. Read the error, correct ui.R
, and reload the
page.
b. OK, the server.R
is going to take your input and return some
output. It does this using the arguments input
and output
. Each of
these is a list, with elements named after fields (like "name"
,
above) or return values. The following takes the name input by user,
creates a greeting, and renders the result in a way that shiny
can
work with.
library(shiny)
shinyServer(function(input, output) {
output$greeting <- renderText(
paste("greetings", input$name, "how R you?"))
})
You should be able to re-load the page in the browser. It might be the case that the screen goes grey, in which case there is an error in your server code. Check back at where you started R to see what is going wrong, fix the problem, and re-load the page.
c. Notice that shiny
doesn't appear to do anything when you enter a
name. Actually, it's waiting to have to do something – so far,
there's no feedback for the user, so no need to formulate a
greeting. So…
In the ui.R
file, arrange for the greeting to be displayed by
updating the mainPanel
:
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Volcano!"),
sidebarPanel(
textInput("name", "Your name:")),
mainPanel(
textOutput('greeting'))
))
Reload the page in the browser and try entering or changing your name. Try editing the server code so that it only responds if the user has entered a name.
library(shiny)
shinyServer(function(input, output) {
output$greeting <- renderText({
if (nchar(input$name) == 0)
character()
else
paste("greetings", input$name, "how R you?")
})
})
Cool!
We'll go through the same same routine, modify the user interface to accept different input, then the server to respond to the new input, and finally the user interface that will trigger the server. The instructions are shorter, because the changes are pretty self-explanatory.
a. Add a fileInput()
widget to your user interface. The
'dataFile'
string is the name of a variable that will contain
information about how to upload the file.
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Volcano!"),
sidebarPanel(
fileInput("datafile", "Choose topTable CSV File")),
mainPanel()
))
Return to your browser, re-load the page, and check out what you can do!
b. Implement the actual data input on the server. This uses the
renderDataTable
function to return a table to the user interface. The
"dataFile"
variable is NULL if the user has not selected a file, and
has several elements if the user has selected a file.
library(shiny)
shinyServer(function(input, output) {
output$toptable <- renderDataTable({
if (is.null(input$datafile))
return(NULL)
read.csv(input$datafile$datapath)
}, options=list(pageLength=5))
})
You should be able to re-load your page in the browser, but there is not any new functionality visible.
c. Finally, modify ui.R
to display the head of the table
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Volcano!"),
sidebarPanel(
fileInput('datafile', 'Choose topTable CSV File')),
mainPanel(
dataTableOutput('toptable'))
))
Check out what you've created now.
Let's now create a volcano plot.
a. We don't need to change the user input, so jump directly to (b).
b. First we'll implement this to read in the data, but we'll change
that… I'll make my plot using lattice
, but use ggplot2
or
whatever environment you'd like; remember to load any additional
required libraries in the server.
library(shiny)
library(lattice)
shinyServer(function(input, output) {
output$toptable <- renderDataTable({
if (is.null(input$datafile))
return(NULL)
read.csv(input$datafile$datapath)
}, options=list(pageLength=5))
output$volcano <- renderPlot({
if (is.null(input$datafile))
return(NULL)
csv <- read.csv(input$datafile$datapath)
print(xyplot(-log10(pvalue) ~ log2FoldChange, csv))
})
})
c. And for displaying the plot (first, above the table)
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Volcano!"),
sidebarPanel(
fileInput('datafile', 'Choose topTable CSV File')),
mainPanel(
dataTableOutput('toptable'),
plotOutput('volcano', width="400px"))
))
Check out your handiwork! (How do I know what to do? I'm reading the
shiny tutorial and looking at the help pages, e.g.,
?plotOutput
).
Clean up the server code so that only one function reads in the
data. Use the reactive
function to indicate that the data input
depends on user input. Adjust the top table and volcano plot
functions to use this single data input function.
Update the server code to order the top table from largest to smallest absolute value log fold change, and to return only the top 20 values for visualization.
After exercises 1 and 2 my server.R
looks like
library(shiny)
library(lattice)
shinyServer(function(input, output) {
dataInput <- reactive({
if (is.null(input$datafile))
return(NULL)
read.csv(input$datafile$datapath)
})
output$toptable <- renderDataTable({
csv <- dataInput()
if (is.null(csv))
return(NULL)
o <- order(abs(csv$log2FoldChange),
decreasing=TRUE)
csv[head(o, 20),]
}, options=list(pageLength=5))
output$volcano <- renderPlot({
csv <- dataInput()
if (is.null(csv))
return(NULL)
print(xyplot(-log10(pvalue) ~ log2FoldChange, csv))
})
})
Add some input widgets to ui.R
, e.g., to allow the user to
specify different arguments to read.csv
, and implement these in
server.R
.
Check out the ReportingTools and AnalysisPageServer packages for pre-built interactive reports.