Related
I'm trying to make a table in R with formattable but some rows are returning NA and I don't know how to remove them.
In Excel the table looks like this, and this is how I would like it to be:
In R looks like this:
How can I make this table in R looks like in Excel?
Code:
library(readxl)
library(formattable)
indicadores <- read_excel("Dados/Tabela Indicadores.xlsx")
tabela_indicadores <- formattable(indicadores,
align = c("c", "c", "c", "c"))
File that I'm using: https://drive.google.com/file/d/1CDhMkW7l78WEj45mYZ86LTY6PjCyhsSd/view?usp=sharing
The easiest way to do this is to replace the missing values with a character, "-" or "":
indicadores$Tema <- ifelse(is.na(indicadores$Tema), "-", indicadores$Tema)
tabela_indicadores <- formattable(indicadores, align = c("c", "c", "c", "c"))
I am assuming you do not want to exclude the lines completely. If you do want to remove them, use
tabela_indicadores <- formattable(na.omit(indicadores), align = c("c", "c", "c", "c"))
I use the DT package in Shiny and want to use filters, however I have a problem with the styling of the filters:
Code: DT::datatable(overview,editable=TRUE, rownames=FALSE, selection='none', filter='top')
This is the way my DT looks when I add items. When I leave the dropdown, it looks like the following picture (collapsed) which is of course pretty bad.
I want to preserve the styling with the grey box and not have anything like "[..." for my users. How can I do this? If that is not possible with DT, using another package is also an option for me.
Edit: Reproduceable example
df <- data.frame(a = c("a", "a", "b", "b", "c", "c"), b = c(1,2,3,4,5,6), c("A", "B"))
df <- setNames(df, c("A", "B"))
DT::datatable(df,editable=TRUE, rownames=FALSE, selection='none', filter='top')
Thank you!
I can save a bunch of plots but it names them as the first value from each list item rather than the name of the variable.
delm2<-data.frame(N = c(5.881, 5.671, 7.628, 4.643, 6.598, 4.485, 4.465, 4.978, 4.698, 3.685, 4.915, 4.983, 3.288, 5.455, 5.411, 2.585, 4.321, 4.661),
t1 = c("N", "N", "T", "T", "N", "N", "T", "N", "N", "N", "N", "T", "T", "T", "T", "T", "T", "N"),
t3 = c("r","v", "r", "v", "v", "r", "c", "c", "v", "r", "c", "c", "r", "v","c", "r", "v", "c"),
B = c(1.3, 1.3, 1.33, 1.25, 1.4, 1.34, 1.36, 1.39, 1.36, 1.42, 1.38, 1.31, 1.37, 1.44, 1.22, 1.4, 1.46, 1.35))
library(boot)
lapply(as.list(delm2[,c('N','B')]),
function(i){
bmp(filename = paste0(i,".bmp"), width = 350, height = 400)
glm.diag.plots(glm(i ~ t1*t3,data=del))
dev.off()
})
This saves the plots but they are named with number values from the data rather than the name of each target of lapply...
i.e. current output is two files named "5.881" and "1.3", when I want the same two files but named "N" and "B"
I thought I could change paste0(i,".bmp") to paste0(names(i),".bmp") but that just saves the first one, with no name at all.
It looks like you can give names that are just integers in How to save and name multiple plots with R but I want the names of the variables from the list or the two numerics N and B in delm2.
It looks from Saving a list of plots by their names() like this would be easier with ggplot output but ggsave didn't work on one glm.diag.plots output.
(Disregard my previous suggestion using Map.)
The big takeaway is how to derive the formula dynamically. One way is with as.formula, which takes a string and converts into a formula that can be used in a model-generating function (for example).
One problem with using lapply(as.list(delm2[,c('N','B')]), ...) is that the remainder of the data (i.e., columns t1 and t3) are not passed, just one vector at a time. (I'm wondering if your reference to del is a typo, un-released/hidden data, or something else.)
Try this:
lapply(c("N", "B"), function(nm) {
bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = delm2))
dev.off()
})
In general, I don't like breaching scope inside these functions. That is, I try to not reach outside lapply for data when I can pass it fairly easily. The above in a pedantic-language way could look like:
lapply(c("N", "B"), function(nm, x) {
bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = x))
dev.off()
}, x = delm2)
While this preserves scope, it may be confusing if you do not understand what is going on.
This might be a great time to use for instead of one of the *apply* functions. Everything you want is in side-effect, and since for and *apply are effectively the same speed, you gain readability:
for (nm in c("N", "B")) {
bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = delm2))
dev.off()
}
(In this case, there is no "scope breach", so I used the original variable.)
Parenthetically, to tie-in my now-edited-out and incorrect answer that included Map. Here's an example using Map that does more to demonstrate what Map (and mapply) are doing, vice actually improving on your immediate need.
If for some reason you wanted them named something distinct from "N.bmp", you could do this:
Map(function(fn, vn, x) {
bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = x))
dev.off()
}, c("N2.bmp", "b3456.bmp"), c("N", "B"), list(delm2))
Two things to note from this:
The use of list(delm2) is to wrap that structure into a single "thing" that is passed repeated to the mapped function. If we did just delm2 (no list(...)), then it would try to use the first column of delm2 with each of the first elements. This might be useful in other scenarios, but in your glm example you need other columns present, so you cannot include just one column at a time. (Well, there are ways to do that, too ... but important at the moment.)
The first time the anonymous function is called, fn is "N2.bmp", vnis"N", andxis the full dataset ofdelm2. The second time the anon-func is called,fnis"b3456.bmp",vnis"B", andxis again the full dataset ofdelm2`.
I label this portion "parenthetic" because it really doesn't add to this problem, but since I started that way in my first-cut answer, I thought I'd continue with the methodology, the "why" of my choice of Map. In the end, I think the for solution or one of the lapply solutions should be fine for you.
I want to generate a random password for employees with the function below. This is my first attempt with functions in R. So I need a bit help.
genPsw <- function(num, len=8) {
# Vorgaben für die Passwortkonventionen festlegen
myArr <- c("", 2, 3, 4, 5, 6, 7, 8, 9, "A", "B",
"C", "D", "E", "F", "G", "H", "J", "K", "L", "M",
"N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"!", "§", "$", "%", "&", "(", ")", "*")
# replicate is a wrapper for the common use of sapply for repeated evaluation of an expression
# (which will usually involve random number generation).
replicate(num, paste(sample(myArr, size=len, replace=T), collapse=""))
# nrow of dataframe mitarbeiter
dim_mitarbeiter <- nrow(mitarbeiter)
for(i in 1:dim_mitarbeiter) {
# Random Number Generation with i
set.seed(i)
# Generate Passwort for new variable password
mitarbeiter$passwort <- genPsw(i)
}
}
With the answer form Floo0 I've changed the function to somthing like that, but it doesn't work:
genPsw <- function(num, len=8) {
# Vorgaben für die Passwortkonventionen festlegen
sam<-list()
sam[[1]]<-1:9
sam[[2]]<-letters
sam[[3]]<-LETTERS
sam[[4]]<-c("!", "§", "$", "%", "&", "(", ")", "*")
# nrow of dataframe mitarbeiter
dim_mitarbeiter <- nrow(mitarbeiter)
for(i in 1:dim_mitarbeiter) {
# Random Number Generation with i
tmp<-mapply(sample,sam,c(2,2,2,2))
# Generate Passwort for new variable password
mitarbeiter$passwort <- paste(sample(tmp),collapse="")
}
}
What about
samp<-c(2:9,letters,LETTERS,"!", "§", "$", "%", "&", "(", ")", "*")
paste(sample(samp,8),collapse="")
result is something like this
"HKF§VvnD"
Caution:
This approch does not enforce having capitals, numbers, and non alpha numeric symbols
EDIT:
If you want to enforce a certain number of capitals, numbers, and non alpha numeric symbols you could go with this:
sam<-list()
sam[[1]]<-1:9
sam[[2]]<-letters
sam[[3]]<-LETTERS
sam[[4]]<-c("!", "§", "$", "%", "&", "(", ")", "*")
tmp<-mapply(sample,sam,c(2,2,2,2))
paste(sample(tmp),collapse="")
Where c(2,2,2,2) specifies the number of numbers, letters, capital letters and symbild (in this order). Result:
[1] "j$bP%5R3"
EDIT2:
To produce an new column in you table mitarbeiter just use
passwort<-replicate(nrow(mitarbeiter),paste(mapply(sample,sam,c(2,2,2,2)),collapse=""))
mitarbeiter$passwort<-passwort
There is function which generates random strings in stringi package:
require(stringi)
stri_rand_strings(n=2, length=8, pattern="[A-Za-z0-9]")
## [1] "90i6RdzU" "UAkSVCEa"
This might work, one might want to alter ASCII to avoid unwanted symbols:
generatePwd <- function(plength=8, ASCII=c(33:126)) paste(sapply(sample(ASCII, plength), function(x) rawToChar(as.raw(x))), collapse="")
The below script creates a password of specified length from a combination of upper and lowercase letters, digits and 32 symbols (punctuation, etc.).
# Store symbols as a vector in variable punc
R> library(magrittr) # Load this package to use the %>% (pipe) operator
R> punc_chr <- "!#$%&’()*+,-./:;<=>?#[]^_`{|}~" %>%
str_split("", simplify = TRUE) %>%
as.vector() -> punc
# Randomly generate specified number of characters from 94 characters
R> sample(c(LETTERS, letters, 0:9, punc), 8) %>%
paste(collapse = "") -> pw
R> pw # Return password
[1] "fAXVpyOs"
I like the brevity of L.R.'s solution, although I don't follow what it does 100%.
My solution allows to specify the length of the password but also ensures that at least one lower case, one upper case, one numeric, and one special character is included, and allows reproducibility. (ht to moazzem for spelling out all the special characters.)
gen_pass <- function(len=8,seeder=NULL){
set.seed(seeder) # to allow replicability of passw generation
# get all combinations of 4 nums summing to length len
all_combs <- expand.grid(1:(len-3),1:(len-3),1:(len-3),1:(len-3))
sum_combs <- all_combs[apply(all_combs, 1, function(x) sum(x)==len),]
# special character vector
punc <- unlist(strsplit("!#$%&’()*+,-./:;<=>?#[]^_`{|}~",""))
# list of all characters to sample from
chars <- list(punc,LETTERS,0:9,letters)
# retrieve the number of characters from each list element
# specified in the sampled row of sum_combs
pass_chars_l<- mapply(sample, chars,
sum_combs[sample(1:nrow(sum_combs),1),],
replace = TRUE)
# unlist sets of password characters
pass_chars <- unlist(pass_chars_l)
# jumble characters and combine into password
passw <- str_c(sample(pass_chars),collapse = "")
return(passw)
}
I am still wondering how the (1:(len-3),1:(len-3),1:(len-3),1:(len-3)) in expand.grid(1:(len-3),1:(len-3),1:(len-3),1:(len-3)) can be expressed more elegantly?
I have just tried the function proposed by Fmerhout. It seems like an excellent solution. thanks a lot. But because of the last line of code:
passw <- str_c (sample (pass_chars), collapse = "")
the function does not work.
I tried :
passw <- str (sample (pass_chars), collapse = "")
... and now it works:
example with a seed:
>gen_pass(4,2)
gives: chr [1:4] "y" "[" "O" "1"
In order to obtain a directly usable password, I changed the end of the code this way:
zz <- sample(pass_chars)
passw <- paste(zz, sep = "", collapse = "")
return(passw)
}
So, now we get for example:
> gen_pass(35, 2)
[1] "0OD}1O}8DKMqTL[JEFZBwKMJWGD’VZ=VRnD"
It's interesting; because we only have to remember the parameters passed to the function. here, in this case: 35 2.
Thank you Mr Fmerhout.
To conclude : with this little script we have a good way to create very strong and very safe passwords with good entropy without having to use a dictionary and without having to record in any place our passwords .
I have a function, where one part reads as follows:
conefor.input <- function(conefor.file, onlyoverall, probmin, index)
{
for(i in 1:l00)
{
cat(paste(conefor.file,
if(onlyoverall=="TRUE")
{onlyoverall<-"onlyoverall"},
distance,
if(probmin=="TRUE")
{probmin<-paste("-pcHeur", min)},
index, sep="\t"),file="conef_command.txt", sep="\n")}
return("conef_command.txt")
}
My objective is to generate 100 lines where each input is divided by a tab.
There is no problem when the two 'if' statements above are true. With the resulting being:
conefor.file\tonlyoverall\tdistance\tpcHeur min\tindex
However, when the two 'if' statements above are false, I am left with two tabs where 'onlyoverall' and 'pcHeur' would have been, whereas, what I really want is no action at all, and only one tab separating each argument.
Example when 'if' statements are false:
conefor.file\t\tdistance\t\tindex
What I want when 'if' statements are false:
conefor.file\tdistance\tindex
Many thanks in advance
it's hard to suggest any form of vectorization or similar for your for loop, since it's not clear (to me at least)
what differences there are between iterations.
However, as for the paste statement inside of cat, you can use the following instead
paste(ifelse(onlyoverall,
paste(conefor.file, onlyoverall<-"onlyoverall", sep="\t"),
conefor.file),
ifelse(probmin,
paste(distance, probmin<-paste("-pcHeur", min), sep="\t"),
distance),
index,
sep="\t")
Notice, this grabs the output prior to the if statement and includes in an ifelse output, where it is given for both TRUE and FALSE
eg:
x1 <- x2 <- TRUE
paste(ifelse(x1, paste("A", "B" , sep="#"), "A"), ifelse(x2, paste("C", "D", sep="#"), "C"), "E", sep="#")
# [1] "A#B#C#D#E"
x1 <- x2 <- FALSE
paste(ifelse(x1, paste("A", "B" , sep="#"), "A"), ifelse(x2, paste("C", "D", sep="#"), "C"), "E", sep="#")
# [1] "A#C#E"
x2 <- TRUE
paste(ifelse(x1, paste("A", "B" , sep="#"), "A"), ifelse(x2, paste("C", "D", sep="#"), "C"), "E", sep="#")
# [1] "A#C#D#E"