How define Server for Copy/Paste regions as input in R/Shiny? - html

I have a shiny which can be used to overlap between query regions and a given data table (e.g. DF). I put two options for uploading query data 1) as .bed format and 2) inserting data as copy/paste.
The shiny works well with uploading .bed file but I am not sure how can I define Server for copy/paste (text) data.
Thank you in advance for any suggestion!
DF<- data.table(chr=c("chr1","chr2"),start=c(10,20),end=c(20,30))%>% setkey(chr, start, end)
text<- data.table(chr=c("chr1","chr2"),start=c(15,25),end=c(15,30))%>% setkey(chr, start, end)
ui <- fluidPage(
sidebarLayout(
sidebarPanel (
p(strong ("Find overlap between query file and data"),style = "color:blue;"),
br(),
selectInput("choose","Choose file source",choices = c("file","text"),selected = "file"),
conditionalPanel("input.choose=='file'",
fileInput("query.file", "Upload genomic coordinates in .bed
format:",multiple = F,accept = ".bed")),
conditionalPanel("input.choose=='text'",
textAreaInput("query.text", "Enter genomic coordinates:")),
actionButton("run", "run"),
width = "2"),
mainPanel(
dataTableOutput("DFtable"),
dataTableOutput("overlap_table"))
)
)
server <- function (input, output, session) {
## Read user .bed file
user_query.file <- reactive({
req(input$query.file)
ext <- tools::file_ext(input$query.file$name)
switch(ext,
bed = fread(input$query.file$datapath,header=F)%>%
dplyr::rename (chr =V1, start=V2, end=V3) %>% setkey(chr, start, end)%>% unique()
)
})
## overlapping between query file and table
overlap <- eventReactive(input$run, {
req(input$run)
withProgress(message = 'Analysis in progress', value = 0, {
query.overlap<- foverlaps(user_query.file() ,DF, nomatch = 0) %>%
unique()
})
})
## output
output$DFtable<- renderDataTable({ DF })
output$overlap_table <- renderDT({overlap () })
}
shinyApp(ui, server)
Desire out put using TEXT input option:
chr start end i.start i.end
chr1 15 15 10 20
chr2 25 30 20 30

Not sure on how your copied text looks like, but assuming something like:
chr,start,end
chr1,10,20
chr4,34,56
All you need is to parse the text contents of the UI input and assigned it to DF variable. Your run event handler could look like:
## overlapping between query file and table
overlap <- eventReactive(input$run, {
req(input$run)
#Requiring text input and parsing it
req(input$query.text)
DF <- data.table(read.csv(text=input$query.text)) %>% setkey(chr, start, end)
withProgress(message = 'Analysis in progress', value = 0, {
query.overlap<- foverlaps(text ,DF, nomatch = 0) %>%
unique()
})
})
Then when clicking on the run button, the analysis is executed and the overlap reactive value is updated. If the comparison is always between file and text provided, you should also include a req(user_query.file()) to ensure the file has been provided and correctly parsed.

Related

Shiny - assigning argument to function

I am trying to create a shiny app that applies a self-made function to an uploaded dataset, then allows to download the modified results. Here is my code:
library(shiny)
library(tidyverse)
namkurz <- function(data, a_spalte) {
kuerzel <- vector(length = length(data$a_spalte))
for (i in 1:length(data$a_spalte)){
spez = data$Art[i]
s = unlist(strsplit(spez, " ", fixed = TRUE))
s = substr(s, 1, 2)
s = paste(s, collapse = ' ')
kuerzel[[i]] = s
}
data <- data %>%
mutate(kurz = kuerzel)
}
ui <- fluidPage(
fileInput('upload','Deine Kartierungsdaten'),
textInput('art', 'Wie heißt die Spalte mit Artnamen?'),
downloadButton('analyse','Artenkürzel hinzufügen')
)
server <- function(input, output, session) {
data <- reactive({
req(input$upload)
ext <- tools::file_ext(input$upload$name)
switch(ext,
csv = vroom::vroom(input$upload$datapath, delim = ";"),
validate("Invalid file; Please upload a .csv file")
)
})
art <- reactive(input$art)
output$analyse <- downloadHandler(
filename = function() {
paste0('mit_kuerzel', ".csv")
},
content = function(file) {
ergebnis <- reactive(namkurz(data(), art()))
vroom::vroom_write(ergebnis(), file)
}
)
}
shinyApp(ui, server)
When trying to save the output I get a 'Warning: Unknown or uninitialised column:' error. I think my problem is in the assignment of argument 'art' to the 'ergebnis' object, but I can't find the way to fix it.
I recommend a few things:
(Required) In your function, a_spalte is a character vector and not the literal name of column in the frame, so you need to use [[ instead of $, see The difference between bracket [ ] and double bracket [[ ]] for accessing the elements of a list or dataframe and Dynamically select data frame columns using $ and a character value.
Change all references of data$a_spalte to data[[a_spalte]].
namkurz <- function(data, a_spalte) {
kuerzel <- vector(length = length(data[[a_spalte]]))
for (i in 1:length(data[[a_spalte]])){
spez = data$Art[i]
s = unlist(strsplit(spez, " ", fixed = TRUE))
s = substr(s, 1, 2)
s = paste(s, collapse = ' ')
kuerzel[[i]] = s
}
data <- data %>%
mutate(kurz = kuerzel)
}
Your function is a bit inefficient doing things row-wise, we can vectorize that operation.
namkurz <- function(data, a_spalte) {
spez <- strsplit(data$Art, " ", fixed = TRUE)
data$kurz <- sapply(spez, function(z) paste(substr(z, 1, 2), collapse = " "))
data
}
(Optional) The content= portion of downloadHandler is already reactive, you do not need to wrap namkurz in reactive. Because of this, you also don't need to treat ergebnis as reactive.
output$analyse <- downloadHandler(
filename = ...,
content = function(file) {
ergebnis <- namkurz(data(), art())
vroom::vroom_write(ergebnis, file)
}
)
(Optional) Your output filename is fixed, so two things here: if it's always going to be "mit_kuerzel.csv", then there's no need for paste0, just use function() "mit_kuerzel.csv".
However, if you are intending to return a file named something based on the original input filename, one could do something like:
filename = function() {
paste0(tools::file_path_sans_ext(basename(input$upload$name)),
"_mit_kuerzel.",
tools::file_ext(input$upload$name))
},
to add _mit_kuerzel to the base portion of the uploaded filename. Note that the file in the content= section is never this name, the new_mit_kuerzel.csv is the filename offered to the downloading browser as a suggestion, that is all.
(Optional) You are using a .csv file extension in the downloadHandler, but the default for vroom::vroom_write is to use delim = "\t", which is not a CSV. I suggest either adding delim = ";" (or similar), or changing the returned filename extension to .tsv instead.

using user interface, nearpoint/renderprint/verbatimTextOutput('print') to show part of variables on user click

Below I attach the code I use for the Shiny application. I am wondering how I can specifically use click="plot_click"/near-point/render print, to show part of data(). If you look at the attached image, you see that bunch of info has appeared see image, but I need to take "name", and winning times only.
#code------------------------------------
server<- function(input, output, session) {
#wrangling data:
gslam<- as.data.frame(gslam1)
gslam$tournament <- sapply(gslam$tournament, function(val)
{agrep(val, c('Australian Open', 'U.S.
Open','Wimbledon','FrenchOpen'),
value = TRUE)})
#pivot plot based on Tournament
reactive_data<-reactive({
req(input$sel_tournament)
df<- gslam %>% filter(tournament %in%
input$sel_tournament)%>%group_by(winner,tournament)%>%
mutate(winningNumber=n())
df<-df %>% arrange(winner)
})
#dynamic list
observe({
updateSelectInput(session,"sel_tournament", choices =
gslam$tournament, select="U.S. Open")
})
# create the plot
output$WinnerPlot <- renderPlot({
g<- ggplot(reactive_data(),aes( y =winner, x
=winningNumber),decreasing=FALSE) +
theme(legend.position=none")
g+geom_bar(stat="identity",width=0.5, fill="black")})
output$print = renderPrint({
nearPoints(
reactive_data(), # the plotting data
input$plot_click, # input variable to get the x/y
maxpoints = 1, # only show the single nearest point
threshold = 1000 # basically a search radius. set this big
# to show at least one point per click
)})
output$Top5Plot <-renderPlot({
g<- ggplot(reactive_data(),aes( y =winner, x
=winningNumber),decreasing=FALSE) + theme(legend.position =
"none")
g+geom_bar(stat="identity",width=0.5, fill="black")
})
}
ui <- navbarPage("Grand Slam Shiny Application", id="cc",
tabPanel("Winners' Rank",
fluidRow(titlePanel("Grand Slam
ShinyApp"),
sidebarPanel(
selectInput(inputId =
"sel_tournament",label="Choose Tournament:","Names"))),
plotOutput(("WinnerPlot"), click="plot_click"),
verbatimTextOutput('print')
),
tabPanel("Top 5 Winners' Performance",
plotOutput("Top5Plot"))
)
# Run the App
shinyApp(ui, server)
You may take help of dplyr::select in nearPoints.
output$print = renderPrint({
nearPoints(
dplyr::select(reactive_data(), winner, winningNumber),
input$plot_click,
maxpoints = 1,
threshold = 1000
)})

R Shiny - Editing a data table inside a dynamically created bsModal

The app below contains an actionButton Add data that inserts a UI element each time it is clicked. Each UI element is a box that contains one selectInput Select data and an actionButton Edit that opens a modal when clicked.
Each modal contains:
A data table with two columns: Parameter and Value (this column is editable).
An actionButton Apply, which applies any changes made to the Value
column.
When the user selects a dataset inside box x, a reactiveValue is created to store the corresponding parameters in a data.frame x_paramset (where x is the id of the box inserted via insertUI) and add a val column which has the same value as default (see list at the top of code below). I then use renderDataTable to add the Value column (which contains the numericInput) - this data table is displayed inside the modal.
To update the data.frame to apply any changes the user may have made in the modal, I use an observeEvent that listens for the Apply button and updates the val column in the data.frame x_paramset with the values inside the numericInputs in the Value column.
Here is the app (the bsModal has been commented out and replaced with a shinyWidgets::dropdownButton):
library(shiny)
library(shinydashboard)
library(shinyjs)
library(shinyWidgets)
library(DT)
library(tidyverse)
all = list(p1 = list(a = list(id = "a", default = 10)),
p2 = list(x = list(id = "x", default = 20)))
# UI ----------------------------------------------------------------------
ui<-fluidPage(shinyjs::useShinyjs(),
tags$head(
tags$script("
$(document).on('click', '.dropdown-shinyWidgets li button', function () {
$(this).blur()
Shiny.onInputChange('lastClickId',this.id)
Shiny.onInputChange('lastClick',Math.random())
});
")
),
box(title = "Add data",
column(width = 12,
fluidRow(
tags$div(id = 'add')
),
fluidRow(
actionButton("addbox", "Add data")
))
)
)
# SERVER ------------------------------------------------------------------
server <- function(input, output, session) {
rvals = reactiveValues()
getInputs <- function(pattern){
reactives <- names(reactiveValuesToList(input))
name = reactives[grep(pattern,reactives)]
}
observeEvent(input$addbox, {
lr = paste0('box', input$addbox)
insertUI(
selector = '#add',
ui = tags$div(id = lr,
box(title = lr,
selectizeInput(lr, "Choose data:", choices = names(all)),
shinyWidgets::dropdownButton(inputId = paste0(lr, "_settings"),
circle = F, status = "success", icon = icon("gear"), width = "1000px",
tooltip = tooltipOptions(title = "Click to edit"),
tags$h4(paste0("Edit settings for Learner", lr)),
hr(),
DT::dataTableOutput( paste0(lr, "_paramdt") ),
bsButton(paste0(lr, "_apply"), "Apply")
) # end dropdownButton
)
) #end tags$div
) # end inserUI
# create reactive dataset
rvals[[ paste0(lr, "_paramset") ]] <- reactive({
do.call(rbind, all[[ input[[lr]] ]]) %>%
cbind(., lr) %>%
as.data.frame %>%
mutate(val = default)
}) # end reactive
# render DT in modal
output[[ paste0(lr, "_paramdt") ]] <- renderDataTable({
DT <- rvals[[ paste0(lr, "_paramset") ]]() %>%
mutate(
Parameter = id,
Value = as.character(numericInput(paste0(lr,"value",id), label = NULL, value = default))) %>%
select(Parameter:Value)
datatable(DT,
selection = 'none',
#server = F,
escape = F,
options = list(preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')))
}) # end renderDT
# Apply changes
observeEvent(input$lastClick, {
# replace old values with new
rvals[[ paste0(lr, "_paramset") ]](rvals[[ paste0(lr, "_paramset") ]]() %>%
mutate(
val = input$box1valuea
)
)
}) # end apply changes observeEvent
}) #end observeEvent
}
shinyApp(ui=ui, server=server)
I encounter errors when I try the following:
Add data >> Edit >> make some change to numericInput >> Apply - this
resets the numericInput inside the modal back to its default whereas
I would like the user-specified value to persist upon applying
changes or closing the modal.
The app crashes when I try:
Add data >> Edit >> Apply >> close modal >> Add data OR
Click Add data twice and then click Edit in either box.
I am not sure where my server logic is failing. I know Shiny does not support "persistent use" modals (https://github.com/rstudio/shiny/issues/1590) but I was wondering if there was a workaround? I am also not sure what inside the insertUI observeEvent is causing the app to crash in the cases described above. Any help you can offer would be greatly appreciated!

R Shiny: Table object not found in reactive RMySQL query in shiny app

[EDIT]: solution by agstudy worked for me.
I have a shiny app that allows users to toggle between three tables in a MySQL database. Users can select a table which is used by renderTable to generate the object.
I have put if statements in renderTable to respond to the users' selected table.
When I run the app, any table fails to print and cannot be viewed.
server.R
library(shiny)
library(RMySQL)
con <- dbConnect(RMySQL::MySQL(),user="x",password="x",host="dbhost",dbname="db")
shinyServer(function(input, output) {
data <- reactive({
selectInput("input$data", "Choose your Input:", choices = c('data1'='1','data2'='2', 'data3'='3'))
})
output$table <- renderTable({
if(input$data == data1){
query1 <- reactive({ "SELECT *
FROM data1
ORDER BY var1, var2"})
reactive({dbGetQuery(con,query1())})
head(data())
} else if(input$data == data2){
query1 <- reactive({ "SELECT *
FROM data2
ORDER BY var1, var2"})
reactive({dbGetQuery(con,query1())})
head(data())
} else if(input$data == data3){
query1 <- reactive({ "SELECT *
FROM data3
ORDER BY var1, var2"})
reactive({dbGetQuery(con,query1())})
head(data())
} else print("Select a dataset")
})
})
ui.R
library(shiny)
library('RMySQL')
shinyUI(navbarPage("Test",
tabPanel("Test",
sidebarLayout(
sidebarPanel(
selectInput("data", label = "Data set",
choices = c("", "data1", "data2", "data3"))
),
mainPanel(
tableOutput("table")
)
))
))
Your problem here is not in any case related to MySQLserver but there is a no UI logic. Programming in Shiny is not easy if you don't isolate your code parts:
inputs: defined in your ui interface
reactive functions : should change each time you change your input
outputs: be refreshed once the input data is changed by the reactive function.
You miss-understand the reactive.The basic idea is that your don't need to refresh your UI manually, it should be done automatically once the input parameter is changed.
Here I am rewriting completely your code using the Shiny logic:
library(RMySQL)
library(shiny)
## this a public function that will be used
## in the server side to connect to the data base
## and retrieve data
get_data <-
function(query){
on.exit(dbDisconnect(conn)) ## important to close connection
conn <- dbConnect("MySQL",user="xuser",
password="xpws",
host="xhost",
dbname="xdbname")
dbGetQuery(con,query)
}
server <- shinyServer(
function(input, output) {
## the reactive engine that will refresh query
## each time input changed
query <- reactive( sprintf("SELECT *
FROM %s
ORDER BY var1, var2",input$data)
)
## simply displaying reactive inputs
output$table <- renderTable(
if(input$data!="") get_data(query())
)
})
## define ui elements by step
## for easy indenting
ui_panel <-
tabPanel("Test",
sidebarLayout(
sidebarPanel(
selectInput("data", label = "Data set",
choices = c("","data1", "data2", "data3"))
),
mainPanel(
tableOutput("table")
)
)
)
ui <- shinyUI(navbarPage("Test",ui_panel))
runApp(list(ui=ui,server=server))

Hide renderPrint Pre Tag Output from Shiny Application in R

I am developing a Shiny application in R. For certain pieces of renderPrint output I would like the shiny user interface to display nothing. Kind of like the hidden option for pre or div tags in HTML5 example shown below:
http://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_global_hidden
Below is my shiny example code. A brief explanation: you can use a drop down menu to select one of two variables (factor variable or continuous variable). If you select the factor variable I want to show the caption and the table output. If you select the continuous variable I don't want to see anything. Right now, the caption disappears if you insert a blank string "" as the return to renderText. However, I don't know how to get renderPrint to show nothing. I've tried:
"". Doesn't work as it returns the actual blank string
NULL. Doesn't work as it returns the string NULL
invisible(). Best so far, but still doesn't work as it returns the grey formatted box.
Goal is to just display nothing. Shiny ui.r and server.r code given below:
library(shiny)
##
## Start shiny UI here
##
shinyUI(pageWithSidebar(
headerPanel("Shiny Example"),
sidebarPanel(
wellPanel(
selectInput( inputId = "variable1",label = "Select First Variable:",
choices = c("Binary Variable 1" = "binary1",
"Continuous Variable 1" = "cont1"),
selected = "Binary Variable 1"
)
)
),
mainPanel(
h5(textOutput("caption2")),
verbatimTextOutput("out2")
)
))
##
## Start shiny server file and simulated data here
##
binary1 <- rbinom(100,1,0.5)
cont1 <- rnorm(100)
dat <- as.data.frame(cbind(binary1, cont1))
dat$binary1 <- as.factor(dat$binary1)
dat$cont1 <- as.numeric(dat$cont1)
library(shiny)
shinyServer(function(input, output) {
inputVar1 <- reactive({
parse(text=sub(" ","",paste("dat$", input$variable1)))
})
output$caption2 <- renderText({
if ( (is.factor(eval(inputVar1()))==TRUE) ) {
caption2 <- "Univariate Table"
} else {
if ( (is.numeric(eval(inputVar1()))==TRUE) ) {
caption2 <- ""
}
}
})
output$out2 <- renderPrint({
if ( (is.factor(eval(inputVar1()))==TRUE) ) {
table(eval(inputVar1()))
} else {
if ( (is.numeric(eval(inputVar1()))==TRUE) ) {
invisible()
}
}
})
})
A few questions...
Why does renderText handle hidden/invisible presentation different than renderPrint? Is it because the former outputs text as pre tag; whereas, the latter displays formatted output in div tag?
To those HTML experts (upfront, I am not one)...what option would be best to get my output to display nothing? Is the hidden option embedded in a pre or div tag best (I know it doesn't work in IE browsers). Should I try something else? CSS options, etc?
Assuming hidden is the best way to go (or that I get an answer to 2. above), how do I pass this option/argument through the renderPrint function in shiny? Or would I need to use a different shiny function to achieve this functionality?
Btw...My R version is: version.string R version 3.0.1 (2013-05-16) and I am using shiny version {R package version 0.6.0}. Thanks in advance for your help.
I am not sure that I have understood your question, but try the following:
here is the Ui first:
library(shiny)
ui <- fluidPage(pageWithSidebar(
headerPanel("Shiny Example"),
sidebarPanel(
wellPanel(
selectInput(inputId = "variable1",label = "Select First Variable:",
choices = c("Binary Variable 1" = "binary1",
"Continuous Variable 1" = "cont1"),
selected = "Binary Variable 1"
)
)
),
mainPanel(
h5(textOutput("caption2")),
verbatimTextOutput("out2", placeholder=TRUE)
)
))
Start shiny Server file and simulated data here:
binary1 <- rbinom(100,1,0.5)
cont1 <- rnorm(100)
dat <- as.data.frame(cbind(binary1, cont1))
dat$binary1 <- as.factor(dat$binary1)
dat$cont1 <- as.numeric(dat$cont1)
server <- (function(input, output) {
inputVar1 <- reactive({
parse(text=sub(" ","",paste("dat$", input$variable1)))
})
output$caption2 <- renderText({
if ((is.factor(eval(inputVar1()))==TRUE) ) {
caption2 <- "Univariate Table"
} else {
if ((is.numeric(eval(inputVar1()))==TRUE) ) {
caption2 <- "Continous"
}
}
})
output$out2 <- renderPrint({
if ((is.factor(eval(inputVar1()))==TRUE) ) {table(eval(inputVar1()))}
})
})
And finally:
shinyApp(ui = ui, server = server)