library(shiny)
library(PeakMapper)
library(ggplot2)
ui <- fluidPage(
tags$h1(tags$b("PeakMapper:"),"Flexible mapping of genomic coordinates to nearest
features"),
tags$hr(),
tabsetPanel(
# Use of the uiOutput function to create drop-down menus that update as new
# datasets are imported or created is based on code from the following RStudio
# Shiny tutorial: https://shiny.rstudio.com/articles/dynamic-ui.html (full
# reference provided in the documentation for runPeakMapperApp())
# This tab allows the user to import their own datasets using importBED
tabPanel("Step 1: Import datasets",
sidebarLayout(
sidebarPanel(
tags$p("Import your files of peak coordinates and feature coordinates,
in BED format. All imported files will remain usable for mapping
until the app is closed. BED files can also be previewed here
after importing them."),
tags$p("An example peak file (H3K27me3PeaksSmall.bed) and an example
feature file (WS263Genes.bed) can be found in the extdata
subdirectory of PeakMapper."),
fileInput("file", "Select a dataset to import:"),
uiOutput("selectInput"),
actionButton(inputId = "button", label = "Display dataset")
),
mainPanel(tableOutput("previewTable"))
)
),
# This tab allows the user to map imported peaks onto imported features
# using mapPeaks
tabPanel("Step 2: Map peaks to features",
fluidRow(
column(4, wellPanel(
tags$p("Datasets imported in the previous step can be selected
from the following menus. After a peak dataset and a feature
dataset are selected from the appropriate menu, peaks can
be mapped onto their closest features by clicking the
'Map peaks onto features' button below. (This may take several
minutes for large datasets)"),
tags$p("Performing a peak-feature mapping will create a new dataset
of results that will remain usable until the app is closed.
Results can be displayed here as a table, and these results
can be exported as a CSV file using the 'Export' button."),
uiOutput("selectPeaks"),
uiOutput("selectFeatures"),
actionButton(inputId = "mappingButton", label =
"Map peaks onto features"),
textOutput("mappingMessage"),
tags$p(),
uiOutput("selectResult"),
actionButton(inputId = "mappingDisplayButton",
label = "Display selected mapping results"),
downloadButton("exportButton",
"Export selected mapping results as CSV file"),
tags$p(),
tags$p("(For proper file exporting, the filename you give this CSV
should end with '.csv')")
))),
fluidRow(
column(12, tableOutput("mappingTable"))
)
),
# This tab allows the user to visualize the results of mapping peaks onto
# closest features
tabPanel("Step 3: Visualize mapping results",
sidebarLayout(
sidebarPanel(
tags$p("After mapping peaks to closest features in the previous step,
the generated results can be visualized here using 4 different
types of plots. The datasets used to create these plots can be
selected from the two menus below. After mapping results and
their corresponding peak file are selected, along with the type
of plot to be made, plots can be generated by clicking the
'Generate plot' button at the bottom of this panel. Generated
plots can also be saved as PNGs by clicking the 'Save' button."),
uiOutput("selectResultsForPlotting"),
uiOutput("selectPeaksForPlotting"),
selectInput('selectPlotType',
'Select the type of plot you want to make:',
c("1. Plot the number of closest features to each peak",
"2. Plot locations of mapped peaks relative to start of closest features",
"3. Plot distribution of overlap proportions between peaks and closest features",
"4. Plot distribution of qualitative peak positions relative to mapped features")),
tags$p("The following 5 parameters can be used to customize the
appearance of the generated plot. Selecting a new plot type
from the above menu will update the boxes for main title, x-axis
title, and y-axis title to the default titles for that plot
type."),
textInput("plotColor", "Enter plot color:", "Red"),
textInput("mainTitle", "Enter main plot title:"),
textInput("xTitle", "Enter plot x-axis title:"),
textInput("yTitle", "Enter plot y-axis title:"),
selectInput("backgroundStyle", "Select style of plot background:",
c("blackAndWhite", "grey", "minimal")),
tags$p("The following three parameters are only used for plotting
locations of mapped peaks relative to the start of closest
features (plot type #2 on the above list). The number of base
pairs plotted upstream or downstream of feature start points
(by default, 2500 bp) is the number of bins (default: 250)
times the number of bases per bin (default: 10). Fewer bases
per bin gives a higher resolution view of peak distribution"),
numericInput("upstreamBins", "Enter the number of bins (plotted points)
to be used upstream of each feature start position:", 250),
numericInput("downstreamBins", "Enter the number of bins (plotted points)
to be used downstream of each feature start position:", 250),
numericInput("basesPerBin", "Enter the width of each bin, in base pairs:", 10),
actionButton(inputId = "plottingButton", label = "Generate plot"),
downloadButton("savePlot", "Save current plot as PNG"),
tags$p(),
tags$p("(For proper plot saving, the filename you give this PNG should
end with '.png')")
),
mainPanel(plotOutput("mainPlot", height = "750px"))
)
)
)
)
# The use of the 'clientData' and 'session' parameters is based off of the
# following R Shiny tutorial used to update input fields based on user actions:
# https://shiny.rstudio.com/gallery/update-input-demo.html (full reference
# provided in the documentation for runPeakMapperApp())
server <- function(input, output, clientData, session) {
# Define reactive lists to hold the datasets that the user has imported, and
# the mapping results that the user has generated
selectableData <- reactiveValues()
mappingResults <- reactiveValues()
# Drop-down menus that the user can use to select imported datasets
# Use of renderUI to create drop-down menus that update as new datasets are
# imported is based on code from the following RStudio Shiny tutorial:
# https://shiny.rstudio.com/articles/dynamic-ui.html (full reference provided
# in the documentation for runPeakMapperApp())
output$selectInput <- renderUI({
selectInput('previewData', 'Select an imported dataset to display:',
names(reactiveValuesToList(selectableData)))
})
output$selectPeaks <- renderUI({
selectInput('selectedPeak', 'Select an imported peak file for mapping:',
names(reactiveValuesToList(selectableData)))
})
output$selectFeatures <- renderUI({
selectInput('selectedFeature', 'Select an imported feature file for mapping:',
names(reactiveValuesToList(selectableData)))
})
output$selectPeaksForPlotting <- renderUI({
selectInput('selectedPeaksForPlotting',
'Select the peak file used to generate these mapping results:',
names(reactiveValuesToList(selectableData)))
})
# Drop-down menus that the user can use to select results generated by
# mapping peaks onto features
# Use of renderUI to create drop-down menus that update as new datasets are
# imported is based on code from the following RStudio Shiny tutorial:
# https://shiny.rstudio.com/articles/dynamic-ui.html (full reference provided
# in the documentation for runPeakMapperApp())
output$selectResult <- renderUI({
selectInput('selectedResult', 'Select mapping results to display or export:',
names(reactiveValuesToList(mappingResults)))
})
output$selectResultsForPlotting <- renderUI({
selectInput('selectedResultsForPlotting',
'Select mapping results to plot:',
names(reactiveValuesToList(mappingResults)))
})
# When the user inputs a file, import it using importBED and add it to
# selectableData
observeEvent(input$file, {
newName <- input$file$name
selectableData[[newName]] <- PeakMapper::importBED(input$file$datapath)
})
# When the user presses the preview button in Step 1, update the table to
# display the selected BED file
selectedData <- eventReactive(input$button, {
selectableData[[input$previewData]]
})
output$previewTable <- renderTable(selectedData())
# When the user presses the mapping button in Step 2, map peaks onto features
# using mapPeaks
observeEvent(input$mappingButton, {
peakName <- input$selectedPeak
featureName <- input$selectedFeature
resultName <- paste(
"Peaks: ", peakName, ", Features: ", featureName, sep = "")
mappingResults[[resultName]] <- PeakMapper::mapPeaks(
selectableData[[peakName]],
selectableData[[featureName]])
output$mappingMessage <- renderText(paste("Peaks in ", peakName,
" successfully mapped onto features in ",
featureName, ". Results can be selected ",
"in the menu below.", sep = ""))
})
# When the user presses the display button in Step 2, update the table to show
# the currently-selected mapping results
mappingResult <- eventReactive(input$mappingDisplayButton, {
mappingResults[[input$selectedResult]]
})
output$mappingTable <- renderTable(mappingResult())
# When the user presses the plot generation button in Step 3, determine the
# type of plot to make based on the user's selection, and then create that
# plot using the user's selected data
mainPlot <- eventReactive(input$plottingButton, {
if (input$selectPlotType ==
"1. Plot the number of closest features to each peak") {
PeakMapper::plotNumMappingsPerPeak(
selectableData[[input$selectedPeaksForPlotting]],
mappingResults[[input$selectedResultsForPlotting]],
plotColor = input$plotColor,
mainTitle = input$mainTitle,
xTitle = input$xTitle,
yTitle = input$yTitle,
backgroundStyle = input$backgroundStyle)
} else if (input$selectPlotType ==
"2. Plot locations of mapped peaks relative to start of closest features") {
PeakMapper::plotPeakLocations(
mappingResults[[input$selectedResultsForPlotting]],
plotColor = input$plotColor,
mainTitle = input$mainTitle,
xTitle = input$xTitle,
yTitle = input$yTitle,
backgroundStyle = input$backgroundStyle,
upstreamBins = input$upstreamBins,
downstreamBins = input$downstreamBins ,
basesPerBin = input$basesPerBin)
} else if (input$selectPlotType ==
"3. Plot distribution of overlap proportions between peaks and closest features") {
PeakMapper::plotOverlapDistribution(
mappingResults[[input$selectedResultsForPlotting]],
plotColor = input$plotColor,
mainTitle = input$mainTitle,
xTitle = input$xTitle,
yTitle = input$yTitle,
backgroundStyle = input$backgroundStyle)
} else if (input$selectPlotType ==
"4. Plot distribution of qualitative peak positions relative to mapped features") {
PeakMapper::plotPeakOrientations(
mappingResults[[input$selectedResultsForPlotting]],
plotColor = input$plotColor,
mainTitle = input$mainTitle,
xTitle = input$xTitle,
yTitle = input$yTitle,
backgroundStyle = input$backgroundStyle)
}
})
output$mainPlot <- renderPlot(mainPlot())
# When the user selects the type of plot they want to create, update the text
# fields for the main title, x-axis title, and y-axis title to hold the default
# values for that plot type
# Code to update these text fields using updateTextInput is based on code
# provided in the following RStudio Shiny tutorial:
# https://shiny.rstudio.com/gallery/update-input-demo.html
# (full reference provided in the documentation for runPeakMapperApp())
titles <- reactiveValues()
observeEvent(input$selectPlotType, {
if (input$selectPlotType ==
"1. Plot the number of closest features to each peak") {
titles[["mainTitle"]] <- "Number of features closest to each peak"
titles[["xTitle"]] <- "Number of features per peak"
titles[["yTitle"]] <- "Number of peaks"
} else if (input$selectPlotType ==
"2. Plot locations of mapped peaks relative to start of closest features") {
titles[["mainTitle"]] <- "Peak positions relative to feature start"
titles[["xTitle"]] <- "Position relative to feature start (bp)"
titles[["yTitle"]] <- "Number of peaks"
} else if (input$selectPlotType ==
"3. Plot distribution of overlap proportions between peaks and closest features") {
titles[["mainTitle"]] <- "Distribution of feature overlaps by mapped peaks"
titles[["xTitle"]] <- "Proportion of feature overlapped by mapped peak"
titles[["yTitle"]] <- "Number of peak-feature pairs"
} else if (input$selectPlotType ==
"4. Plot distribution of qualitative peak positions relative to mapped features") {
titles[["mainTitle"]] <- "Position of peaks relative to closest features"
titles[["xTitle"]] <- "Relative peak position"
titles[["yTitle"]] <- "Number of peak-feature pairs"
}
updateTextInput(session, "mainTitle", value = titles[["mainTitle"]])
updateTextInput(session, "xTitle", value = titles[["xTitle"]])
updateTextInput(session, "yTitle", value = titles[["yTitle"]])
})
# The following 2 blocks of code that use the downloadHandler function to
# download data from the app are based off of code from the following
# RStudio Shiny tutorial: https://shiny.rstudio.com/articles/download.html
# (full reference provided in the documentation for runPeakMapperApp())
# Download the currently-selected mapping results when the user presses the
# export button
output$exportButton <- downloadHandler(
filename = "mappingResult.csv",
content = function(file) {
write.csv(mappingResults[[input$selectedResult]], file)
}
)
# Download the currently-displayed plot when the user presses the save button
output$savePlot <- downloadHandler(
filename = "plot.png",
content = function(file) {
ggplot2::ggsave(file, width = 8, height = 7)
}
)
}
shinyApp(ui = ui, server = server)
# [END]
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.