3

I have created a shiny app in which a user can load a file and use the object as a function argument. I also print the code to run the function locally (so that I or anyone else could copy and paste to reproduce the result).

What I would like to do is to be able to use something like dput but to save the text representation of the loaded object to an object rather than the console. dput outputs to the console, but simply returns a copy of it's first argument. I can use deparse but it fails when the length of the object exceeds width.cutoff (default 60 and max 500).

The following hacky reproducible example illustrates. In it I use image as the example function. In my case I have other functions with more arguments.

#create example matrices
m2 <- matrix(1:4,2,2)
m4 <- matrix(1:4,4,4)

#this is what I want to recreate
image(z=m2,col=rainbow(4))
image(z=m4,col=rainbow(4))

#convert the matrices to their text representation
txtm2 <- deparse(m2)
txtm4 <- deparse(m4)

#create a list of arguments
lArgs2 <- list( z=txtm2, col=rainbow(4) )
lArgs4 <- list( z=txtm4, col=rainbow(4) )

#construct arguments list
vArgs2 <- paste0(names(lArgs2),"=",lArgs2,", ")
vArgs4 <- paste0(names(lArgs4),"=",lArgs4,", ")

#remove final comma and space
vArgs2[length(vArgs2)] <- substr(vArgs2[length(vArgs2)],0,nchar(vArgs2[length(vArgs2)])-2)
vArgs4[length(vArgs4)] <- substr(vArgs4[length(vArgs4)],0,nchar(vArgs4[length(vArgs4)])-2)

#create the text function call
cat("image(",vArgs2,")")
cat("image(",vArgs4,")")

#the 1st one when pasted works
image( z=structure(1:4, .Dim = c(2L, 2L)),  col=c("#FF0000FF", "#80FF00FF", "#00FFFFFF", "#8000FFFF") )

#the 2nd one gives an error because the object has been split across multiple lines
image( z=c("structure(c(1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, ", "2L, 3L, 4L), .Dim = c(4L, 4L))"),  col=c("#FF0000FF", "#80FF00FF", "#00FFFFFF", "#8000FFFF") )

#In an ideal world I would also like it to work when I did this, but maybe that's asking too much
image(z=txtm2,col=rainbow(4))

I realise that the way I construct the function call is a hack, but when I looked at it a while ago I couldn't find a better way of doing. Open to any suggestions. Thanks.

Andy
  • 1,821
  • 13
  • 23

1 Answers1

8

You can do something like :

## an object that you want to recreate
m2 <- matrix(1:4,2,2)
## use capture.output to save structure as a string in a varible
xx <- capture.output(dput(m2))

## recreate the object 
m2_ <- eval(parse(text=xx))
image(z=m2_,col=rainbow(4))
agstudy
  • 119,832
  • 17
  • 199
  • 261
  • Thanks @agstudy. I was trying to avoid having to use eval(parse(text= because that is something I would need to apply to the first argument but not to others. I did notice that it does cope with the text string being split across multiple elements of a vector. I hadn't come across capture.output, but I see that with dput it splits the string in the same way as deparse. – Andy Oct 09 '14 at 11:28