Add new row to dataframe when actionButton is clicked - r

I'm trying to create a R Shiny application that creates a 1 row dataframe based on the input values, and when an action button is clicked it adds that dataframe as a new row to another dataframe (which starts blank).
I've browsed around StackOverflow but I couldn't find something that addressed my issue.
What I would like to happen is the following:
input$one <- "A"
input$two <- "B"
input$three <- "C"
df1 = A | B | C
now when I press the actionButton, I would like df2 (which starts blank) to be the following:
df2 = A | B | C
next, I want to be able to add more rows. So if I change my input values to the following:
input$one <- "X"
input$two <- "Y"
input$three <- "Z"
df1 = X | Y | Z
and I click the actionButton again, df2 should update to be the following:
df2 = A | B | C
X | Y | Z
and finally, one last update and click of the actionButton would be the following:
input$one <- "1"
input$two <- "2"
input$three <- "3"
df1 = 1 | 2 | 3
*actionButton click*
df2 = A | B | C
X | Y | Z
1 | 2 | 3
I would like to do this virtually as many times as possible, that every time I click the actionButton it adds whatever is in df1 as a new row to df2. I know that this will have to use rbind, but how can it be done with actionButton?

This worked for me.
mydata <- data.frame()
df <- eventReactive(input$add_payer, {
newrow <- data.frame(ALEMO())
mydata <<- rbind(mydata, newrow)
})
output$all_data <- renderTable(df())

Related

R: Aggregating a list of column names mapped to row numbers based off of a condition in a data frame

Scaled down my dataframe looks like this:
+---+------------+-------------+
| | Label1 | Label2 |
+---+------------+-------------+
| 1 | T | F |
| 2 | F | F |
| 3 | T | T |
+---+------------+-------------+
I need to create a list of lists that map the column names to all the row numbers that have a false boolean as their value. For the above example it would look something like this:
{"Label1" : (2), "Label2" : (1,2)}
I am currently doing it as so:
myList = with(data.frame(which(!myDataFrame, arr.ind = TRUE)), list("colNames" = names(myDataFrame)[col], "rows" = row))
l = list()
count = 1;
for (i in myList[["colNames"]]) {
tmpRowNum = myList[["rows"]][[count]];
tmpList = l[[i]];
if (is.null(tmpList)) {
tmpList = list();
}
l[[i]] = c(tmpList, list(tmpRowNum))
count = count + 1;
}
This does work, but as I am new to R I can only assume there is a more efficient method of doing this. The with function creates two separate lists that I essentially have to combine to get the result that I am looking for.
You could try:
df <- data.frame(Label1=c("T","F","T"),Label2=c("F","F","T"))
lapply(df,function(x) which(x=="F"))
$Label1
[1] 2
$Label2
[1] 1 2
EDIT To get the same by row, use apply with margin=1:
apply(df,1,function(x) which(x=="F"))
To get a vector of the "F"s in row 2:
res <- apply(df,1,function(x) which(x=="F"))
res[[2]]
1 2
One useful way to get the row/column index is with which and arr.ind
i1 <- which(df=="F", arr.ind=TRUE)

Splitting strings and stacking them in one column

I've got a data frame with this structure:
> df
modifications
13-MOD:0057
13-MOD:0046
13-MOD:0051,13-MOD:0076
13-MOD:0036,13-MOD:0076,13-MOD:0016
13-MOD:0256,13-MOD:0156,13-MOD:0956,13-MOD:0125
13-MOD:0014 13-MOD:0156, 13-MOD:0956,13-MOD:0125...n
13-MOD:0012 ... n
To split the data I used this code:
df2 <- data.frame(str_split_fixed(df$modifications, ",", 20))
Basically, I get this data.
> df2
x1 | x2 | x3 | empty |
13-MOD:0057 | empty | empty | empty |
13-MOD:0046 | emply | empty | empty |
13-MOD:0051 | 13-MOD:0076 | empty | empty |
13-MOD:0036 | 13-MOD:0076 | 13-MOD:0016 | empty |
13-MOD:0256 | 13-MOD:0156 | 13-MOD:0956 | 13-MOD:0125
13-MOD:0014 | 13-MOD:0156 | 13-MOD:0956 | 13-MOD:0125 | ... n
13-MOD:0012 | ... | ...n
What I want is remove the empty values and stack the data from columns X2,X3, X4 ... n to the first one X1.
To do that I was using this:
df3 <- melt(setDT(df2), # set df to a data.table
measure.vars = list(c(1:20)), # set column groupings
value.name = 'V')[ # set output name scheme
, -1, with = F]
To remove the empty values:
df3[df3==""] <- NA
histo3 = subset(df3, V1 != 'NA')
But I don't know why I get an error about the length of the column in melt function. Do you know any way to make this easier?.
Reproducible example:
df <- data.frame(modifications=c("UNIMOD:108,UNIMOD:108","UNIMOD:108","UNIMOD:108","UNIMOD:108,UNIMOD:108,UNIMOD:108","UNIMOD:108,UNIMOD:108,UNIMOD:108,UNIMOD:108,UNIMOD:108,UNIMOD:108","UNIMOD:108"))
could it be something like this?
library(stringr)
# input dataset
s <- c('13-MOD:0057', '13-MOD:0046', '13-MOD:0051,13-MOD:0076', '13-MOD:0036,13-MOD:0076,13-MOD:0016', '13-MOD:0256,13-MOD:0156,13-MOD:0956,13-MOD:0125')
s
[1] "13-MOD:0057"
[2] "13-MOD:0046"
[3] "13-MOD:0051,13-MOD:0076"
[4] "13-MOD:0036,13-MOD:0076,13-MOD:0016"
[5] "13-MOD:0256,13-MOD:0156,13-MOD:0956,13-MOD:0125"
# get the individual lengths
lengths <- sapply(str_split(s,','), function(x){ length(x) })
# create the dataframe splitting in N columns
as.data.frame(str_split_fixed(s, ',', max(lengths)))
V1 V2 V3 V4
1 13-MOD:0057
2 13-MOD:0046
3 13-MOD:0051 13-MOD:0076
4 13-MOD:0036 13-MOD:0076 13-MOD:0016
5 13-MOD:0256 13-MOD:0156 13-MOD:0956 13-MOD:0125
UPDATE 1
To stack all the non-empty cells into a single column
# create the dataframe splitting in N columns
first.matrix <- str_split_fixed(s, ',', max(lengths))
# select only the cells != ""
first.matrix[which(first.matrix!="")]
[1] "13-MOD:0057" "13-MOD:0046" "13-MOD:0051" "13-MOD:0036" "13-MOD:0256" "13-MOD:0076"
[7] "13-MOD:0076" "13-MOD:0156" "13-MOD:0016" "13-MOD:0956" "13-MOD:0125"

Getting a dataframe of logical values from a vector of statements

I have a number of lists of conditions and I would like to evaluate their combinations, and then I'd like to get binary values for these logical values (True = 1, False = 0). The conditions themselves may change or grow as my project progresses, and so I'd like to have one place within the script where I can alter these conditional statements, while the rest of the script stays the same.
Here is a simplified, reproducible example:
# get the data
df <- data.frame(id = c(1,2,3,4,5), x = c(11,4,8,9,12), y = c(0.5,0.9,0.11,0.6, 0.5))
# name and define the conditions
names1 <- c("above2","above5")
conditions1 <- c("df$x > 2", "df$x >5")
names2 <- c("belowpt6", "belowpt4")
conditions2 <- c("df$y < 0.6", "df$y < 0.4")
# create an object that contains the unique combinations of these conditions and their names, to be used for labeling columns later
names_combinations <- as.vector(t(outer(names1, names2, paste, sep="_")))
condition_combinations <- as.vector(t(outer(conditions1, conditions2, paste, sep=" & ")))
# create a dataframe of the logical values of these conditions
condition_combinations_logical <- ????? # This is where I need help
# lapply to get binary values from these logical vectors
df[paste0("var_",names_combinations] <- +(condition_combinations_logical)
to get output that could look something like:
-id -- | -x -- | -y -- | -var_above2_belowpt6 -- | -var_above2_belowpt4 -- | etc.
1 | 11 | 0.5 | 1 | 0 |
2 | 4 | 0.9 | 0 | 0 |
3 | 8 | 0.11 | 1 | 1 |
etc. ....
Looks like the dreaded eval(parse()) does it (hard to think of a much easier way ...). Then use storage.mode()<- to convert from logical to integer ...
res <- sapply(condition_combinations,function(x) eval(parse(text=x)))
storage.mode(res) <- "integer"

Selecting random row from a data.frame and assigning it to one of the two other data.frames based on three conditions in R

I have a data.frame (a) as mentioned below:
V1 V2
1 a b
2 a e
3 a f
4 b c
5 b e
6 b f
7 c d
8 c g
9 c h
10 d g
11 d h
12 e f
13 f g
14 g h
Lets assume each row represents an edge of a graph and the values of the rows are vertices.
What I want is to pick a random row (which is an edge) from data.frame (a) and assign it to data.frame (b) or data.frame (c) based on the three conditions below. Just to clarify that data.frame (b and c) are empty in the beginning. So the conditions are:
When a row(edge) is randomly picked from data.frame (a) and if neither vertex has been assigned, then assign the edge to the data.frame with least number of rows.
To clarify this condition:
Lets say I pick a random row(edge)#2 from data.frame (a) which has two vertices "a" and "e". So I should check if data.frame (b) and data.frame (c) have either "a" or "e" present in any of their rows. So if they have "a" or "e" present then this rule should not be implemented and next rule should be checked. If both data.frames do not have "a" or "e" present in any of the rows then nrow(number of rows) should be checked in both data.frames and the one with lower number of nrow() should be assigned that row. If both have same nrow() then any of the two data.frame could be assigned that row.
When a row(edge) is randomly picked from data.frame (a) and if one of the vertices of that row is present in any of the data.frames (b) or (c) then assign the row(edge) to that data.frame
If a random row is picked say for example #3 which has "a" and "f". Then data.frames b and c should be checked to see if any of the rows contain either "a" or "f". Suppose data.frame (b) does not contain either "a" or "f" but data.frame (c) contains "f". So the row should be assigned to data.frame (c).
Now there is also a possibility that data.frame (b) contains "a" and data.frame(c) contains "f". In that case, all the instances of "a" in data.frame (b) and "f" in data.frame (c) should be counted. If "a" appears 3 times and "f" appears 4 times then the row should be assigned to (b) i.e The row then should be assigned to the data.frame which has lower number of instances of the vertex present in that data.frame.
When a row(edge) is randomly picked from data.frame (a) and if both the vertices of that row are present in a data.frame then assign the row to that data.frame
So to summarize, a random row should be picked from data.frame(a) and check for the above mentioned conditions and should be assigned to data.frame(b) or (c) after going through the conditions above. So all the rows of data.frame(a) have to be checked for the conditions.
This should get you started. You can't continually randomly select rows, as you discovered, as that leads to duplicates. Instead, randomly assign the rows to a vector which gives the order they should be processed in. If you don't think this is the right approach, you could also randomly select a row, then remove it from a and later randomly select from what remains. If you still need a, remove the row from a copy of a.
set.seed(1)
dfa <- data.frame(V1 = sample(letters[1:9], replace = TRUE), V2 = sample(letters[1:9], replace = TRUE))
todo <- sample(1:nrow(dfa), nrow(dfa), replace = FALSE)
dfb <- dfa[todo[1],]
dfc <- dfa[todo[2],]
Now continue through 'todo' in order, applying your conditions
and using rbind to add rows to the dfb and dfc:
for (i in 3:length(todo)) {
# apply your logic
# if a row belongs in dfb, do
dfb <- rbind(dfb, dfa[todo[i],])
# etc
}
aCopy<-read.table("isnodes.txt")
p1<-aCopy[-c(1:nrow(aCopy)),]
p2<-aCopy[-c(1:nrow(aCopy)),]
currentRowHistory<-aCopy[-c(1:nrow(aCopy)),]
for(i in 1:nrow(a)) {
currentRow <- aCopy[sample(nrow(aCopy), 1), ]
currentRowHistory <- rbind(currentRow,currentRowHistory)
currentRowV1 <- as.character(currentRow$V1[1])
currentRowV2 <- as.character(currentRow$V2[1])
aCopy <- aCopy[!(aCopy$V1 == currentRowV1 & aCopy$V2 == currentRowV2),]
if(length(which(currentRowV1 == p1$V1)) | length(which(currentRowV1 == p1$V2))){
if(length(which(currentRowV2 == p1$V1)) | length(which(currentRowV2 == p1$V2))){
p1<-rbind(currentRow,p1)
result <- "case 1 assign it to p1"
}
else if(length(which(currentRowV2 == p2$V1)) | length(which(currentRowV2 == p2$V2))){
V1occurances <- length(which(p1$V1 == currentRowV1))+length(which(p1$V2==currentRowV1))
V2occurances <- length(which(p2$V1 == currentRowV2))+length(which(p2$V2==currentRowV2))
ifelse(V1occurances<V2occurances,p1<-rbind(currentRow,p1),p2<-rbind(currentRow,p2))
result <- "case 2"
}
else {
p1<-rbind(currentRow,p1)
result <- "case 3 assign it to p1"
}
} else if(length(which(currentRowV1 == p2$V1)) | length(which(currentRowV1 == p2$V2))){
if(length(which(currentRowV2 == p2$V1)) | length(which(currentRowV2 == p2$V2))){
p2<-rbind(currentRow,p2)
result <- "case 1 assign it to p2"
}
else if(length(which(currentRowV2 == p1$V1)) | length(which(currentRowV2 == p1$V2))){
V1occurancesInP2 <- length(which(p2$V1 == currentRowV1))+length(which(p2$V2==currentRowV1))
V2occurancesInP1 <- length(which(p1$V1 == currentRowV2))+length(which(p1$V2==currentRowV2))
ifelse(V1occurancesInP2<V2occurancesInP1,p2<-rbind(currentRow,p2),p1<-rbind(currentRow,p1))
result <- "case 2"
}
else {
p2<-rbind(currentRow,p2)
result <- "case 3 assign it to p2"
}
} else if(length(which(currentRowV2 == p1$V1)) | length(which(currentRowV2 == p1$V2))){
p1<-rbind(currentRow,p1)
result <- "Assign it to p1 case 3"
} else if(length(which(currentRowV2 == p2$V1)) | length(which(currentRowV2 == p2$V2))){
p2<-rbind(currentRow,p2)
result <- "Assign it to p2 case 3"
} else {
ifelse(nrow(p1)<nrow(p2),p1<-rbind(currentRow,p1), p2<-rbind(currentRow,p2))
}
}

Find string match in R

I have data.frame with 2 columns and thousands rows of random strings as:
Column1 Column2
"this is done in 1 hour" "in 1 hour"
I would like to get a new data.frame column like this:
Column3
"this is done"
So basically match the string according to the Column2 and get the remaining of Column1. How to approach this?
EDIT:
This would not solve the issues since the length of strings varies so I can't do:
substrRight <- function(x, n){
substr(x, nchar(x)-n+1, nchar(x))
}
substrRight(x, 3)
So I would need something like grepl matching.
You can do it with regular expression:
data <- data.frame(Column1 = "this is done in 1 hour", Column2 = "in 1 hour")
data$Column3 <- gsub(data$Column2, '', data$Column1) # Replace fist parameter by second in third.
EDIT:
For more than 1 row, you can use mapply:
data <- data.frame(Column1 = c("this is done in 1 hour", "this is a test"), Column2 = c("in 1 hour", "a test"))
data$Column3 <- mapply(gsub, data$Column2, '', data$Column1)
Here is an example of how you could do it:
# example data frame
testdata <- data.frame(colA=c("this is","a test"),colB=c("is","a"),stringsAsFactors=FALSE)
# adding the new column
newcol <- sapply(seq_len(nrow(testdata)),function(x) gsub(testdata[x,"colB"],"",testdata[x,"colA"],fixed=TRUE))
new.testdata <- transform(testdata,colC=newcol)
# result
new.testdata
# colA | colB | colC
# --------------------------
# 1 this is | is | th
# 2 a test | a | test
EDIT: gsub(str1,'',str2,fixed=TRUE) deletes all occurrences of str1 within str2 whereas using sub would only delete the first occurrence. Since str1 is usually interpreted as regular expression, it is important to set fixed=TRUE. Otherwise a mess happens if str1 contains characters such as .\+?*{}[]. To address the comment, the following would replace only the last occurrence of str1 in str2 leading to the desired output:
revColA <- lapply(testdata[["colA"]],function(x) paste0(substring(x,nchar(x):1,nchar(x):1)))
revColA <- lapply(revColA,paste,collapse='')
revColB <- lapply(testdata[["colB"]],function(x) paste0(substring(x,nchar(x):1,nchar(x):1)))
revColB <- lapply(revColB,paste,collapse='')
revNewCol <- sapply(seq_len(nrow(testdata)),function(x) sub(revColB[x],"",revColA[x],fixed=TRUE))
newcol <- lapply(revNewCol,function(x) paste0(substring(x,nchar(x):1,nchar(x):1)))
newcol <- sapply(newcol,paste,collapse='')
new.testdata <- transform(testdata,colC=newcol)
### output ###
# colA colB colC
------------------------
# 1 |this is | is | this
# 2 | a test | a | test

Resources