Again reactiveFileReader - r

Let's say get_line() is reactive, returns an integer, e.g.:
get_line <- reactive({
i=1
getline=0
while (getline==0 & i<=100) {
x <- readLines(input$StoreDestination , n =100)[i]
x <- stringr::str_extract(x, pattern = "t1=[0-9]")
if(!is.na(x)) {getline=i}
i=i+1
}
return(getline)
})
Next calling reactiveFileReader such that skip parameter of the read.table function is reactive, e.g.:
df_source <- reactiveFileReader(
intervalMillis = 10000,
session=session,
filePath = reactive({ input$StoreDestination }),
readFunc = read.table,
skip = get_line(), ### with () as we see :)
check.names = F,
sep = ";")
Getting Error:
Warning: Error in .getReactiveEnvironment()$currentContext: Operation not allowed without an active reactive context.
• You tried to do something that can only be done from inside a reactive consumer.
tried to sort of explicitly state that it is a reactive:
df_source <- reactiveFileReader(
intervalMillis = 10000,
session=session,
filePath = reactive({ input$StoreDestination }),
readFunc = read.table,
skip = reactive({ get_line() }),
check.names = F,
sep = ";")
Getting Error:
Warning: Error in >: comparison (6) is possible only for atomic and list types
any try such that df_source <- reactive({ reactiveFileReader( ..., skip = get_line(),...)})
Getting Error:
Warning: Error in as.data.frame.default: cannot coerce class ‘c("reactiveExpr", "reactive", "function")’ to a data.frame
However if we use, fixed value for the skip, everything is working. e.g.:
df_source <- reactiveFileReader(
intervalMillis = 10000,
session=session,
filePath = reactive({ input$StoreDestination }),
readFunc = read.table,
skip = 4,
check.names = F,
sep = ";")

Related

Using reactive input within reactiveValue() function

I am new to shiny and trying to figure out some reactive stuff.
Currently this works for a static csv.
## function to return random row from twitter csv
tweetData <- read.csv('twitterData1.csv')
## stores reactive values
appVals <- reactiveValues(
tweet = tweetData[sample(nrow(tweetData), 1), ],
ratings = data.frame(tweet = character(), screen_name = character(), rating = character())
)
I need the same block of reactive values to be funciton but using a selected csv using input$file.
appVals <- reactiveValues(
csvName <- paste0('../path/', input$file),
tweetData <- read.csv(csvName),
tweet = tweetData[sample(nrow(tweetData), 1), ],
ratings = data.frame(tweet = character(), screen_name = character(), rating = character())
)
I get the error:
Warning: Error in : Can't access reactive value 'file' outside of reactive consumer.
I've tried moving things around but I keep getting stuck, help appreciated!
The error is telling that you should update the values inside a reactive expression.
First initialize the reactive values:
tweetData <- read.csv('twitterData1.csv')
appVals <- reactiveValues()
appVals$tweet <- tweetData[sample(nrow(tweetData), 1), ]
appVals$ratings <- data.frame(tweet = character(), screen_name = character())
Then update them with a reactive:
observeEvent(input$file,{
csvName <- paste0('../path/', input$file)
if (file.exists(csvName) {
tweetData <- read.csv(csvName)
appVals$tweet = tweetData[sample(nrow(tweetData), 1), ]
appVals$ratings = data.frame(tweet = character(), screen_name = character(), rating = character())
}
})

Optional argument parsing in R for working directory

I am parsing argument in a rscript (merge_em.r) below. Let's say I run the code below using commandline Rscript merge_em.r dataframe1, dataframe2 which gives me this error: Error in setwd(working.dir) : character argument expected. I want to keep working directory argument optional. How do I do it?
library("argparse")
merge_em <- function (x, y, working.dir){
mergedfile <- merge (x, y, by = intersect(names(x), names(y)))
if (missing(working.dir)) {
print ("Working directory not specified! Will use present working directory.")
working.dir <- as.character(file.path(getwd()))
} else {
working.dir <- working.dir
}
setwd(working.dir)
write.table (mergedfile, "merged.txt",
col.names = FALSE,
row.names = FALSE,
sep = "\t",
quote = FALSE
)
}
main <- function() {
# breaks if you set warn = 2
options(error = traceback,
warn = 1)
parser <- ArgumentParser(prog = "merge_em.r",
description = "Merge dataframes")
parser <- ArgumentParser()
parser$add_argument("x")
parser$add_argument("y")
parser$add_argument(
"--working_dir",
dest = "working.dir",
type = "character",
metavar = "DIR",
required = FALSE,
help = "Working directory where files are present"
)
args <- parser$parse_args()
working.dir <- args$working.dir
x <- args$x
if (!R.utils::isAbsolutePath(x))
x <- file.path(working.dir, x)
y <- args$y
if (!R.utils::isAbsolutePath(y))
y <- file.path(working.dir, y)
tryCatch(
merge_em (x, y, working.dir)
,
finally = setwd(working.dir)
)
}
main()
You could exchange the missing() conditional to this:
if (working.dir=="") {
print ("Working directory not specified! Will use present working directory.")
working.dir <- as.character(file.path(getwd()))
} else {
print ("Working directory is specified!")
working.dir <- working.dir
}
And change the argument for working_dir to (default=""):
parser$add_argument(
"--working_dir",
dest = "working.dir",
type = "character",
metavar = "DIR",
default="",
required = FALSE,
help = "Working directory where files are present"
)
And change the tryCatch to:
tryCatch(merge_em(x, y, working.dir), finally = print("Fin"))
Why are you using setwd() io the finally part? If the argument is not given, there is nothing to set or?
Like that you can call the script like this, for example:
Rscript merge_em.r data_frame1, data_frame2
Or with a directory:
Rscript merge_em.r data_frame1, data_frame2, --working_dir "path_to_folder"
Full code:
library(argparse)
merge_em <- function (x, y, working.dir){
mergedfile <- merge (x, y, by = intersect(names(x), names(y)))
if (working.dir=="") {
print ("Working directory not specified! Will use present working directory.")
working.dir <- as.character(file.path(getwd()))
} else {
print ("Working directory is specified!")
working.dir <- working.dir
}
setwd(working.dir)
write.csv(x = mergedfile, file = "merged.txt",
row.names = FALSE,
quote = FALSE
)
}
main <- function() {
# breaks if you set warn = 2
options(error = traceback,
warn = 1)
parser <- ArgumentParser(prog = "merge_em.r",
description = "Merge dataframes")
parser <- ArgumentParser()
parser$add_argument("x")
parser$add_argument("y")
parser$add_argument(
"--working_dir",
dest = "working.dir",
type = "character",
metavar = "DIR",
default="",
required = FALSE,
help = "Working directory where files are present"
)
args <- parser$parse_args()
working.dir <- args$working.dir
x <- args$x
if (!R.utils::isAbsolutePath(x))
x <- file.path(working.dir, x)
y <- args$y
if (!R.utils::isAbsolutePath(y))
y <- file.path(working.dir, y)
tryCatch(merge_em(x, y, working.dir), finally = print("Fin"))
}
main()
You can set it as a default and override it when necessary.
merge_em <- function (x, y, working.dir = getwd()){
mergedfile <- merge (x, y, by = intersect(names(x), names(y)))
setwd(working.dir)
write (mergedfile, "merged.txt",
col.names = FALSE,
row.names = FALSE,
sep = "\t",
quote = FALSE
)
}
And override it with some other value:
merger_em(x, y, 'another/path/dir')
I haven't tested this, but default parameters are a standard in many languages.
Also, you can setwd with getwd like: setwd(getwd())

How to pass user input inside an eventReactive expression Shiny/R

I am having trouble with creating a new variable in dplyr::mutate using a user inputted variable through selectInput in the UI.
gwrdata <- eventReactive(input$rungwr, {
sp_shape <- as(data(), "Spatial")
bwG <- gwr.sel(formula(), data = sp_shape, gweight = gwr.Gauss, verbose = FALSE)
gwrG <- gwr(formula(), data = sp_shape, bandwidth = bwG,
gweight = gwr.Gauss, hatmatrix = TRUE)
sf_gwr <- st_as_sf(gwrG$SDF)
bins <- 3
browser()
sf_gwr <- mutate(sf_gwr, parBin = cut2(sf_gwr[, input$inVar],
g = bins, levels.mean = TRUE))
sf_gwr <- mutate(sf_gwr, sigBin = cut2(localR2, g = bins, levels.mean = TRUE))
bvColors = c("#e8e8e8", "#dfb0d6", "#be64ac", "#ace4e4",
"#a5add3", "#8c62aa", "#5ac8c8", "#5698b9", "#3b4994")
levels(sf_gwr$parBin) <- 1:bins
levels(sf_gwr$sigBin) <- 1:bins
sf_gwr <- mutate(sf_gwr, value = paste(parBin, '-', sigBin, sep = ''))
sf_gwr
})
There are two mutate functions. The process works fine if it is hard coded like it is with localR2. However when using the sf_gwr[,input$inVar] the following error is given.
Evaluation error: no applicable method for 'st_geometry<-' applied to an object of class "list".
Does this have something to do with the subsetting in the mutate function?

R asks for a list which seems to be a list according to is.list (=TRUE)

I am using the RAM package.
The function I use is very simple for diversity index, adding up a column in my metadata ;
outname <-OTU.diversity(data=OTUtables, meta=metatables)
(Arguments: data a list of OTU tables.
meta the metadata to append the outputs)
I am looping it but I get this error:
please provide otu tables as list; see ?RAM.input.formatting
So I go to that help menu and read this:
one data set:
data=list(data=otu)
multiple data sets:
data=list(data1=otu1, data2=otu2, data3=otu3)
here is my code:
i <- 1
for(i in 1:nrow(metadataMasterTax)){
temp <- read.table(paste(metadataMasterTax$DataAnFilePath[i], metadataMasterTax$meta[i], sep = ""),
sep = "\t", header = TRUE, dec = ".", comment.char = "", quote = "", stringsAsFactors = TRUE,
as.is = TRUE)
temp2 <- temp
temp2$row.names <- NULL #to unactivate numbers generated in the margin
trans <- read.table(paste(metadataMasterTax$taxPath[i], metadataMasterTax$taxName[i], sep = ""),
sep = "\t", header = TRUE, dec = ".", comment.char = "", quote = "", stringsAsFactors = TRUE,
as.is = TRUE, check.names = FALSE)
trans2 <- trans
trans2$row.names <- NULL #to unactivate numbers generated in the margin
data=list(data=trans2[i])
temp2[i] <- OTU.diversity(data=trans2[i], meta=temp2[i])
# Error in OTU.diversity(trans2, temp2) :
# please provide otu tables as list; see ?RAM.input.formatting
# is.list(trans2)
# [1] TRUE
# is.list(data)
# [1] TRUE
temp$taxonomy <- temp2$taxonomy
write.table(temp, file=paste(pathDataAn, "diversityDir/", metadataMasterTax$ShortName[i], ".meta.div.tsv", sep = ""),
append = FALSE,
sep = "\t",
row.names = FALSE)
}
Can anyone help me please....
thanks a lot
Because the main problem appears to be getting the OTU.diversity function to work, I focus on this issue. The code snippet below runs OTU.diversity without any problems, using the Google sheets data provided by OP.
library(gsheet)
library(RAM)
for (i in 1:2) {
# Meta data
temp <- as.data.frame(gsheet2tbl("https://drive.google.com/open?id=1hF47MbYZ1MG6RzGW-fF6tbMT3z4AxbGN5sAOxL4E8xM"))
temp$row.names <- NULL
# OTU
trans <- as.data.frame(gsheet2tbl("https://drive.google.com/open?id=1gOaEjDcs58T8v1GA-OKhnUsyRDU8Jxt2lQZuPWo6XWU"))
trans$row.names <- NULL
rownames(temp) <- colnames(trans)[-ncol(trans)]
temp2 <- OTU.diversity(data = list(data = trans), meta = temp)
write.table(temp2,
file = paste0("file", i, ".meta.div.tsv"), # replace
append = FALSE,
sep = "\t",
row.names = FALSE)
}
Replace for (i in 1:2) with for(i in 1:nrow(metadataMasterTax)), as.data.frame(gsheet2tbl(...)) with read.table(...), and the file argument in write.table with the appropriate string.

Can I nest apply functions in R?

I have a series of CSV files that I want to prepare to append together. My appended file will be large, so I'd like to convert some string variables to numeric and date formats in the individual files rather than the larger appended file.
With other software, I would have one for loop that opens the file and nested for loops that would iterate over certain groups of variables. For this project, I am attempting to use R and apply functions.
I have mapply and lapply functions that work independently. I'm now trying to figure out how to combine them. Can I nest them? (See below for the independent parts and the nesting.)
(This code references code in the answer to How do I update data frame variables with sapply results?)
(Is it customary to provide an example CSV to give a reproducible example? Does R have built-in example CSVs?)
These work separately:
insert.division <- function(fileroot, divisionname){
ext <- ".csv"
file <- paste(fileroot, ext, sep = "")
data <- read.csv(file, header = TRUE, stringsAsFactors = FALSE)
data$division <- divisionname
write.csv(data, file = paste(fileroot, "_adj3", ext, sep = ""),
row.names = FALSE)
}
files <- c(
"file1",
"file2",
"file3",
"file4",
"file5"
)
divisions <- c(1:5)
#Open the files, insert division name, save new versions
mapply(insert.division, fileroot = files, divisionname = divisions)
#Change currency variables from string to numeric
currency.vars <- c(
"Price",
"RetailPrice"
)
df[currency.vars] <- lapply(
df[currency.vars],
function(x) as.numeric(sub("^\\(","-", gsub("[$,]|\\)$","", x)))
)
Combined version:
file.prep <- function(fileroot, divisionname, currency.vars){
ext <- ".csv"
file <- paste(fileroot, ext, sep = "")
data <- read.csv(file, header = TRUE, stringsAsFactors = FALSE)
data$division <- divisionname
df[currency.vars] <- lapply(
df[currency.vars],
function(x) as.numeric(sub("^\\(","-", gsub("[$,]|\\)$","", x)))
)
write.csv(data, file = paste(fileroot, "_adj", ext, sep = ""),
row.names = FALSE)
}
#Open the files, insert division name, change the currency variables,
#save new versions
mapply(file.prep, fileroot = files, divisionname = divisions,
currency.vars = df[currency.vars])
I'm not really sure why you're writing it back to file after changing the data, but here's an example of how I might approach the problem.
## Set up three csv files
set.seed(1)
DF <- data.frame(
w = paste0("($", sample(1500, 30) / 100, ")"),
x = Sys.Date() + 0:29,
y = sample(letters, 30, TRUE),
z = paste0("($", sample(1500, 30) / 100, ")")
)
fnames <- paste0("file", 1:3, ".csv")
Map(write.csv, split(DF, c(1, 10, 20)), fnames, row.names = FALSE)
Using your file.prep() function, you could adjust it a little and do
file.prep <- function(fileroot, divname, vars) {
ext <- ".csv"
file <- paste0(fileroot, ext)
data <- read.csv(file, stringsAsFactors = FALSE)
data$division <- divname
data[vars] <- lapply(data[vars], function(x) {
type.convert(gsub("[()$]", "", x))
})
write.csv(data, row.names = FALSE, file = paste0(fileroot, "_adj", ext))
}
divname <- 1:3
fnames <- paste0("file", divname)
Map(file.prep, fnames, divname, MoreArgs = list(vars = c("w", "z")))

Resources