In Shiny App, I want to read a table from my local, display it as an rhandsontable, and overwrite one of the columns with Sys.Date(), and display the updated table as rhandsontable.
the table function_table looks like this.
client fun agency loading_site last_update_on_DB
IKEA mean NA Paris 2018-08-01
Nestle sum NA Berlin 2018-08-02
Toyota mean NA Munich 2018-07-01
: : : : :
Here is my server.R
# read a table
func_path <- '/...[FILE PASS].../function_table.csv'
function_table <- reactive({read.csv(func_path, header = T, sep = ',', stringsAsFactors = F)})
# convert table to rhandsontable object to display in the app
hot_func <- reactive({function_table() %>%
rhandsontable(width = 1000, height = 1000) %>%
hot_cols(readOnly = T) %>%
hot_table(stretchH = "all" )})
# do some computations and overwrites the table
# ui.R has an action button (id = compute)
observeEvent({
input$compute
},{
# some computations...
# overwrite last_update_on_DB column with Sys.Date()
function_table()[function_table()$client == input$client,]$last_update_on_DB <- Sys.Date()
})
But the error reads:
Reactives: invalid (NULL) left side of assignment
I also followed this page like below, but got another error:
# read a table
values <- reactiveValues()
func_path <- '/...[FILE PASS].../function_table.csv'
values$function_table <- reactive({read.csv(func_path, header = T, sep = ',', stringsAsFactors = F)})
# convert table to rhandsontable object to display in the app
hot_func <- reactive({values$function_table() %>%
rhandsontable(width = 1000, height = 1000) %>%
hot_cols(readOnly = T) %>%
hot_table(stretchH = "all" )})
# do some computations and overwrites the table
# ui.R has an action button (id = compute)
observeEvent({
input$compute
},{
# some computations...
# overwrite last_update_on_DB column with Sys.Date()
values$function_table <- values$function_table()
values$function_table[values$function_table$client == input$client, ]$last_update_on_DB <- Sys.Date()
})
Warning: Error in eval: tentative d'appliquer un objet qui n'est pas une fonction
(it's telling me that in the line of hot_func, values$function_table() is not a function)
Any solutions?
Focusing on your first example:
You are trying to assign a value to a reactive object. function_table is a reactive, so you can only get its value not set its value via function_table()[....] <- .....
It is difficult to know exactly how to fix this as you have not posted a minimal reproducible example.
One way to resolve this using a reactive value. This is a value that can be assigned to and changed within the server. Here is an example:
server = function(input, output, session){
current = reactiveValues()
current$rhandsontable = read.csv(....) # your own code here to load the file on start up
observeEvent(input$compute,{
tmp = isolate(current$rhandsontable)
tmp[tmp$client == input$client,]$last_update_on_DB <- Sys.Date()
current$rhandsontable <- tmp
}
}
The use of isolate(...) may be unnecessary. It is used to prevent reactive values being re-evaluated in the retrieval of its contents.
This example assumes you are loading a fixed/known file at the beginning of your server. If you are loading your file dynamically you will probably need to use an observer to set the current value. For example (pseudo-code):
current = reactiveValues()
current$rhandsontable = NULL
observe(file_name,current$rhandsontable = read.csv(file_name))
Related
I am trying to define the dates between a user specified date range in Shiny R. I am using R version 3.6.2. However, I am obtaining an error:
Error in seq.int: 'to' must be a finite number
when I am inputting the start and end dates values to a seq function. The seq works fine when I hardcode test start and end dates. The snippets of code are specified below, any advice to resolve the issue is much appreciated.
UI Input Widget Code Parts
dateRangeInput("date_range","Select Date Range",start = "NA",end = "NA",format="%Y-%m-%d")) ## For Date Range
div(DT::dataTableOutput("test_table"),style="width:50%;") ## For plotting table to check results
Server
observeEvent(input$date_range,{
mins<- as.Date(input$date_range[1],format="%Y-%m-%d")
maxs<- as.Date(input$date_range[2],format="%Y-%m-%d")
dates <- seq(from=mins, to= maxs,by = 1)
output$test_table <- DT::renderDataTable(
data.frame(dates),
rownames = FALSE,
options = list(searching = FALSE, pageLength = 5,lengthChange = FALSE)
)
})
#Jay,
A few things might help:
In the ui, I might use as.Date(NA) for your default start and end to ensure in Date format. And you can use default format for dateRangeInput which already is yyyy-mm-dd
In server, check your input$date_range to make sure not NA that you start them out with. This will avoid giving seq an NA value to trigger your error.
You can also make your observeEvent an eventReactive expression, and then take output out of it, which is preferable
Working example:
library(shiny)
library(DT)
ui <- fluidPage(
dateRangeInput("date_range","Select Date Range",start=as.Date(NA),end=as.Date(NA)), ## For Date Range
div(DT::dataTableOutput("test_table"),style="width:50%;") ## For plotting table to check results
)
server <- function(input, output, session) {
dates <- eventReactive(input$date_range, {
if (is.na(input$date_range[1]) | is.na(input$date_range[2])) return (NULL)
mins<- as.Date(input$date_range[1],format="%Y-%m-%d")
maxs<- as.Date(input$date_range[2],format="%Y-%m-%d")
dates <- seq(from=mins, to=maxs, by = 1)
})
output$test_table <- DT::renderDataTable(
data.frame(dates()),
rownames = FALSE,
options = list(searching = FALSE, pageLength = 5,lengthChange = FALSE)
)
}
shinyApp(ui, server)
I'm getting this error when I run below code, can anyone please tell how to overcome this error.
Below is the code in which mydata is the main data set and I have created a shiny dashboard using the below code.
I tried to make one of the column as URL , but its showing error as in title.
And I tried giving data()$IFX_USERNAME as in his is a very common error in shiny apps. This most typically appears when you create an object such as a list, data.frame or vector using the reactive() function – that is, your object reacts to some kind of input. If you do this, when you refer to your object afterwards, you must include parentheses.
For example, let’s say you make a reactive data.frame like so:
MyDF<-reactive({ code that makes a data.frame with a column called “X” })
If you then wish to refer to the data.frame and you call it MyDF or MyDF$X you will get the error. Instead it should be MyDF() or MyDF()$X You need to use this naming convention with any object you create using reactive(), even then its showing the same error
library("shiny")
library("datasets")
library("DT")
library("shinyBS")
library(tidyr)
lapply( dbListConnections( dbDriver( drv = "MySQL")), dbDisconnect)
#connecting to database
dbListTables(mydb)
dbListFields(mydb, 'DL_COMMUNITY')
rs = dbSendQuery(mydb, "select * from DL_COMMUNITY")
mydatabase=fetch(rs)
setDT(mydatabase)
colnames(mydatabase)
header <- dashboardHeader()
ui = shinyUI(fluidPage(
DT::dataTableOutput("mtcarsTable"),
bsModal("mtCarsModal", "My Modal", "",dataTableOutput('mytext'), size = "large")
))
on_click_js = "
Shiny.onInputChange('mydata', '%s');
$('#mtCarsModal').modal('show')
"
on_click_js1 = "
Shiny.onInputChange('mydata', '%s');
$('#mtcarsTable').modal('show')
"
convert_to_link = function(x) {
as.character(tags$a(href = "#", onclick = sprintf(on_click_js,x), x))
}
convert_to_link1 = function(x) {
as.character(tags$a(href = "#", onclick = sprintf(on_click_js1,x), x))
}
shinyApp(
ui = ui,
server = function(input, output, session) {
mtcarsLinked <- reactive({
mydatabase$IFX_USERNAME <- sapply(
mydatabase$IFX_USERNAME,convert_to_link)
return(mydatabase)
})
**linked <- reactive({
myd$TEAM_MEMBERS <- sapply(
myd$TEAM_MEMBERS,convert_to_link1)
return(myd)
})**
output$mtcarsTable <- DT::renderDataTable({
DT::datatable(mtcarsLinked(),
class = 'compact',
escape = FALSE, selection='none'
)
})
output$mytext = DT::renderDataTable({
#userQuery=paste("select PROJECT,COMMENT from DL_COMMUNITY where IFX_USERNAME = '",user,"'",sep="")
#rs = dbSendQuery(mysqlCon,userQuery)
userQuery=paste("SELECT *
from Heatmap.DL_PROJECT where CONCAT(',', TEAM_MEMBERS, ',') like '%,sa,%'
or PROJECT_OWNER like '%,sa,%'
or PROJECT_LEAD like '%,sa,%'")
rs = dbSendQuery(mydb,userQuery)
myd=fetch(rs,n=-1)
myd<-data.frame(myd)
myd$TEAM_MEMBERS<- as.list(strsplit(myd$TEAM_MEMBERS, ","))
#myd<-myd %>%
#mutate(TEAM_MEMBERS = strsplit(as.character(TEAM_MEMBERS), ",")) %>%
#unnest(TEAM_MEMBERS)
#setDT(myd)
#hello <- input$mydata
#myd<-mydatabase[mydatabase$IFX_USERNAME==input$mydata,]
#myd1<-t(myd)
DT::datatable(linked(),
class='compact',
escape = FALSE,selection = 'none')
})
}
)
First, always use my_reactive() when you call a reactive function e.g. my_reactive.
Second, the object of type closure not subsettable usually means that the object you want to subset (here with $) cannot be found. You are not having the object not found error because you gave it a name already known to R.
As in the example of jogo, the same error occurs when trying to subset mean. mean is an object in R so it exists and R will not return object not found but it is a function and you cannot subset from it hence the error object is not subsettable.
Compare the results of the following lines of code.
mean[1]
mean <- c(1, 3)
mean[1]
Also note that R can still use mean to perform the mean of a numeric vector as it knows when to look for a function or for something else. But it is strongly advised not to do that. You should always properly name your objects with meaningful names.
In my shiny app, I created dynamic date range ui (input$daterange[i]) per selection of column(s) for date range input by users. And then I'd like to pass each input$daterange[i] value to a variable checking which rows in the corresponding column are within the user selected date range, I store the check results in dt$range_checks[i]. And then after checking all the input$daterange[1:i], I'd combine the check results dt$range_checks[1:i] to find out which rows satisfy all check conditions, this value is to be stored in dt$filtered_ind. So I'll use this index to filter the dataset with rows meeting all date range requirements. However, I don't know how I'd do the last part right, how can I combine the dynamic checks to get the final index? Below please find my code:
Part 1 - generate daterange uis per date column(s) selected by user:
# generate daterange uis per selected input$datecols
observeEvent({
# when a new file uploaded
input$file
# when user change selection date column(s)
input$datecols}, {
dt$datecols = input$datecols
dt$datecols_len = length(dt$datecols)
# render daterange ui(s) per selected datecols
output$daterangescontrol <- renderUI({
# when input$datecols is NULL, no daterangecontrol ui
if ( is.null(dt$datecols) ) { return(NULL) }
# otherwise
else {
# whenever input$datecols change, start/end of daterange ui refresh to original state
D = dt$data
output = tagList()
req(dt$datecols_len > 0)
for (i in 1:dt$datecols_len) {
output[[i]]= tagList()
output[[i]][[1]] = tags$div(id = paste("dateranges_div", i, sep = "_"),
dateRangeInput(paste0("daterange", i),
paste("Date range of", dt$datecols[[i]]),
start = min(D[[dt$datecols[[i]]]]),
end = max(D[[dt$datecols[[i]]]])
))
}
# return output tagList() with ui elements
output
}
})
}, ignoreNULL = FALSE)
Part 2: here goes the codes for assigning input$daterange data to filter corresponding columns:
observe({
# loop observeEvent on input$daterange1, input$daterange2...
lapply( 1:dt$datecols_len,
FUN = function(i) {
# don't call the following unless input$datecols is not of length 0
req(dt$datecols_len > 0)
# on change of input$daterange[i]
observeEvent(input[[paste0("daterange", i)]], {
# update reactive values to test whether this loop is working
dt$range[[i]] = input[[paste0("daterange", i)]]
req(dt$range[[i]])
# filter dataset with the corresonding date column:
D = dt$data[dt$cols]
col = dt$datecols[[i]]
dt$range_checks[i] = D[[col]] >= dt$range[[i]][[1]] & D[[col]] <= dt$range[[i]][[2]]
}) # end of observeEvent
}
) # end of lapply()
lapply( dt$range_checks,
FUN = function(x) {
# How to write the code to get the following desired result????
dt$filtered_ind = dt$range_checks[1] & dt$range_checks[2] ... dt$range_checks[i]
}
)
})
I'm developing a shiny app using reactive value, of course. However, I'd like to explore the use of reactiveValues to test my understanding of the concept. My design is to create a dt container of reactive values, e.g. data, cols, rows; so that I can save shiny input$file uploaded data to dt$data; also I'd use checkboxGroupInput to display the columns of the data, which is saved as dt$cols, and let users to select columns and then render data table of dt$data[dt$cols]. Here's the code I used:
dt <- reactiveValues()
observeEvent(input$uploadbutton, {
file <- input$file
req(input$file)
f <- read.csv(file$datapath, header = TRUE)
dt$data <- f
# get the col names of the dataset and assign them to a list
cols <- mapply(list, names(dt$data))
# update columns ui under columnscontrol div
updateCheckboxGroupInput(session, "columns", "Select Columns:", choices = cols, selected = cols)
})
observeEvent(input$columns, { dt$cols <- input$columns })
output$datatbl <- DT::renderDataTable(
dt$data[dt$cols], rownames = FALSE,
# column filter on the top
filter = 'top', server = TRUE,
# autoWidth
options = list(autoWidth = TRUE)
)
The code didn't work, I was thrown with the error of "undefined columns" when dt$data[dt$cols] is called. However, the above works fine if I only use reactive value dt2 <- eventReactive(input$columns, { f <- dt$data[input$columns], f }) and then call dt2() in renderDataTable(). I wonder what's wrong with the use of the variables in reactiveValues.
When you upload the file, the instruction dt$data <- f will then trigger the renderDataTable which uses dt$data. This happens before dt$cols <- input$columns is called therefore dt$colsis NULL and dt$data[dt$cols] throws an error.
You can try with isolate :
isolate(dt$data)[dt$cols]
When a row in a DataTable is clicked, I would like an image in a different panel to be loaded but, I keep getting an error and not.
**Warning in widgetFunc() :
renderDataTable ignores ... arguments when expr yields a datatable object; see ?renderDataTable
Error in basename(file) : a character vector argument expected**
output$image1 <- renderImage({
s = input$table1_rows_selected
if (length(s)) list(src=paste0(imagePath,"/peak",s,".png"))},deleteFile=FALSE)
The function below works however,
output$image1 <- renderImage({list(src=paste0(imagePath,"/peak1.png"))},deleteFile=FALSE)
Here is a full version of the code:
server.R
writeLines("Please select ANY image")
imagePath = file.choose()
# break up the character vector, delete the last word
imagePath = dirname(imagePath)
server = function(input, output) {
output$table1 = renderDataTable({
# the peak table
datatable(peaksTable,
# when rowname is false each row does not have a numeric # associated with it
rownames = FALSE,
# specify the name of the column headers
colnames = c("Seqnames", "Start", "End","Width","Strand","P","Q","Effectsize",
"FDR","Keep","Gene_name","Gene.nearest","Count","Count.pred",
"Coverage","Local.mut.density","Base.context.GC","Tn.Context.TpC",
"Tn.context.CpG","Dnase","Activechrom","Hetchrom","Rept"))
},
escape = FALSE)
# render an Image based on which rows are clicked on.
output$image1 <- renderImage({
s = input$table1_rows_selected
if (length(s)) list(src=paste0(imagePath,"/peak",s,".png"))},deleteFile=FALSE)
ui.R
shinyUI(navbarPage(
title = " Nanoproject",
# first panel , create table of the peaksTable dataframe
tabPanel('Peak Table' ,
dataTableOutput('table1')),
# second panel
tabPanel('Peak Images' ,
imageOutput("image1",width = "auto",height = "auto")
))
I'm not sure where I'm going wrong.
Like it's been pointed out, without a reproducible example it's hard to help.
My guess is that your code is not dealing with the case where no rows are selected. If that's true, something like this should fix the problem:
server.R
output$image1 <- renderImage({
s <- input$table1_rows_selected
# print(s)
if(is.null(s)) return(NULL)
list(src = paste0(imagePath,"/peak",s,".png"))
}, deleteFile=FALSE)
Printing out s could help you understand better whats going on.