Exclude Node in semPaths {semPlot} - r

I'm trying to plot a sem-path with R.
Im using an OUT file provinent from Mplus with semPaths {semPLot}.
Apparently it seems to work, but i want to remove some latent variables and i don't know how.
I am using the following syntax :
Out from Mplus : https://www.dropbox.com/s/vo3oa5fqp7wydlg/questedMOD2.out?dl=0
outfile1 <- "questedMOD.out"
```
semPaths(outfile1,what="est", intercepts=FALSE, rotation=4, edge.color="black", sizeMan=5, esize=TRUE, structural="TRUE", layout="tree2", nCharNodes=0, intStyle="multi" )

There may be an easier way to do this (and ignoring if it is sensible to do it) - one way you can do this is by removing nodes from the object prior to plotting.
Using the Mplus example from your question Rotate Edges in semPaths/qgraph
library(qgraph)
library(semPlot)
library(MplusAutomation)
# This downloads an output file from Mplus examples
download.file("http://www.statmodel.com/usersguide/chap5/ex5.8.out",
outfile <- tempfile(fileext = ".out"))
# Unadjusted plot
s <- semPaths(outfile, intercepts = FALSE)
In the above call to semPaths, outfile is of class character, so the line (near the start of code for semPaths)
if (!"semPlotModel" %in% class(object))
object <- do.call(semPlotModel, c(list(object), modelOpts))
returns the object from semPlot:::semPlotModel.mplus.model(outfile). This is of class "semPlotModel".
So the idea is to create this object first, amend it and then pass this object to semPaths.
# Call semPlotModel on your Mplus file
obj <- semPlot:::semPlotModel.mplus.model(outfile)
# obj <- do.call(semPlotModel, list(outfile)) # this is more general / not just for Mplus
# Remove one factor (F1) from object#Pars - need to check lhs and rhs columns
idx <- apply(obj#Pars[c("lhs", "rhs")], 1, function(i) any(grepl("F1", i)))
obj#Pars <- obj#Pars[!idx, ]
class(obj)
obj is now of class "semPlotModel" and can be passed directly to semPaths
s <- semPaths(obj, intercepts = FALSE)
You can use str(s) to see the structure of this returned object.

Assuming that you use the following sempath code to print your SEM
semPaths(obj, intercepts = FALSE)%>%
plot()
you can use the following function to remove any node by its label:
remove_nodes_and_edges <- function(semPaths_obj,node_tbrm_vec){
relevent_nodes_index <- semPaths_obj$graphAttributes$Nodes$names %in% node_tbrm_vec
semPaths_obj$graphAttributes$Nodes$width[relevent_nodes_index]=0
semPaths_obj$graphAttributes$Nodes$height[relevent_nodes_index]=0
semPaths_obj$graphAttributes$Nodes$labels[relevent_nodes_index]=""
return(semPaths_obj)
}
and use this function in the plotting pipe in the following way
semPaths(obj, intercepts = FALSE) %>%
remove_nodes_and_edges(c("Y1","Y2","Y3")) %>%
plot()

Related

Change title: mcmc_trace function with ggplot

I used mcmc_trace function from the bayesplot package to plot traceplot with mcmc list, which is a ggplot item so it can be further edited by ggplot function.
Follows is the plot that produced by the function. I needed to change the title k1...k[20] to subject 1... subject 20. Are there any approaches I can achieve this with ggplot function?
Follows is a simple reproducible model.
library (r2jags)
library (bayesplot)
library (ggplot2)
# data
dlist <- list(
NSubjects = 20,
k = rep (5,20),
n = rep (10,20)
)
# monitor
parameter <- 'theta'
# model
minimodel <- function(){
for (i in 1:NSubjects){
theta [i] ~ dbeta (1,1)
k[i] ~ dbin(theta[i],n[i])
}
}
samples <- jags(dlist, inits=NULL, parameter,
model.file = minimodel,
n.chains=1, n.iter=10, n.burnin=1, n.thin=1, DIC=T)
# mcmc list
codaSamples = as.mcmc.list(samples$BUGSoutput)
# select subjects
colstheta <- sprintf("theta[%d]",1:20)
# plot (here is where I need to change title, in this example: theta[1]...theta[20] to subject [1].. subject [20]
mcmc_trace(codaSamples[,colstheta]) +
labs (x='Iteration',y='theta value',
title='Traceplot - theta')
Use colnames<- to modify the column names. Since the object is a 1-element list containing a matrix-like object, you need to use [[1]]; if you have multiple chains you'll need to lapply() (or use a for loop) to apply the solution to every chain (i.e., every element in the list).
cc <- codaSamples[,colstheta]
colnames(cc[[1]]) <- gsub("theta\\[([0-9]+)\\]","subject \\1",colnames(cc[[1]]))
mcmc_trace(cc, ...)
The code above finds the numerical element in each name and inserts it into the new name; since you happen to know in this case that these are elements 1:20, you could simplify considerably, e.g.
colnames(cc[[1]]) <- paste("subject",seq(ncol(cc[[1]])))

R - Defining a function which recognises arguments not as objects, but as being part of the call

I'm trying to define a function which returns a graphical object in R. The idea is that I can then call this function with different arguments multiple times using an for loop or lapply function, then plotting the list of grobs in gridExtra::grid.arrange. However, I did not get that far yet. I'm having trouble with r recognising the arguments as being part of the call. I've made some code to show you my problem. I have tried quoting and unquoting the arguments, using unqoute() in the function ("Object not found" error within a user defined function, eval() function?), using eval(parse()) (R - how to filter data with a list of arguments to produce multiple data frames and graphs), using !!, etc. However, I can't seem to get it to work. Does anyone know how I should handle this?
library(survminer)
library(survival)
data_km <- data.frame(Duration1 = c(1,2,3,4,5,6,7,8,9,10),
Event1 = c(1,1,0,1,1,0,1,1,1,1),
Duration2 = c(1,1,2,2,3,3,4,4,5,5),
Event2 = c(1,0,1,0,1,1,1,0,1,1),
Duration3 = c(11,12,13,14,15,16,17,18,19,20),
Event3 = c(1,1,0,1,1,0,1,1,0,1),
Area = c(1,1,1,1,1,2,2,2,2,2))
# this is working perfectly
ggsurvplot(survfit(Surv(Duration1, Event1) ~ Area, data = data_km))
ggsurvplot(survfit(Surv(Duration2, Event2) ~ Area, data = data_km))
ggsurvplot(survfit(Surv(Duration3, Event3) ~ Area, data = data_km))
myfun <- function(TimeVar, EventVar){
ggsurvplot(survfit(Surv(eval(parse(text = TimeVar), eval(parse(text = EventVar)) ~ Area, data = data_km))
}
x <- myfun("Duration1", "Event1")
plot(x)
You need to study some tutorials about computing on the language. I like doing it with base R, e.g., using bquote.
myfun <- function(TimeVar, EventVar){
TimeVar <- as.name(TimeVar)
EventVar <- as.name(EventVar)
fit <- eval(bquote(survfit(Surv(.(TimeVar), .(EventVar)) ~ Area, data = data_km)))
ggsurvplot(fit)
}
x <- myfun("Duration1", "Event1")
print(x)
#works

Using foreach() in R to speed up loop for ggplot2

I would like to create a PDF file containing hundreds of plots in a certain order.
My strategy was using foreach() and storing each ggplot2 object into the output list, and then printing each ggplot2 object to the output file.
For example, I would like to plot a histogram of prices for every factor "carat" in the diamonds dataset:
library(ggplot2)
library(plyr)
library(foreach) # for parallelization
library(doParallel) # for parallelization
#setup parallel backend to use 4 processors
cl<-makeCluster(4)
registerDoParallel(cl)
# use diamonds dataset
carats.summary <- ddply(diamonds, .(carat), summarise, count = length(carat))
m.list <- foreach(i = 1:length(carats.summary$carat),
.packages = "ggplot2") %dopar% {
jcarat = carats.summary$carat[i]
m <- ggplot(subset(diamonds, carat == jcarat), aes(x = price)) +
geom_histogram()
print(m)
}
With this code, I am hoping to create a list of ggplot2 objects which I can then save into a single pdf file (for example using pdf()) in an ordered manner (for example, in ascending carats).
However, running this results in an error message:
Error in serialize(data, node$con) : error writing to connection
I suspect this is due to the fact that if I tried to append the ggplot2 object to a list, I would get a warning message like this:
lst <- vector(mode = "list")
lst[1] <- m
Warning message:
In lst[1] <- m :
number of items to replace is not a multiple of replacement length
Although this is pure speculation and I could be wrong.
Does anybody have an idea how to use foreach() to save ggplot2 objects onto a list? Or some way to parallelize for loops involving ggplot2?
Thanks in advance.
You shouldn't be printing the object inside the loop, just create the ggplot object. Only print when you have the graphic device open that you want.
m.list <- foreach(i = 1:length(carats.summary$carat),
.packages = "ggplot2") %dopar% {
jcarat = carats.summary$carat[i]
ggplot(subset(diamonds, carat == jcarat), aes(x = price)) +
geom_histogram()
}
then you can get at them with
m.list[[1]]
etc...

How can I suppress the creation of a plot while calling a function in R?

I am using a function in R (specifically limma::plotMDS) that produces a plot and also returns a useful value. I want to get the returned value without producing the plot. Is there an easy way to call the function but suppress the plot that it creates?
You can wrap the function call like this :
plotMDS.invisible <- function(...){
ff <- tempfile()
png(filename=ff)
res <- plotMDS(...)
dev.off()
unlink(ff)
res
}
An example of call :
x <- matrix(rnorm(1000*6,sd=0.5),1000,6)
rownames(x) <- paste("Gene",1:1000)
x[1:50,4:6] <- x[1:50,4:6] + 2
# without labels, indexes of samples are plotted.
mds <- plotMDS.invisible(x, col=c(rep("black",3), rep("red",3)) )

Multiple plots with high-level plotting functions, especially plot.rqs()

I am trying to plot two regression summaries side-by-side with one centered title. Each regression summary is generated by plot.rqs() and amounts to a set of 9 plots.
I've tried using par(mfrow=c(1,2)) already, but as I learnt from Paul Murrel's (2006) book, high-level functions like plot.rqs() or pairs() save the graphics state before drawing and then restore the graphics state once completed, so that pre-emptive calls to par() or layout() can't help me. plot.rqs() doesn't have a 'panel' function either.
It seems that the only way to achieve the result is to modify the plot.rqs() function to get a new function, say modified.plot.rqs(), and then run
par(mfrow=c(1,2))
modified.plot.rqs(summary(fit1))
modified.plot.rqs(summary(fit2))
par(mfrow=c(1,1))
From there I might be able to work out how to add an overall title to the image using layout(). Does anyone know how to create a modified.plot.rqs() function that could be used in this way?
Thanks
You can patch a function as follows:
use dput and capture.output to retrieve
the code of the function, as a string;
change it as you want (here, I just replace each occurrence of par
with a function that does nothing);
finally evaluate the result to produce a new function.
library(quantreg)
a <- capture.output(dput(plot.summary.rqs))
b <- gsub("^\\s*par\\(", "nop(", a)
nop <- function(...) {}
my.plot.summary.rqs <- eval(parse(text=b))
First we generate an example object, fm . Then we copy plot.rqs and use trace on the copy to insert par <- list at top effectively nullifying any use of par within the function. Then we do the same with plot.summary.rqs. Finally we test it out with our own par:
library(quantreg)
example(plot.rqs) # fm to use in example
# plot.rqs
plot.rqs <- quantreg::plot.rqs
trace("plot.rqs", quote(par <- list), print = FALSE)
# plot.summary.rqs
plot.summary.rqs <- quantreg::plot.summary.rqs
trace("plot.summary.rqs", quote(par <- list), print = FALSE)
# test it out
op <- par(mfrow = c(2, 2))
plot(summary(fm))
plot(fm)
title("My Plots", outer = TRUE, line = -1)
par(op)
EDIT: added plot.summary.rqs.

Resources