# Share your functions & code

#### Dason

##### Ambassador to the humans
Maybe define it as a method for lm objects?

Code:
segments.lm <- function(coef, xlim, ...) {
a <- coef[1]
b <- coef[2]
x0 <- xlim[1]
x1 <- xlim[2]
y0 <- a + b*x0
y1 <- a + b*x1
segments(x0 = x0, y0 = y0, x1 = x1, y1 = y1, ...)
}
You would probably want to do this then?
Code:
segments.lm <- function(lm, xlim, ...) {
a <- coef(lm)[1]
b <- coef(lm)[2]
x0 <- xlim[1]
x1 <- xlim[2]
y0 <- a + b*x0
y1 <- a + b*x1
segments(x0 = x0, y0 = y0, x1 = x1, y1 = y1, ...)
}
The way yours works you need coef to be an lm object but if that's true then you can't just subset like you're doing. But using ... is probably the better idea.

#### Lazar

##### Phineas Packard
EDIT: Clean code thanks to Dason.

Ok so in preparing my script to post on CFA by hand I got distracted and developed a SEM data simulation function inspired by this. I think my one is better because it is much more flexible in that in can generate data to 1 to N latent factors and does not require you to type out a whole bunch of zeros. Also my error approximations are probably better. I would be greatful if people who do SEM could try it out and others feel free to comment on how to improve the code:

Code:
SEMsim<- function(N.Obs, fa, load, l.pattern, fcov = 1){
## N.Obs    : is the number of observations wanted for simulation
## fa       : number of factors
## load     : vector of factor loadings
## l.pattern: pattern indicating how the factor loadings load
## onto     : the simulated factors
## fcov     : factor covariances (variances set to 1)
##            entered in column major order

## Needed for simulating multivariate normal data
require(MASS)
## Needed for forceSymmetric. upper.tri is unstable
require(Matrix)
## Number of items to be simulated
it <- length(load)

l <- matrix(0, it, fa)

## Create a loading matrix. Cross loadings constrained to zero.
for (i in 1:fa){
l[l.pattern[[i]], i] <- load[l.pattern[[i]]]
}

psi <- matrix(1, fa, fa)
## Use expand grid to get needed covariances
ref <- expand.grid(1:fa, 1:fa)
## Picks refernce to be filled in lower tri
ref <- ref[ref[,1] > ref[,2], 1:2]

for (i in 1:nrow(ref)){
## Is filled in column major order
psi[ref[i,1], ref[i,2]] <- fcov[i]
}

## More effective than upper.tri function
psi <- forceSymmetric(psi, 'L')
## Gives decent approximation of item residuals
e <- 1 - diag(l %*% t(l))^2
## Simulates population covariance matrix
sigma <- l %*% psi %*% t(l) + diag(e)
## Simulates random data based on population covariance matrix.
## Variances set to 1. Means set to zero.
simData<- as.data.frame(mvrnorm(N.Obs, rep(0,it), sigma))
colnames(simData)<- paste('Var', 1:it, sep='')

out <- list(items = it,
sigma = sigma,
loadingMatrix = l,
latentCovar = psi,
resMatrix = e,
data = simData)

return(out)
}
So far I have tried the following examples which all work well in MPlus:
Code:
#Demonstrations for 5 to 1 factor.
simData5<-SEMsim(N.Obs=1000, fa=5,
load=c(.8,.7,.6,.7,.6,.5,.7,.8,.6,.76,.82,.72,.66,.68,.92, .87),
l.pattern=list(1:3, 4:6, 7:9, 10:12, 13:16),
fcov=c(.25, .5, .11, .3, .22, .05, .45, .54, .32, .23))
simData4<-SEMsim(N.Obs=1000, fa=4,
load=c(.8,.7,.6,.7,.6,.5,.7,.8,.6,.76,.82,.72),
l.pattern=list(1:3, 4:6, 7:9, 10:12), fcov=c(.25, .5, .11, .3, .22, .05))
simData3<-SEMsim(N.Obs=1000, fa=3,
load=c(.8,.7,.6,.7,.6,.5,.7,.8,.6),
l.pattern=list(1:3, 4:6, 7:9), fcov=c(.25, .5, .11))
simData2<-SEMsim(N.Obs=1000, fa=2,
load=c(.8,.7,.6,.7,.6,.5),
l.pattern=list(1:3, 4:6), fcov=c(.25))
simData1<-SEMsim(N.Obs=1000, fa=1,
load=c(.8,.7,.6),
l.pattern=list(1:3))

#### Dason

##### Ambassador to the humans
I cleaned up your code a little bit. I hope you don't mind!

Code:
SEMsim<- function(N.Obs, fa, load, l.pattern, fcov = 1){
## N.Obs    : is the number of observations wanted for simulation
## fa       : number of factors
## load     : vector of factor loadings
## l.pattern: pattern indicating how the factor loadings load
## onto     : the simulated factors
## fcov     : factor covariances (variances set to 1)
##            entered in column major order

## Needed for simulating multivariate normal data
require(MASS)
## Needed for forceSymmetric. upper.tri is unstable
require(Matrix)
## Number of items to be simulated
it <- length(load)

l <- matrix(0, it, fa)

## Create a loading matrix. Cross loadings constrained to zero.
for (i in 1:fa){
l[l.pattern[[i]], i] <- load[l.pattern[[i]]]
}

psi <- matrix(1, fa, fa)
## Use expand grid to get needed covariances
ref <- expand.grid(1:fa, 1:fa)
## Picks refernce to be filled in lower tri
ref <- ref[ref[,1] > ref[,2], 1:2]

for (i in 1:nrow(ref)){
## Is filled in column major order
psi[ref[i,1], ref[i,2]] <- fcov[i]
}

## More effective than upper.tri function
psi <- forceSymmetric(psi, 'L')
## Gives decent approximation of item residuals
e <- 1 - diag(l %*% t(l))^2
## Simulates population covariance matrix
sigma <- l %*% psi %*% t(l) + diag(e)
## Simulates random data based on population covariance matrix.
## Variances set to 1. Means set to zero.
simData<- as.data.frame(mvrnorm(N.Obs, rep(0,it), sigma))
colnames(simData)<- paste('Var', 1:it, sep='')

out <- list(items = it,
sigma = sigma,
loadingMatrix = l,
latentCovar = psi,
resMatrix = e,
data = simData)

return(out)
}

#### Lazar

##### Phineas Packard
Hope I have this code cleaner (feel free to point out where it is not as I am still learning).

Below is a code that follows on from the SEMsimulation code above. This one mimics the pattern missing approach that is used in mplus simulations.

Code:
MISSpattern<- function(pattern, probs=1, simulation){
#simulation     :is an SEMsimulation object
#Pattern        :is a list  with as many elements as the length of probs
#                Each element of the list contains a vector the length of the
#                the number of items in the data frame. This vector represents
#                the proportion of missing data to simulate per item.
#probs          :is a vector. Each element indicates the proportion of the same to
#                apply the missing data patterns to. The probs must sum to 1.

#Takes data out of the SEMsimulation object.
sim<- simulation$data #Takes number of items from the SEMsimulation object. item<- simulation$it

#Function taken from stack overflow
check.integer <- function(N){
!length(grep("[^[:digit:]]", as.character(N)))
}

#Admissability Checks
if(sum(probs)!=1)
stop('FATAL ERROR: probs must sum to one')

if(any(sapply(probs, function(x)(check.integer(nrow(sim)*x)))==FALSE) )
stop('FATAL ERROR: when sample is multipled by probs, result must be integer')

if(sum(sapply(pattern, length))!=item*length(probs))
stop('FATAL ERROR: number of pattern entries must equal items x number of probs groups')

#The following function randomly assigns cases to probs group
probsList<- list()

for (i in 1:length(probs)){
probsList[[i]]<- rep(i, nrow(sim)*probs[i])
}
#Provide a new variable in data frame used to split data to apply missing
#data patterns
probsList<-do.call(c, probsList)
probsList<-sample(probsList, length(probsList))
sim$spl<- probsList #Split data so that the patterns can be applied. data<- split(sim,sim$spl)

#Applies missing data patterns to porpotions of sample
#as set in probs command
f1<-function(x,n){
for (i in 1:item){
if(pattern[[n]][i] == 0){x[,i]<- x[,i]
}else{
x[sample(nrow(x), floor(nrow(x)*pattern[[n]][i])),i]<-NA
}
}
return(x)
}

for (j in 1:length(data)){
data[[j]]<-f1(data[[j]], j)
}

#Pulls the seperate patterns back into single data frame
sim<- do.call(rbind, data)
sim<- sim[,1:item]
rownames(sim)<- seq(1:nrow(sim))
return(sim)
}
Examples:
Code:
#SEMsimulation results used for the examples
simData2<-SEMsim(N.Obs=1000, fa=2,
load=c(.8,.7,.6,.7,.6,.5),
l.pattern=list(1:3, 4:6), fcov=c(.25))

#single pattern of missing values applied to whole sample
sim<-MISSpattern(probs=1,
pattern=list(c(.2, .2, .2, .2, .4, 0)),
simulation=simData2)

#multiple samples applied to different proportions of the simulated sample
sim<-MISSpattern(probs=c(.2, .2, .2, .4),
pattern=list(rep(.2, 6), rep(.3, 6), rep(.1, 6), rep(0, 6)),
simulation=simData2)

#### Lazar

##### Phineas Packard
Ok bringing the two functions above together. The following simulates N latent variable data sets or covariance matrices.

Code:
SEMulation<- function(SIMS=10, COVAR=FALSE, MISSING=FALSE, MISSlist=list(NULL),
N.Obs, fa, load, l.pattern, fcov = 1){
#SIMS        :The number of simulated data sets or covariance matrices.
#COVAR       :If true returns covariance matrices rather than data sets.
#MISSING     :If true takes the list augments from MISSlist and runs MISSpattern
#             MISSING=TRUE is not compatable with COVAR=TRUE.
#             For augments in MISSlist see MISSpattern
#MISSlist    :Needs probs and pattern. See MISSpattern.
#For N.obs to fcov see SEMsim documentation.

#If both MISSING and COVAR are true returns an error.
if(MISSING & COVAR)
stop("Missing simulation is not compatable with Type equals covariance")

#If COVAR=TRUE runs SEMsim for N sims and returns a list of simulated covariance
#matrices. Else data sets are returned.
if(COVAR){
SEMS<- list()
for (i in 1:N){
SEMS[[i]] <- SEMsim(N.Obs, fa,load,
l.pattern, fcov)
SEMS[[i]] <- cov(SEMS[[i]]$data) } }else{ SEMS<- list() for (i in 1:SIMS){ SEMS[[i]] <- SEMsim(N.Obs, fa,load, l.pattern, fcov) #If missing is true MISSpattern is run on all N sims. Else #data sets with no missing data are returned. if (MISSING){ SEMS[[i]] <- MISSpattern(MISSlist$pattern, MISSlist$probs, SEMS[[i]]) }else SEMS[[i]] <- SEMS[[i]]$data

}
}
return(SEMS)
}
Example:
Code:
simData2<-SEMulation(SIMS=10, COVAR=FALSE, N.Obs=1000, fa=2,
load=c(.8,.7,.6,.7,.6,.5),
l.pattern=list(1:3, 4:6), fcov=c(.25),
MISSING=TRUE,
MISSlist=list(probs=1,
pattern=list(c(.2, .2, .2, .2, .4, 0))))
Check that the long run average coverges to specified value, I used lavaan and checked that the .25 covariance between the simulated latent factors occurs:

Code:
require(lavaan)

model1 <- ' p1  =~ Var1 + Var2 + Var3
p2 =~ Var4 + Var5 + Var6
p1~~1*p1
p2~~1*p2'

cfaFit<- function(x){fit<-cfa(model1, data=x)
return(fit@Model@GLIST$psi)} test<-sapply(simData2,cfaFit) rowMeans(test)[2] Exampls 2 with 5 factors and 100 sims (note lavaan takes a while to run): Code: #Simulate 100 datasets with missing value. simData5<-SEMulation(SIMS=100,N.Obs=100, fa=5, load=c(.8,.7,.6,.7,.6,.5,.7,.8,.6,.76,.82,.72,.66,.68,.92, .87), l.pattern=list(1:3, 4:6, 7:9, 10:12, 13:16), fcov=c(.25, .5, .11, .3, .22, .05, .45, .54, .32, .23), MISSING=TRUE, MISSlist=list(probs=c(.2, .2, .6), pattern=list(rep(.2, 16), rep(0, 16), rep(.1, 16))) ) #Run lavaan and check latent factor covariances require(lavaan) model1 <- ' p1 =~ Var1 + Var2 + Var3 p2 =~ Var4 + Var5 + Var6 p3 =~ Var7 + Var8 + Var9 p4 =~ Var10 + Var11 + Var12 p5 =~ Var13 + Var14 + Var15 p1~~1*p1 p2~~1*p2 p3~~1*p3 p4~~1*p4 p5~~1*p5' cfaFit<- function(x){fit<-cfa(model1, data=x) return(fit@Model@GLIST$psi)}

test<-sapply(simData5,cfaFit)

rowMeans(test)
Note that the missing data pattern is less extreme in this example so results are closer to the population model.

#### Lazar

##### Phineas Packard
Did some optimization and speed up the code by a factor of 4 using lapply and only generating the population covariance matrix once rather that repeatedly for every simulation.
Code:
#rewrite so that only mvrnorm goes into the for loop.

SEMulation2<- function(SIMS=10, COVAR=FALSE, MISSING=FALSE, MISSlist=list(NULL),
N.Obs, fa, load, l.pattern, fcov = 1){
#SIMS        :The number of simulated data sets or covariance matrices.
#COVAR       :If true returns covariance matrices rather than data sets.
#MISSING     :If true takes the list augments from MISSlist and runs MISSpattern
#             MISSING=TRUE is not compatable with COVAR=TRUE.
#             For augments in MISSlist see MISSpattern
#MISSlist    :Needs probs and pattern. See MISSpattern.
#For N.obs to fcov see SEMsim documentation.
## N.Obs    : is the number of observations wanted for simulation
## fa       : number of factors
## load     : vector of factor loadings
## l.pattern: pattern indicating how the factor loadings load
## onto     : the simulated factors
## fcov     : factor covariances (variances set to 1)
##            entered in column major order
#If both MISSING and COVAR are true returns an error.
if(MISSING & COVAR)
stop("Missing simulation is not compatable with Type equals covariance")

## Needed for simulating multivariate normal data
require(MASS)
## Needed for forceSymmetric. upper.tri is unstable
require(Matrix)
## Number of items to be simulated
it <- length(load)
l <- matrix(0, it, fa)
## Create a loading matrix. Cross loadings constrained to zero.
for (i in 1:fa){
l[l.pattern[[i]], i] <- load[l.pattern[[i]]]
}

psi <- matrix(1, fa, fa)
## Use expand grid to get needed covariances
ref <- expand.grid(1:fa, 1:fa)
## Picks refernce to be filled in lower tri
ref <- ref[ref[,1] > ref[,2], 1:2]

for (i in 1:nrow(ref)){
## Is filled in column major order
psi[ref[i,1], ref[i,2]] <- fcov[i]
}

## More effective than upper.tri function
psi <- forceSymmetric(psi, 'L')
## Gives decent approximation of item residuals
e <- 1 - diag(l %*% t(l))^2
## Simulates population covariance matrix
sigma <- l %*% psi %*% t(l) + diag(e)
#If COVAR=TRUE runs SEMsim for N sims and returns a list of simulated covariance
#matrices. Else data sets are returned.
SEMS<- list()
for (i in 1:SIMS){
SEMS[[i]]<- as.data.frame(mvrnorm(N.Obs, rep(0,it), sigma))
}
lapply(SEMS, function(x) colnames(x)<- paste('Var', 1:it, sep='') )

if(COVAR){
lapply(SEMS, function(x) cov(x))
}else{
#If missing is true MISSpattern is run on all N sims. Else
#data sets with no missing data are returned.
if (MISSING){
lapply(SEMS, function(x) MISSpattern2(MISSlist$pattern, MISSlist$probs, MISSlist$item, x) ) }else SEMS <- SEMS } return(SEMS) } This required a slight change in the MISSpattern code: Code: MISSpattern2<- function(pattern, probs=1, item, simulation){ #simulation :is an SEMsimulation object #Pattern :is a list with as many elements as the length of probs # Each element of the list contains a vector the length of the # the number of items in the data frame. This vector represents # the proportion of missing data to simulate per item. #probs :is a vector. Each element indicates the proportion of the same to # apply the missing data patterns to. The probs must sum to 1. #Takes data out of the SEMsimulation object. sim<- simulation #Function taken from stack overflow check.integer <- function(N){ !length(grep("[^[:digit:]]", as.character(N))) } #Admissability Checks if(sum(probs)!=1) stop('FATAL ERROR: probs must sum to one') if(any(sapply(probs, function(x)(check.integer(nrow(sim)*x)))==FALSE) ) stop('FATAL ERROR: when sample is multipled by probs, result must be integer') if(sum(sapply(pattern, length))!=item*length(probs)) stop('FATAL ERROR: number of pattern entries must equal items x number of probs groups') #The following function randomly assigns cases to probs group probsList<- list() for (i in 1:length(probs)){ probsList[[i]]<- rep(i, nrow(sim)*probs[i]) } #Provide a new variable in data frame used to split data to apply missing #data patterns probsList<-do.call(c, probsList) probsList<-sample(probsList, length(probsList)) sim$spl<- probsList

#Split data so that the patterns can be applied.
data<- split(sim,sim$spl) #Applies missing data patterns to porpotions of sample #as set in probs command f1<-function(x,n){ for (i in 1:item){ if(pattern[[n]][i] == 0){x[,i]<- x[,i] }else{ x[sample(nrow(x), floor(nrow(x)*pattern[[n]][i])),i]<-NA } } return(x) } for (j in 1:length(data)){ data[[j]]<-f1(data[[j]], j) } #Pulls the seperate patterns back into single data frame sim<- do.call(rbind, data) sim<- sim[,1:item] rownames(sim)<- seq(1:nrow(sim)) return(sim) } MISSpattern function is now the major bottleneck in terms of speed. Last edited by a moderator: #### bryangoodrich ##### Probably A Mammal Since I don't understand any of this, I'm just going to assume Lazar is showing off #### Lazar ##### Phineas Packard I appear to be showing off my bad coding form. Thanks to dason for nesting the CODE tags inside the SPOILER tags above. It never occured to me that you could do that. Now to learn C so I can get rid of the bottleneck in MISSpattern. #### trinker ##### ggplot2orBust A few simple utilities functions These are nothing spectacular but may save time if you store them in your .Rprofile. I know some are opposed to this but if the code is just for you. I actually have mutiple .Rprofiles in different folders depending on if it's a project I'm screwing around on for me/HW/classwork, professional, or coding to share with others. These three functions are in the for me Rprofiles. I'm not going to formally introduce them as they're little crap functions but I especially like the rownamer as I use it pretty frequently. rownamer Takes a dataframe and adds integers as rownames DFduplicate Takes a data frame, repeats it, and stacks it n number of times IDer Adds an ID column at the beginning of a data frame, simply integers IDs Code: rownamer <- function(dataframe){ x <- as.data.frame(dataframe) rownames(x) <- 1:nrow(x) return(x) } rownamer(mtcars) ############################################### DFduplicate <- function(dataframe, repeats=10){ DF <- dataframe[rep(seq_len(nrow(dataframe)), repeats), ] rownamer(DF) } DFduplicate(mtcars) ############################################## IDer <- function(dataframe, id.name="id"){ DF <- data.frame(c=1:nrow(dataframe), dataframe) colnames(DF)[1] <- id.name return(DF) } IDer(mtcars) #### trinker ##### ggplot2orBust Paste2 I see the next version of R will have a paste0 function that is a shortcut to paste(objects, sep=""). Recently I've had the need to make a paste function of my own that takes multiple columns of a data frame and pastes them together. Basically it takes an unknown list of columns and pastes them together. In the past: This works as you know the number of columns to pass to paste. But sometimes inside of a function you don't know how many columns you will pass to paste. Code: paste(mtcars$am, mtcars$cyl, sep=".") These do not work Code: paste(CO2[1:3], sep=".") x <- list(mtcars$am, mtcars$cyl) paste(x, sep=".") The solution (compliments of Dason) is paste2. The function arguments: Code: paste2(multi.columns, sep=".", handle.na=TRUE, trim=TRUE) multiple.columns columns in the form of a list or indexes from a data frame sep come on you'd better know what this is handle.na if there's an NA in the column returns NA, otherwise splices the NA in trim eliminates white spaces The Code Code: paste2 <- function(multi.columns, sep=".", handle.na=TRUE, trim=TRUE){ if (trim) multi.columns <- lapply(multi.columns, function(x) { gsub("^\\s+|\\s+$", "", x)
}
)

if (!is.data.frame(multi.columns) & is.list(multi.columns)) {
multi.columns <- do.call('cbind', multi.columns)
}

m <- if(handle.na){
apply(multi.columns, 1, function(x){if(any(is.na(x))){
NA
} else {
paste(x, collapse = sep)
}
}
)
} else {
apply(multi.columns, 1, paste, collapse = sep)
}
names(m) <- NULL
return(m)
}
Examples
Code:
paste2(CO2[1:3])
paste2(CO2)
paste2(list(mtcars$am, mtcars$cyl))

#### trinker

##### ggplot2orBust
Another dumb one that's just for me. I can never remember what the function name is for the sos package [findFn()] so i made a wrapper for it and Rseek to search for r terms from within R. It's handy to me and I threw it in my .Rprofile. I can remember sos so that's the name of the function. The default method is sos but takes ressek and both as arguments as well.

Code:
sos <- function(x, method='sos'){
require(sos)
switch(method,
sos=findFn(x),
rseek=browseURL(paste("http://www.rseek.org/?cx=010923144343702598753%3Aboaz1reyxd4&newwindow=1&q=",x,"&sa=Search+functions%2C+lists%2C+and+more&cof=FORID%3A11&siteurl=www.rseek.org%2F#933",sep = "")),
both={browseURL(paste("http://www.rseek.org/?cx=010923144343702598753%3Aboaz1reyxd4&newwindow=1&q=",x,"&sa=Search+functions%2C+lists%2C+and+more&cof=FORID%3A11&siteurl=www.rseek.org%2F#933",sep = ""))
findFn(x)
}
)
}
PS: anyone know a good way to split those web addresses up with out having to paste a bunch o pieces together?

#### Dason

##### Ambassador to the humans
One of the cool things about sos is that it adds a triple question mark to do a search as well

The following two lines search the same thing.
Code:
> findFn("linear model")
found 8056 matches;  retrieving 20 pages, 400 matches.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
> ???"linear model"
found 8056 matches;  retrieving 20 pages, 400 matches.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

#### trinker

##### ggplot2orBust
Here is a simple wrapper for strwrap with nicer formatting. It works best using clipboard but you can also supply text to it. I think Wickham has something like this in stringR already.

The code
Code:
strWrap <- function(text = "clipboard", width = 70) {
x <- ifelse(text == "clipboard", paste(readClipboard(), collapse = " "), text)
x <- gsub("\\s+", " ", gsub("\n|\t", " ", x))
x <- strwrap(x, width = width)
writeClipboard(x, format = 1)
writeLines(x)
}
Example
Code:
x <-"5t34xdtfr5  5y6gh56g56hg 6 h456rh5rhrth5h45hrt 56hhh5h  th5t rtrkhvjnevurchf4rthyuiebrtnvr  hjrvt8ujtovet8 tvujreopuicmrtg envrticmogir hurvtouvgnr tncvmoritndtiower rtcvnvperonuvtr"
strWrap(x)
Returns:
Code:
5t34xdtfr5 5y6gh56g56hg 6 h456rh5rhrth5h45hrt 56hhh5h th5t
rtrkhvjnevurchf4rthyuiebrtnvr hjrvt8ujtovet8 tvujreopuicmrtg
envrticmogir hurvtouvgnr tncvmoritndtiower rtcvnvperonuvtr
Just happened to think this works well for windows as it pastes the code to the clipboard. I'd appreciate anyone extending it to a mac and/or linux too as I'm including this in a package and don't have a mac to test it one. Would this work on Linux? (the copying to the clipboard that is)

#### Dason

##### Ambassador to the humans
Doesn't work on my mac. I wouldn't expect it to work on Linux either.

#### bryangoodrich

##### Probably A Mammal
Yeah. That's one sad thing I noticed about the *nix environment. It doesn't have the 'clipboard' reference as a possible connection. You have to explicitly link to something (there's a workaround, but I never got it to work and it was ugly and not worth the trouble).

#### Dason

##### Ambassador to the humans
Yeah. That's one sad thing I noticed about the *nix environment. It doesn't have the 'clipboard' reference as a possible connection. You have to explicitly link to something (there's a workaround, but I never got it to work and it was ugly and not worth the trouble).
Yeah there are ways to do it. But the reason it doesn't work out of the box is that well... somebody might not even have a clipboard program installed. Since there are so many choices too it's hard to just make things work out of the box.

#### bryangoodrich

##### Probably A Mammal
That was one thing I found interesting when I ran into that problem. We Window users take the clipboard for granted, thinking it's just a standard operating system thing, since you always can just CTRL+C some stuff! The problem is that Linux systems are diverse and do often use a variety of utilities to accomplish a given task, including the clipboard. So no generic solution will work out of the box in that regard.

#### trinker

##### ggplot2orBust
Occasionally I can't remember a package name I want to call but remember part of the name or what it starts with. I then have to go search the net for that function which annoys me. So I put this function in my library that gives me a menu interface with the packages in my library. I threw this one in my .Rprofile

Function
Code:
lib(begins.with = NULL, contains = NULL)
Arguments
begins.with searches packages beginning with this string
contains searches packages containing this string

The Code
Code:
lib <- function(begins.with = NULL, contains = NULL){
if (!is.null(begins.with) & !is.null(contains)) {
stop("Can not use both 'begins.with' & 'contains' arguments")
}

y <- sort(.packages(all.available = TRUE))

if (!is.null(begins.with)) {
w <- gsub("(\\w*)","\\U\\1", begins.with, perl=T)
begins.with <- c(begins.with, w)
y <- y[substring(y, 1, nchar(begins.with)) %in% begins.with]
if(length(y)==0) stop("No packages match")
}
if (!is.null(contains)) {
y <- y[grep(contains, y, ignore.case = TRUE)]
if(length(y)==0) stop("No packages match")
}
x <- select.list(y, title = "packages")
library(x, character.only = TRUE)
cat(x, "loaded\n")
}
Examples
Code:
lib()  #gives all packages in your library
lib(contains='plot')   #gives only packages containing the word plot in it
lib('r')  #gives only packages starting with r or R
lib(contains='Dason_Is_Cool')  #throws up an error as Dason is not cool