Pass reactive table to function to be printed via action button - r

I have a R shinydashboard where a table can be edited and then I'd like the new table to be passed to the function agree() to calculate a statistic to be printed upon clicking an action button. I'm getting the following error in my renderPrint box on the app and assume a few things may be off in my code:
Error message in renderPrint box on app:
structure(function (...) ,{, if (length(outputArgs) != 0 && !hasExecuted$get()) {, warning("Unused argument: outputArgs. The argument outputArgs is only ", , "meant to be used when embedding snippets of Shiny code in an ", , "R Markdown code chunk (using runtime: shiny). When running a ", , "full Shiny app, please set the output arguments directly in ", , "the corresponding output function of your UI code."), hasExecuted$set(TRUE), }, if (is.null(formals(renderFunc))) , renderFunc(), else renderFunc(...),}, class = "function", outputFunc = function (outputId, placeholder = FALSE) ,{, pre(id = outputId, class = "shiny-text-output", class = if (!placeholder) , "noplaceholder"),}, outputArgs = list(), hasExecuted = <environment>, cacheHint = list(, label = "renderPrint", origUserExpr = agree(as.data.frame(table1))))
Below is my code (I have 3 tabItems but am just focusing on getting the first tab: tabName = "2int" to work. Issue lies in the sever code of output$irr1. Can use the baseR cor() function in replace of agree() from the irr package for testing purposes. Just need the updated table to be saved as a dataframe with all numbers or matrix to function correctly with the agree() function.
library(shiny)
library(irr)
library(DT)
library(dplyr)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "Interview Reliability"),
dashboardSidebar(
sidebarMenu(
menuItem("Two Interviewers",
tabName = "2int",
icon = icon("glass-whiskey")),
menuItem("Three Interviewers",
tabName = "3int",
icon = icon("glass-whiskey")),
menuItem("Four Interviewers",
tabName = "4int",
icon = icon("glass-whiskey"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "2int",
fluidRow(box(sliderInput("obs1", "Number of Interview Questions:",
value = 4,
min = 4,
max = 12,
step = 1))),
box(dataTableOutput("table1")),
box(verbatimTextOutput("irr1")),
box(actionButton("calc1", "Calculate"))
),
tabItem(tabName = "3int",
box(sliderInput("obs2", "Number of Interview Questions:",
value = 4,
min = 4,
max = 12,
step = 1))
),
tabItem(tabName = "4int",
box(sliderInput("obs3", "Number of Interview Questions:",
value = 4,
min = 4,
max = 12,
step = 1)),
)
)
)
)
server <- function(input, output) {
tablevalues <- reactiveValues(df = NULL)
observeEvent(input$obs1, {
tablevalues$df <- matrix(NA, nrow = input$obs1, ncol = 2,
dimnames = list(1:input$obs1, c("Interviewer 1", "Interviewer 2")))
})
output$table1 <- renderDT(tablevalues$df, escape = FALSE, selection = 'none', editable=TRUE)
output$irr1 <- eventReactive(input$calc1, {
renderPrint(agree(as.data.frame(table1)))
})
}
shinyApp(ui = ui, server = server)

You are mixing things here, and therefore your syntax is incorrect. Try this
server <- function(input, output) {
tablevalues <- reactiveValues(df = NULL)
observeEvent(input$obs1, {
tablevalues$df <- matrix(NA, nrow = input$obs1, ncol = 2,
dimnames = list(1:input$obs1, c("Interviewer 1", "Interviewer 2")))
})
output$table1 <- renderDT(tablevalues$df, escape = FALSE, selection = 'none', editable=TRUE)
### update tablevalues$df with all the edits
observeEvent(input$table1_cell_edit,{
info = input$table1_cell_edit
str(info)
i = info$row
j = info$col
v = as.numeric(info$value) ### change it to info$value if your function does not need it to be numeric
tablevalues$df[i, j] <<- DT::coerceValue(v, tablevalues$df[i, j])
})
mycor <- eventReactive(input$calc1, {
cor(tablevalues$df)
})
output$irr1 <- renderPrint({mycor()})
}

Related

Independent reactions are interacting in a Shiny App

I'm using the sliderInput function with the animate argument to perform an automatic calculation in my shinyApp. However, using animate is affecting other reactions in my app. I would like to stop this side effect that is occurring in other reactivities.
For example, I have a dropdownMenu inside an if else structure. But, because of the animate argument, I can't click the option in the top right corner when I start the animation. It is disappearing with each calculation that the animate is doing. See:
I tried use isolate() in pred_1() but it stop the valueBox and the conditional structure (if else structure).
I'd like to just make animate not affect other reactivity in the app.
My app:
library(shiny)
library(shinydashboard)
header <- dashboardHeader(
title = "Dashboard",
titleWidth = 300,
dropdownMenuOutput(
outputId = "drop1"
)
)
sidebar <- dashboardSidebar(
width = 300
)
body <- dashboardBody(
sliderInput(
inputId = "one",
label = "Registro 1",
value = 1,
animate = animationOptions(
interval = 500, loop = TRUE
),
min = 1,
max = 10,
step = 1,
ticks = TRUE
),
sliderInput(
inputId = "two",
label = "Registro 2",
value = 1,
animate = animationOptions(
interval = 500, loop = TRUE
),
min = 1,
max = 10,
step = 1,
ticks = TRUE
),
sliderInput(
inputId = "three",
label = "Sum 3",
value = 1,
animate = animationOptions(
interval = 500, loop = TRUE
),
min = 1,
max = 10,
step = 1,
ticks = TRUE
),
valueBoxOutput(
outputId = "box1"
)
)
ui <- dashboardPage(
header = header,
sidebar = sidebar,
body = body
)
server <- function(session, input, output) {
fx <- function(x, y) {
x + y
}
fy <- function(x) {
x
}
reac_0 <- reactive({
tibble::tibble(
one = input$one,
two = input$two,
three = input$three
)
})
chuveiro <- reactive({
temp <- reac_0()
fx(
x = temp$one,
y = temp$two
)
})
luz <- reactive({
temp <- reac_0()
fy(
x = temp$three
)
})
fdrop <- function(x) {
if (x <= 5) {
dropdownMenu(
type = "notifications",
badgeStatus = NULL,
headerText = "Not 1",
notificationItem(
text = HTML(
"<text style='color:#020202;'>Without.</text>"
),
status = "danger",
icon = icon("times"),
href = NULL
)
)
} else (
dropdownMenu(
type = "notifications",
badgeStatus = "danger",
headerText = "Not 2",
notificationItem(
text = HTML(
"<a style='color:#020202;'
href='https://www.instagram.com' target='_blank' title='A'>
With</a>"
),
status = "success",
icon = icon("tags")
)
)
)
}
output$drop1 <- renderMenu({
expr = fdrop(x = luz())
})
output$box1 <- renderValueBox({
expr = valueBox(
value = chuveiro(),
subtitle = "Sum"
)
})
}
shinyApp(ui, server)
So how can I make one reactivity effect another in a shinyApp?
I would like to click normally on the dropdownMenu notification with the sliderInput working with animate.
I tried isolating each argument of sliderInput, but not work.
The reac0() reactive is triggered whenever an input changes. Then it triggers every reactive that includes it, even if the value used in that reactive has not changed.
Your code :
reac_0 <- reactive({
tibble::tibble(
one = input$one,
two = input$two,
three = input$three
)
})
luz <- reactive({
temp <- reac_0()
fy(
x = temp$three
)
})
triggers luz() whenever one, two or three changes.
An alternative would be to use input$three directly:
luz <- reactive({
fy(
x = input$three
)
})
This way, the change or animation of slider one and two won't trigger luz() which won't trigger the menu rendering.
Of course, since the value of slider three is used to render the menu, any update of its value has to trigger the menu rendering.

Topic Modelling Visualization using LDAvis and R shinyapp and parameter settings

I am using LDAvis in R shiny app.
Here is the code and it works without errors.
# docs is a csv file with a "text" column, e.g.
# docs <- read.csv("docs.csv",sep=",",header=TRUE)
ui <- navbarPage(
title = "NLP app",
tabPanel("Topic Model",icon = icon("group"),
fluidPage(
headerPanel(""),
titlePanel(p(h2("Topic Modelling example",style = "color:#4d3a7d"))),
#sidebarPanel(
wellPanel(tags$style(type="text/css", '#leftPanel { width:200px; float:left;}'), style = "background: lightgrey",
id = "leftPanel",
sliderInput("nTopics", "Number of topics to display", min = 5, max = 50, value = 10, step=5),
sliderInput("nTerms", "#top terms per topic", min = 10, max = 50, value = 20, step=5),
tags$hr(),
actionButton(inputId = "GoButton", label = "Go", icon("refresh"))
),
mainPanel(
tabPanel("Topic Visualisation", hr(),helpText(h2("Please select a topic!")), visOutput('visChart')))
)
)
)
# server
server <- function(input, output, session) {
Topic_Subset <- reactive({
docs <- docs$text
nTopics <- input$nTopics
# topic model using text2vec package
tokens = docs %>%
tolower %>%
word_tokenizer
it = itoken(tokens, progressbar = FALSE)
v = create_vocabulary(it,stopwords=tm::stopwords("en"))
vectorizer = vocab_vectorizer(v)
dtm = create_dtm(it, vectorizer, type = "dgTMatrix")
lda_model = text2vec::LDA$new(n_topics = nTopics, doc_topic_prior = 0.1, topic_word_prior = 0.01)
lda_model$fit_transform(x = dtm, n_iter = 1000,
convergence_tol = 0.001, n_check_convergence = 25,
progressbar = FALSE)
return(lda_model) #
})
output$visChart <- renderVis({
input$GoButton
isolate({
nterms <- input$nTerms
lda_model <- Topic_Subset()
})
lda_model$plot(out.dir = "./results", R = nterms, open.browser = FALSE)
readLines("./results/lda.json")
})
}
shinyApp(ui = ui, server = server)
I would like to see whether it is possible to use width = "80%" in visOutput('visChart') similar to, for example, wordcloud2Output("a_name",width = "80%"); or any alternative methods to make the size of visualization smaller. Particularly, when I minimize the shiny app window, the plot does not fit in the page. My second question is: how can I initialize the parameter lambda (please see the below image and yellow highlights) with another number like 0.6 (not 1)?

Shiny values within a function from input

I am working on a shiny app, where I need input values to show up in a function.
What I am trying to do is to somehow extract names and values from input, like CL=4, V1=3, and feed them in a function that I need to feed into a model in server later on. The model I am working on only takes function format. Below is my code.
UI:
#Set up
rm(list=ls())
library(shiny)
library(shinydashboard)
library(shinyBS)
library(dplyr)
#Design sidebar
sidebar <- dashboardSidebar(width = 200, collapsed=TRUE,
sidebarMenu(id="tabs",
menuItem("Simulations", tabName = "Sims", icon = icon("line-chart"), selected=TRUE),
menuItem("Placeholder", tabName = "Place", icon = icon("square-o"))
))
#Design body
body <- dashboardBody(
tabItems(
tabItem(tabName = "Sims",
box(collapsible=TRUE, width = 3, status = "success", solidHeader = T, title="Select Your Model",
radioButtons(inputId="PK_Model", label = "PK Model", selected="One_Comp",
choices = c("1 Compartment"="One_Comp", "2 Compartment"="Two_Comp")),
radioButtons(inputId="Clearance_Model",label ="Clearance Mechanism", selected="Linear",
choices = c("Linear"="Linear"))),
box(collapsible=TRUE, status = "success", solidHeader = T, title="Enter Parameter Estimates",
conditionalPanel(condition = "input.Clearance_Model == 'Linear'",
numericInput(label="Clearance (Linear) (CL; L/day)", inputId="CL", min = 0, max = NA, value = 0),
numericInput(label="Central volume of distribution (V1; L)", inputId="V1", min = 0, max = NA, value = 0)),
conditionalPanel(condition = "input.PK_Model == 'Two_Comp'",
numericInput(label="Inter-compartment clearance (Q; L/day)", inputId="Q", min = 0, max = NA, value = 0),
numericInput(label="Peripheral volume of distribution (V2; L)", inputId="V2", min = 0, max = NA, value = 0))),
box(collapsible=T, width=2, status = "success", solidHeader = T, title="Run",
actionButton('gosim','Run Sims',class='btn btn-info', icon=icon('play-circle-o','fg-lg'))),
box(width=5, status = "success", solidHeader = T, title="Simulated", textOutput('testprint')))))
#Show title and the page (includes sidebar and body)
dashboardPage(skin=c("blue"),
dashboardHeader(titleWidth=900, title = "Shiny Test"),
sidebar, body)
UPDATED:
Following PoGibas's answer below, I updated server code to following, but result does not look like what I need.
Server:
library(shiny)
library(shinydashboard)
library(shinyBS)
library(RxODE)
library(parallel)
library(ggplot2)
test <- function (N1, N2, N3, N4) {
mypar <- function(lKa, lKdeg, N1, N2, N3, N4){
Ka=exp(lKa)
Kdeg=exp(lKdeg)
V1=N1
CL=N2
Q=N3
V2=N4}
return(mypar)
}
shinyServer(function(input, output, session){
mypar <-eventReactive(input$goSimPH20, {
N1=as.numeric(input$V1)
N2=as.numeric(input$CL)
N3=as.numeric(input$Q)
N4=as.numeric(input$V2)
par1 = test(N1, N2, N3, N4)
return(par1)
})
output$testprint <- renderText(mypar())
})
What I need result to look like when I call mypar() within server is as below:
test <- function (lKa, lKdeg, V1, CL, Q, V2) {
Ka=exp(lKa)
Kdeg=exp(lKdeg)
V1=xx
V2=xx
CL=xx
Q=xx
}
xx can be any user supplied value in UI.
I simplified server part to this:
test <- function (V1 = 1, CL = 2, lA = 1, lB = 2) {
return(lA + lB + V1 + CL)
}
shinyServer(function(input, output, session) {
mypar <- reactive({
V1 = as.numeric(input$V1)
CL = as.numeric(input$CL)
return(test(V1, CL))
})
output$testprint <- renderText(mypar())
})
In test function add your wanted formula. User input is extracted using V1 = as.numeric(input$V1) and passed to test using test(V1, CL).

Shiny R: Modifying the variable class

I am trying to create a shiny-app that load data-set, present the variable list and their classes and allow the user to modify the class of a selected variable. All the functions in the following code are working except to the last function in the server- observeEvent which not working when trying to modify the variable class. Any suggestions?
Thank you in advance,
Rami
`
rm(list = ls())
library(shiny)
library(shinydashboard)
library(DT)
ui <- dashboardPage(
dashboardHeader(title = "Shiny Example"),
#--------------------------------------------------------------------
dashboardSidebar(
sidebarMenu(
menuItem("Data", tabName = "data", icon = icon("th"))
)
),
#--------------------------------------------------------------------
dashboardBody(
#--------------------------------------------------------------------
tabItem(tabName = "data",
fluidPage(
fluidRow(
box(
selectInput('dataset', 'Select Dataset', list(GermanCredit = "GermanCredit",
cars = "cars",
iris = "iris")),
title = "Datasets",width = 4, status = "primary",
checkboxInput("select_all", "Select All Variable", value = TRUE),
conditionalPanel(condition = "input.select_all == false",
uiOutput("show.var"))
),
box(
title = "Variable Summary", width = 4, status = "primary",
DT::dataTableOutput('summary.data')
),
box(
title = "Modify the Variable Class", width = 4, status = "primary",
radioButtons("choose_class", label = "Modify the Variable Class",
choices = list(Numeric = "numeric", Factor = "factor",
Character = "character"),
selected = "numeric"),
actionButton("var_modify", "Modify")
)
)
)
)
)
)
#--------------------------------------------------------------------
# Server Function
#--------------------------------------------------------------------
server <- function(input, output,session) {
#--------------------------------------------------------------------
# loading the data
get.df <- reactive({
if(input$dataset == "GermanCredit"){
data("GermanCredit")
GermanCredit
}else if(input$dataset == "cars"){
data(cars)
cars
}else if(input$dataset == "iris"){
data("iris")
iris
}
})
# Getting the list of variable from the loaded dataset
var_list <- reactive(names(get.df()))
# Choosing the variable - checkbox option
output$show.var <- renderUI({
checkboxGroupInput('show_var', 'Select Variables', var_list(), selected = var_list())
})
# Setting the data frame based on the variable selction
df <- reactive({
if(input$select_all){
df <- get.df()
} else if(!input$select_all){
df <- get.df()[, input$show_var, drop = FALSE]
}
return(df)
})
# create list of variables
col.name <- reactive({
d <- data.frame(names(df()), sapply(df(),class))
names(d) <- c("Name", "Class")
return(d)
})
# render the variable list into table
output$summary.data <- DT::renderDataTable(col.name(), server = FALSE, rownames = FALSE,
selection = list(selected = 1, mode = 'single'),
options = list(lengthMenu = c(5, 10, 15, 20), pageLength = 20, dom = 'p'))
# storing the selected variable from the variables list table
table.sel <- reactive({
df()[,which(colnames(df()) == col.name()[input$summary.data_rows_selected,1])]
})
# Trying to modify the variable class
observeEvent(input$var_modify,{
modify.row <- which(colnames(df()) == col.name()[input$summary.data_rows_selected,1])
if( input$choose_class == "numeric"){
df()[, modify.row] <- as.numeric(df()[, modify.row])
} else if( input$choose_class == "factor"){
df()[, modify.row] <- as.factor(df()[, modify.row])
} else if( input$choose_class == "character"){
df()[, modify.row] <- as.character(df()[, modify.row])
}
})
}
shinyApp(ui = ui, server = server)
`
I would use reactiveValues() instead.
library(shiny)
# Define UI for application that draws a histogram
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("classType", "Class Type:", c("as.numeric", "as.character"))
),
mainPanel(
textOutput("class")
)
)
))
server <- shinyServer(function(input, output) {
global <- reactiveValues(sample = 1:9)
observe({
global$sample <- get(input$classType)(global$sample)
})
output$class <- renderText({
print(class(global$sample))
})
})
shinyApp(ui = ui, server = server)
In case you are interested:
Concerning your attempt: reactive() is a function and you called the output of the function by df()[, modify.row]. So in your code you try to change the output of the function, but that does not change the output of futures calls of that function.
Maybe it is easier to see in a simplified version:
mean(1:3) <- 1
The code can not change the mean function to output 1 in future. So thats what reactiveValues() help with :). Hope that helps!

shiny sliderInput from max to min

Is it possible to make a sliderInput that shows the values in decreasing order (from left to right; eg. 5 4 3 2 1)?
runApp(
list(
ui = fluidPage(
sliderInput("test","", min=5, max=1, value = 3, step=1)
),
server = function(input,output) {}
)
)
EDIT 2017-10-13: This function is now available in package shinyWidgets (with a different name : sliderTextInput()).
Hi you can write your own slider function like this (it's a little dirty...) :
sliderValues <- function (inputId, label, values, from, to = NULL, width = NULL) {
sliderProps <- shiny:::dropNulls(list(class = "js-range-slider",
id = inputId,
`data-type` = if (!is.null(to)) "double",
`data-from` = which(values == from) - 1,
`data-to` = if (!is.null(to)) which(values == to) - 1,
`data-grid` = TRUE,
`data-values` = paste(values, collapse = ", ")
))
sliderProps <- lapply(sliderProps, function(x) {
if (identical(x, TRUE))
"true"
else if (identical(x, FALSE))
"false"
else x
})
sliderTag <- div(class = "form-group shiny-input-container",
style = if (!is.null(width))
paste0("width: ", validateCssUnit(width), ";"),
if (!is.null(label))
shiny:::controlLabel(inputId, label), do.call(tags$input,
sliderProps))
dep <- list(htmltools::htmlDependency("ionrangeslider", "2.0.12", c(href = "shared/ionrangeslider"),
script = "js/ion.rangeSlider.min.js",
stylesheet = c("css/ion.rangeSlider.css",
"css/ion.rangeSlider.skinShiny.css")))
htmltools::attachDependencies(sliderTag, dep)
}
The point to do this is to use the values attribute from ionrangeslider (see section Using custom values array here)
The downside is the value of the input you retrieve server-side isn't the value of the slider but the index of the value (starting from 0).
You can use this function like this :
library("shiny")
runApp(
list(
ui = fluidPage(
# you have to pass the values you want in the slider directly to th function
sliderValues(inputId = "test", label = "", from = 5, values = 5:1),
verbatimTextOutput(outputId = "slidervalue")
),
server = function(input,output) {
output$slidervalue <- renderPrint({
# Careful ! : input$test isn't the expected value !!!
(5:1)[input$test + 1]
})
}
)
)
And bonus : it works with characters vectors too :
runApp(
list(
ui = fluidPage(
sliderValues(inputId = "test", label = "", from = "g", to = "o", values = letters),
verbatimTextOutput(outputId = "slidervalue")
),
server = function(input,output) {
output$slidervalue <- renderPrint({
# Careful ! : input$test isn't the expected value !!!
letters[input$test + 1]
})
}
)
)

Resources