Difference between paste and print (affecting result of function) - r

To start off, I'm not really sure what the difference between paste and print is. But I am using "print" to spit out generic statements and "paste" to spit out statements that use/ reference specific variables.
My issue is that when using paste within a function, I am losing my pasted output if there is anything included in the function following the "paste" statement.
Please see the following three functions:
TS<-5
Example 1- everything works fine
T<-function(){
if(exists("TS"))
{paste("TS= ", TS, sep=" ")}
else
if(!exists("TS"))
{print.noquote("No TS Values")}
}
Example 2- My Problem. When I add anything (in this case another print command) following my "if" statement I will lose my pasted output
T<-function(){
if(exists("TS"))
{paste("TS= ", TS, sep=" ")}
else
if(!exists("TS"))
{print.noquote("No TS Values")}
print("my exsistance removes paste output")
}
Example 3- The same statement placed before the "if" has no negative effect
T<-function(){
print("my exsistance does not remove paste output")
if(exists("TS"))
{paste("TS= ", TS, sep=" ")}
else
if(!exists("TS"))
{print.noquote("No TS Values")}
}
Can someone explain where the conflict is within this function. And better yet how can I work around it so that I can have a paste statement followed by other actions within a function
basically how can I get example #2 to work.
Brownie points- (for sake of visual consistency) when using "print.noquote", is there such a thing as a paste.noquote?

paste concatenates (pastes) strings and returns a character vector, so you can do thing like
paste('a','b', sep = '-')
## [1] "a-b"
print prints values. From ?print
print prints its argument and returns it invisibly (via invisible(x)). It is a generic function which means that new printing methods can be easily added for new classes.
Most classes will have a defined print method (or will use print.default)
You can see the available print methods by typing
methods('print')
In your case
paste("TS= ", TS, sep=" ") returns a character vector, so when this is the result of the function, print.character is used to display the results
In fact, I think you want message not print or print.noquote.
T <- function() {
if (exists("TS"))
{
message(paste("TS= ", TS, sep=" "))
} else if (!exists("TS")) {
message("No TS Values")
}
message("my exsistance removes paste output")
}

paste returns the input concatenated together. When a function returns it calls print on whatever was returned if it isn't stored into a variable. Functions return the last top level call if there is no explicit 'return' or 'invisible' statement.
All of these things add up to what you end up seeing. If paste is the last function called it ends up returning the input concatenated together - which ends up being returned by the function - which ends up being printed since you don't save it into a variable. If you explicitly want something printed it is best to use print or message or cat - they each serve slightly different purposes.

Related

Is there a way make a parameter of a function be put in quotes in one life of code and not the other?

I'm not showing my actual code because it has many running parts, so let me just showcase what I am running into. I have this function:
paste <- function(d) {
print(paste0(d,"_test", sep =""))
}
What I wanted returned would be if I did paste(advising) for example is "advising_test".
The reason I am not just doing paste("advising") is because in the function I am writing, advising needs to be used as both in quotes in order to name a particular object and needs to be used as the name of a dataframe that I am doing another function on. Therefore, I need to figure out how in the code I can paste the parameter with quotes, so I can use the term both ways.
paste <- function(d) {
print(paste0(ensym(d),"_test", sep =""))
}
Edit : You can have a look at https://rlang.r-lib.org/reference/nse-defuse.html
Use substitute . No packages are used.
mypaste <- function(d) print(paste0(substitute(d), "_test"))
# test
mypaste(advising)
## [1] "advising_test"

Why the code only works with numbers and not letters?

I have to use the code bellow but I don't completely understand how it works. Why it won't work if I change du.4 by du.f and then use the f when calling the function? For some reason it only works with numbers and I do not undarstand why.
This is the error that it is giving in the case of du.f
Error in paste("Meth1=", nr, ".ps", sep = "") : object 'f' not found
du.4 <- function(u,v,a){(exp(a)*(-1+exp(a*v)))/(-exp(a)+exp(a+a*u)-exp(a*(u+v))+exp(a+a*v))}
plotmeth1 <- function(data1,data2,alpha,nr) {
psfile <-paste("Meth1=",nr,".ps",sep="")
diffmethod <-paste("du.",nr,sep="")
title=paste("Family",nr)
alphavalue <-paste("alpha=",round(alpha,digits=3),sep="")
#message=c("no message")
postscript(psfile)
data3<-sort(eval(call(diffmethod,data1,data2,alpha)))
diffdata <-data3[!is.na(data3)]
#if(length(data3)>length(diffdata))
#{message=paste("Family ",nr,"contains NA!")}
tq <-((1:length(diffdata))/(length(diffdata)+1))
plot(diffdata,tq,main=title,xlab="C1[F(x),G(y)]",ylab="U(0,1)",type="l")
legend(0.6,0.3,c(alphavalue))
abline(0,1)
#dev.off()
}
In R, a dot is used as just another character in identifiers. It is often used for clarity but doesn't have a formal function in defining the part after the dot as being in a name-space given by the part of the identifier before the dot. In something like du.f you can't refer to the function by f alone, even if your computation is inside of an environment named du. You can of course define a function named du.4 and then use 4 all by itself, but when you do so you are using the number 4 as just a number and not as a reference to the function. For example, if
du.4 <- function(u,v,a){(exp(a)*(-1+exp(a*v)))/(-exp(a)+exp(a+a*u)-exp(a*(u+v))+exp(a+a*v))}
Then du.4(1,2,3) evaluates to 21.08554 but attempting to use 4(1,2,3) throws the error
Error: attempt to apply non-function
In the case of your code, you are using paste to assemble the function name as a string to be passed to eval. It makes sense to paste the literal number 4 onto the string 'du.' (since the paste will convert 4 to the string '4') but it doesn't make sense to paste an undefined f onto 'du.'. It does, however, make sense to paste the literal string 'f' onto 'du.', so that the function call plotmeth1 (data1, data2, alpha, 'f') will work even though plotmeth1 (data1, data2, alpha, f) will fail.
See this question for more about the use of the dot in R identifiers.

Method to paste whisker template

I am writing a program to generate whisker template in a loop, and I want to paste them together. For every template, my code looks like this:
script[i] <- whisker.render(template_pdf[i], data = parameter)
Is there a method to paste all the script[i] together? I know I can paste all the chunks first and then use function whisker.render just for one time, but that will cause some trouble in my particular case. If I can paste all the script[i] together, that will be convenient for me.
When script is a character vector you can do
paste(script, collapse = "\n")
with \n (newline) the character inserted between the script elements.
When script is a list, you can do
do.call(paste, c(script, sep ="\n"))

R indent output

is it possible to indent output in R?
e.g.
cat("text1\n")
indent.switch(indent=4)
cat("random text\n")
print("another random text")
indent.switch(indent=0)
cat("text2\n")
resulting in
text1
random text
another random text
text2
I searched for this a few months ago, found nothing and am now searching again.
My current idea is to "overwrite" (I forgot the special term) the functions cat and/or print with an additional argument like:
cat("random text", indent=4)
Only I'm stuck with this and I dont like this procedure very much.
Any ideas?
Edit:
I should be more particular, nevertheless thank you for the \t (omg, i totally forgot this -.-) and that I can format it inside cat.
The given solutions work, but only solve my second-choice-path.
A switch as shown in my first codeexample does not exist I suppose?
My problem is that I have parts of a bigger program which have multiple subscripts, and the output of each subscript should be indented. This is absolutely possible with the "\t" or just blanks inside cat() but has to be done in every command, which I dont like very much.
Solution
I used Chris C's code and extended it in a very easy way. (Thank you very much Chris!)
define.catt <- function(ntab = NULL, nspace=NULL){
catt <- function(input = NULL){
if(!is.null(ntab)) cat(paste0(paste(rep("\t", ntab), collapse = ""), input))
if(!is.null(nspace)) cat(paste0(paste(rep(" ", nspace), collapse = ""), input))
if(is.null(ntab) && is.null(nspace)) cat(input)
}
return(catt)
}
The same way you used \n to print a newline, you can use \t to print a tab.
E.g.
cat("Parent level \n \t Child level \n \t \t Double Child \n \t Child \n Parent level")
Evaluates to
Parent level
Child level
Double Child
Child
Parent level
As an alternative, you can create a derivative of cat called catt and alter options depending on the script. For example.
define.catt <- function(ntab = NULL){
catt <- function(input = NULL){
cat(paste0(paste(rep("\t", ntab), collapse = ""), input))
}
return(catt)
}
You would then set catt with however many tabs you wanted by
catt <- define.catt(ntab = 1)
catt("hi")
hi
catt <- define.catt(ntab = 2)
catt("hi")
hi
And just use catt() instead of cat().
You may consider the very versatile function capture.output(...), which evaluates the '...' list of expressions provided as main input arguments, and stores the text output (as if it would be displayed in the console) into a character vector instead. Then, you simply have to modify the strings as desired: here you want to add some leading spaces to each string. Finally, you write the strings to the console.
These can be done all in one line of nested calls. For example:
writeLines(paste(" ", capture.output(print(head(iris))), sep=""))
I therefore recommend you all to read the help of the capture.output function, and then try to use it for various purposes. Indeed, since the main input has the usual flexibility of the '...' list-like structure, you are free to include, for instance, a call to one home-made function, and thus do almost anything. As for indentation, that is simply done with paste function, once the former has done its magic.

Do you always use row.names=F in write.csv? Changing the default values inside R (base) functions

Couldn't see a solution online but I thought this might be quite common.
with write.csv I basically always have the argument row.name set to F. Is it possible to run a line once and update the default value of the argument for the rest of the session?
I tried paste <- paste(sep="") which ran and returned no error but seemed to do nothing (and didn't destroy the paste function). This is another one, I always set sep="" with paste...
like I always have exclude=NULL when I am using table so I can see the N/A values.
EDIT: So, I'm looking for a solution that will work for multiple functions if possible: paste, write.csv, table and other functions like these.
paste <- paste(sep="") puts the output of paste() into an object named "paste". You would need to do something like this instead.
paste <- function (..., sep = "", collapse = NULL) {
base::paste(..., sep=sep, collapse=collapse)
}
You can also look at the Defaults package for this sort of thing, but it doesn't currently work for two of your examples.
Try this:
paste <- paste
formals(paste)$sep <- ""
This creates a new copy of paste in your workspace, and then modifies its default value for sep to "". Subsequent calls to paste will then use the modified copy, as it sits in front of the base environment in your search path.

Resources