|
|
|
|
|
|
|
|
|
|
|
|
|
library(rtemis) |
|
library(rtemisbio) |
|
library(shiny) |
|
library(bslib) |
|
library(htmltools) |
|
library(plotly) |
|
source("globals.R") |
|
source("data.R") |
|
|
|
|
|
primary <- "#72CDF4" |
|
info <- helpcol <- "#FEB2E0" |
|
success <- "#B4DC55" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rtemisseq_version <- "0.2.6" |
|
seqvizlive <- function( |
|
default_theme = "dark", |
|
protein_plotly_height = "900px", |
|
jsonedit_height = "900px", |
|
verbosity = 0) { |
|
|
|
logo <- base64enc::dataURI( |
|
file = "./www/rtemisbio_gray.png", mime = "image/png" |
|
) |
|
|
|
platform <- sessionInfo()[["platform"]] |
|
svl <- paste0( |
|
"rtemisseq v.", rtemisseq_version, |
|
" | ", "rtemis v.0.97.3", utils::packageVersion("rtemis"), |
|
" | ", "rtemisbio v.", utils::packageVersion("rtemisbio"), |
|
" | R v.", version$major, ".", version$minor, |
|
" | running on ", platform |
|
) |
|
|
|
|
|
shinylive_info <- if (substr(platform, 1, 4) == "wasm") { |
|
paste0( |
|
"<br><br>This application has been compiled to ", |
|
as.character(a("WebAssembly", href = "https://webassembly.org/", target = "_blank")), |
|
" using ", |
|
as.character(a("shinylive", href = "https://posit-dev.github.io/r-shinylive/", target = "_blank")), |
|
"<br>and is best viewed with the latest version of Chrome." |
|
) |
|
} else { |
|
NULL |
|
} |
|
|
|
|
|
ui <- function(request) { |
|
bslib::page_navbar( |
|
|
|
title = list( |
|
logo = a( |
|
img( |
|
src = logo, |
|
width = "140px", |
|
height = "auto", |
|
alt = "rtemisbio" |
|
), |
|
href = "https://rtemis.org/rtemisbio", |
|
) |
|
), |
|
id = "rtemisbio", |
|
selected = "Welcome", |
|
footer = span( |
|
svl, |
|
" © 2024 EDG", |
|
style = "display: block; text-align: center; margin-top: 1em; margin-bottom: 1em;" |
|
), |
|
|
|
theme = bslib::bs_theme( |
|
bg = "#fff", |
|
fg = "#000", |
|
primary = primary, |
|
secondary = "#704071", |
|
success = success, |
|
info = info, |
|
`tooltip-bg` = "#303030", |
|
`tooltip-color` = helpcol, |
|
`tooltip-opacity` = 1, |
|
`tooltip-border-radius` = "10px", |
|
`tooltip-padding-x` = "1rem", |
|
`tooltip-padding-y` = "1rem", |
|
`tooltip-font-size` = "1rem" |
|
|
|
|
|
) |> |
|
bs_add_rules(sass::sass_file("www/rtemislive.scss")), |
|
|
|
window_title = "rtemisSeq", |
|
|
|
lang = "en", |
|
|
|
|
|
|
|
bslib::nav_panel( |
|
title = "Welcome", |
|
icon = bsicons::bs_icon("stars"), |
|
bslib::card( |
|
h4("Welcome to rtemisSeq", style = "text-align: center;"), |
|
card_body( |
|
class = "d-inline text-center", |
|
HTML(paste0( |
|
"rtemisSeq is a web interface for ", |
|
as.character(a("rtemisbio", href = "https://rtemis.org/rtemisbio", target = "_blank")), |
|
", <br>providing interactive visualization of sequence data.", |
|
"<br>Created for the ", as.character(a("FTD CWOW", href = "https://cwow.ucsf.edu/", target = "_blank")), |
|
".<br><br>", |
|
rthelp_inline( |
|
"To get started, use the navigation tabs at the top.", |
|
title = "Welcome" |
|
), |
|
shinylive_info |
|
)), |
|
br(), br(), |
|
bslib::card_image( |
|
file = "./www/svl.webp", |
|
alt = "rtemislive", |
|
align = "center", |
|
border_radius = "all", |
|
fill = FALSE, |
|
width = "40%", |
|
class = "mx-auto" |
|
) |
|
) |
|
) |
|
), |
|
|
|
bslib::nav_panel( |
|
title = "Protein Visualization", |
|
icon = bsicons::bs_icon("body-text"), |
|
card( |
|
full_screen = TRUE, |
|
class = "p-0", |
|
|
|
card_header( |
|
class = "d-flex justify-content-end", |
|
|
|
uiOutput("ui_a3_tooltip"), |
|
|
|
uiOutput("ui_a3_popover") |
|
), |
|
layout_sidebar( |
|
fillable = TRUE, |
|
|
|
sidebar = bslib::sidebar( |
|
uiOutput("ui_a3_load_switch"), |
|
uiOutput("ui_a3_data_load"), |
|
uiOutput("ui_a3_data_info"), |
|
uiOutput("ui_a3_plot_button"), |
|
|
|
), |
|
|
|
|
|
|
|
uiOutput("ui_dplot3_protein") |
|
) |
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
), |
|
|
|
bslib::nav_panel( |
|
title = "About", |
|
icon = bsicons::bs_icon("info-square"), |
|
bslib::card( |
|
card_image( |
|
file = "./www/rtemisbio_s.webp", |
|
href = "https://rtemis.org/rtemisbio", |
|
alt = "rtemislive", |
|
align = "center", |
|
border_radius = "all", |
|
fill = FALSE, |
|
width = "54%", |
|
class = "mx-auto" |
|
), |
|
div( |
|
class = "d-inline text-center", |
|
HTML(paste0( |
|
"Created by the ", |
|
as.character(a("FTD CWOW", href = "https://cwow.ucsf.edu/", target = "_blank")), |
|
" Genomics & Transcriptomics core.<br/>", |
|
"Powered by rtemis & rtemisbio (", |
|
as.character(a("rtemis.org", href = "https://rtemis.org", target = "_blank")), |
|
")." |
|
)), |
|
br(), br(), |
|
a( |
|
img( |
|
src = "rtemis_gray.png", |
|
alt = "rtemis", |
|
align = "center", |
|
width = "190px" |
|
), |
|
href = "https://rtemis.org", |
|
target = "_blank" |
|
), |
|
align = "center" |
|
) |
|
) |
|
), |
|
bslib::nav_spacer(), |
|
bslib::nav_item(input_dark_mode(id = "dark_mode", mode = default_theme)), |
|
header = list( |
|
|
|
shinybusy::add_busy_spinner( |
|
spin = "orbit", |
|
|
|
color = "#00ffff", |
|
timeout = 200, |
|
position = "bottom-left", |
|
onstart = FALSE |
|
) |
|
) |
|
) |
|
} |
|
|
|
|
|
server <- function(input, output, session) { |
|
|
|
output$ui_a3_load_switch <- shiny::renderUI({ |
|
if (verbosity > 0) { |
|
message("Rendering ui_a3_load_switch") |
|
} |
|
|
|
shiny::radioButtons( |
|
inputId = "a3_load_switch", |
|
label = "Data source", |
|
choices = list( |
|
`Built-in datasets` = "builtin", |
|
`File upload` = "upload" |
|
), |
|
selected = "builtin" |
|
) |
|
}) |
|
|
|
|
|
output$ui_a3_data_load <- shiny::renderUI({ |
|
req(input$a3_load_switch) |
|
if (input$a3_load_switch == "upload") { |
|
|
|
if (verbosity > 0) { |
|
message("Rendering ui_a3_data_load for file upload") |
|
} |
|
shiny::fileInput( |
|
inputId = "a3_file", |
|
label = "Upload a3 JSON file", |
|
buttonLabel = "Browse local files...", |
|
) |
|
} else { |
|
|
|
if (verbosity > 0) { |
|
message("Rendering ui_a3_data_load for built-in data selection") |
|
} |
|
shiny::selectizeInput( |
|
inputId = "a3_builtin_data", |
|
label = "Select built-in a3 dataset", |
|
choices = c("mapt_annot", "mapt_clv"), |
|
selected = "mapt_annot" |
|
) |
|
} |
|
}) |
|
|
|
|
|
output$ui_a3_data_info <- shiny::renderUI({ |
|
req(a3_obj()) |
|
if (verbosity > 0) { |
|
message("Rendering ui_a3_data_info") |
|
} |
|
bslib::card( |
|
bslib::card_title("a3 Dataset Info", container = htmltools::h6), |
|
bslib::card_body( |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
summarize_a3(a3_obj()), |
|
fillable = FALSE |
|
) |
|
) |
|
}) |
|
|
|
|
|
output$ui_a3_plot_button <- shiny::renderUI({ |
|
req(a3_obj()) |
|
if (verbosity > 0) { |
|
message("Rendering ui_a3_plot_button") |
|
} |
|
bslib::input_task_button( |
|
"a3_plot_button", |
|
"Plot dataset", |
|
icon = bsicons::bs_icon("magic"), |
|
label_busy = "Drawing...", |
|
icon_busy = bsicons::bs_icon("clock-history"), |
|
type = "primary", |
|
auto_reset = TRUE |
|
) |
|
}) |
|
|
|
|
|
a3_obj <- shiny::reactive({ |
|
req(input$a3_load_switch) |
|
if (input$a3_load_switch == "upload") { |
|
req(input$a3_file) |
|
if (verbosity > 0) { |
|
message("Loading a3 JSON file '", input$a3_file$datapath, "'") |
|
} |
|
dat <- read.a3json(input$a3_file$datapath) |
|
if (verbosity > 0) { |
|
message("Loaded dataset of class '", class(dat)[1], "'") |
|
} |
|
return(dat) |
|
} else { |
|
|
|
req(input$a3_builtin_data) |
|
if (verbosity > 0) { |
|
message("Loading built-in a3 dataset '", input$a3_builtin_data, "'") |
|
} |
|
|
|
|
|
|
|
dat <- get(input$a3_builtin_data) |
|
if (verbosity > 0) { |
|
message("Loaded dataset of class '", class(dat)[1], "'") |
|
} |
|
return(dat) |
|
} |
|
}) |
|
|
|
|
|
dplot3_theme <- shiny::reactive({ |
|
req(input$dark_mode) |
|
if (input$dark_mode == "dark") { |
|
"black" |
|
} else { |
|
"white" |
|
} |
|
}) |
|
|
|
|
|
output$dplot3_protein <- plotly::renderPlotly({ |
|
req(a3_obj()) |
|
if (verbosity > 0) { |
|
message("Rendering dplot3_protein of object with class '", class(a3_obj())[1], "'") |
|
} |
|
plot( |
|
a3_obj(), |
|
theme = dplot3_theme(), |
|
marker.size = input$marker.size, |
|
font.size = input$font.size, |
|
ptm.marker.size = input$ptm.marker.size, |
|
clv.marker.size = input$clv.marker.size, |
|
bg = input$plot.bg, |
|
plot.bg = input$plot.bg, |
|
marker.col = input$marker.col, |
|
n.per.row = if (input$n.per.row == "auto") NULL else as.integer(input$n.per.row) |
|
) |
|
}) |> |
|
bindEvent(input$a3_plot_button, input$a3_plot_update_button) |
|
|
|
|
|
clicked <- shiny::reactiveVal(FALSE) |
|
shiny::observeEvent(input$a3_plot_button, { |
|
clicked(TRUE) |
|
}) |
|
|
|
|
|
output$ui_a3_tooltip <- shiny::renderUI({ |
|
if (clicked()) { |
|
bslib::tooltip( |
|
trigger = span( |
|
"Plot help", bsicons::bs_icon("info-circle", class = "text-info"), |
|
style = "text-align: right;", |
|
class = "rtanihi" |
|
), |
|
div( |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rhelplist( |
|
c( |
|
"Hover over plot to see annotations.", |
|
"Click on legend items to toggle visibility of annotations.", |
|
"Double-click on legend items to isolate a single annotation type.", |
|
"Click on top-right gear icon to change plot settings." |
|
) |
|
), |
|
style = "text-align: left;" |
|
), |
|
placement = "bottom" |
|
) |
|
} |
|
}) |
|
|
|
|
|
output$ui_a3_popover <- shiny::renderUI({ |
|
if (clicked()) { |
|
popover( |
|
trigger = bsicons::bs_icon("gear", class = "ms-auto"), |
|
|
|
|
|
|
|
|
|
shiny::sliderInput("marker.size", label = "Marker size", min = 1, max = 100, value = 28), |
|
shiny::sliderInput("font.size", label = "Font size", min = 1, max = 72, value = 18), |
|
if (length(a3_obj()$Annotations$PTM) > 0) shiny::sliderInput("ptm.marker.size", label = "PTM Marker size", min = .1, max = 36, value = 28 / 4.5), |
|
if (length(a3_obj()$Annotations$Cleavage_site) > 0) shiny::sliderInput("clv.marker.size", label = "Cleavage Site Marker size", min = .1, max = 36, value = 28 / 4), |
|
shinyWidgets::colorPickr( |
|
"plot.bg", |
|
label = "Plot background", |
|
selected = ifelse(input$dark_mode == "dark", "#191919", "#FFFFFF") |
|
), |
|
shinyWidgets::colorPickr( |
|
"marker.col", |
|
label = "Marker color", |
|
selected = ifelse(input$dark_mode == "dark", "#3f3f3f", "#dfdfdf") |
|
), |
|
textInput("n.per.row", "Number of AAs per row", value = "auto"), |
|
|
|
bslib::input_task_button( |
|
"a3_plot_update_button", |
|
"Update rendering", |
|
icon = bsicons::bs_icon("arrow-clockwise"), |
|
label_busy = "Drawing...", |
|
icon_busy = bsicons::bs_icon("clock-history"), |
|
type = "primary", |
|
auto_reset = TRUE |
|
), |
|
title = "Plot settings", |
|
placement = "auto" |
|
|
|
) |
|
} |
|
}) |
|
|
|
|
|
|
|
output$ui_dplot3_protein <- renderUI({ |
|
if (clicked() == FALSE || is.null(a3_obj())) { |
|
rthelp( |
|
"Select Data Source and Click 'Plot dataset' on the left.", |
|
title = "Protein Visualization " |
|
) |
|
} else { |
|
plotly::plotlyOutput( |
|
"dplot3_protein", |
|
width = "100%", |
|
height = protein_plotly_height |
|
) |
|
} |
|
}) |
|
|
|
|
|
output$jsonedit <- listviewer::renderJsonedit({ |
|
req(a3_obj()) |
|
listviewer::jsonedit(a3_obj()) |
|
}) |
|
|
|
|
|
output$ui_jsonedit <- shiny::renderUI({ |
|
listviewer::jsoneditOutput( |
|
"jsonedit", |
|
height = jsonedit_height |
|
) |
|
}) |
|
} |
|
|
|
|
|
shiny::shinyApp(ui = ui, server = server, enableBookmarking = "url") |
|
} |
|
|
|
seqvizlive() |
|
|