Change title: mcmc_trace function with ggplot - r

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]])))

Related

How can I apply a piece of R code to every column of my data frame

I have to analyze EMG data, but I'm not very good in using R:
I have a data.frame with 9 columns: one column is specifying the time and the other 8 are specifying my channels.
I want to filter my emg data, but I am only able to do it per channel, but I want to do it for all channels of the dataframe at once, so I don't have to apply it to every single channel.
# This example computes the LE-envelope using the lowpass routine
# Coerce a data.frame into an 'emg' object
x <- as.emg(extensor_raw$channel1, samplingrate = 1000, units = "mV") ##do this for every channel
# Compute the rectified signal
x_rect <- rectification(x)
# Filter the rectified signal
y <- lowpass(x_rect, cutoff = 100)
# change graphical parameters to show multiple plots
op <- par(mfrow = c(3, 1))
# plot the original channel, the filtered channel and the
# LE-envelope
plot(x, channel = 1, main = "Original channel")
plot(x_rect, main = "Rectified channel")
plot(y, main = "LE-envelope")
# reset graphical parameters
par(op)
so instead of using extensor_raw$channel1 here can i put something in like extensor_raw$i and loop around it? Or is there any way to apply this bit of code to every channel (i.e. 8 column of the 9 column data frame excluding the first column which specified the time?)
If it is columnwise, use lapply and store as a list and assuming that all the columns needs to be changed. (Note that this is not tested. The par in plot may have to be changed)
lst1 <- lapply(extensor_raw, \(vec) {
x <- as.emg(vec, samplingrate = 1000, units = "mV")
# Compute the rectified signal
x_rect <- rectification(x)
# Filter the rectified signal
y <- lowpass(x_rect, cutoff = 100)
# change graphical parameters to show multiple plots
op <- par(mfrow = c(3, 1))
# plot the original channel, the filtered channel and the
# LE-envelope
plot(x, channel = 1, main = "Original channel")
plot(x_rect, main = "Rectified channel")
plot(y, main = "LE-envelope")
# reset graphical parameters
par(op)
})
Here my solution. First of all, as there is no data with your question I used the 'EMG data for gestures Data Set' from UCI Machine Learning Repository.
Link https://archive.ics.uci.edu/ml/datasets/EMG+data+for+gestures
It is fairly similar dataset you been using, first variable is time and after that 8 variables are channels, the last one is class
To create a graph for every channel you can use FOR loop by using the column of your concern as your iterating operator. Middle code is same as yours, at last while plotting I did the change in plot title so it resembles with its respective column name.
library(biosignalEMG)
extensor_raw <- read.delim("01/1_raw_data_13-12_22.03.16.txt")
head(extensor_raw)
for(i in names(extensor_raw[2:9])){
print(paste("Drawing for ", i))
# Coerce a data.frame into an 'emg' object
x <- as.emg(extensor_raw[i], samplingrate = 1000, units = "mV") ##do this for every channel
# Compute the rectified signal
x_rect <- rectification(x)
# Filter the rectified signal
y <- lowpass(x_rect, cutoff = 100)
# change graphical parameters to show multiple plots
op <- par(mfrow = c(3, 1))
# plot the original channel, the filtered channel and the
# LE-envelope
plot(x, channel = 1, main = paste("Original ", i))
plot(x_rect, main = paste("Rectified", i))
plot(y, main = paste("LE-envelope", i))
}
At the end of this code you can see multiple pages created in graph section of rstudio, plotting each channel from 1 to 8 simultaneously
like for channel 5 and similarly for others. I hope this should help you to resolve your problem.
On the second part you have asked in comments : If you have the files separate let's keep it separate. will read it one by one and then plot it. To achieve this we will use nested FOR loop.
First set up your working directory, where you have all your gesture files. Like here in my case I have two files in my directory with same structure.
The changes in the code is as follows :
setwd('~/Downloads/EMG_data_for_gestures-master/01')
library(biosignalEMG)
for(j in list.files()){
print(paste("reading file ",j))
extensor_raw <- read.delim(j)
head(extensor_raw)
for(i in names(extensor_raw[2:9])){
print(paste("Drawing for ", i))
# Coerce a data.frame into an 'emg' object
x <- as.emg(extensor_raw[i], samplingrate = 1000, units = "mV") ##do this for every channel
# Compute the rectified signal
x_rect <- rectification(x)
# Filter the rectified signal
y <- lowpass(x_rect, cutoff = 100)
# change graphical parameters to show multiple plots
op <- par(mfrow = c(3, 1))
# plot the original channel, the filtered channel and the LE-envelope
plot(x, channel = 1, main = paste("Original ", i," from ", j))
plot(x_rect, main = paste("Rectified", i," from ", j))
plot(y, main = paste("LE-envelope", i," from ", j))
}
}
I hope this will be helpful.

How to use plot function to plot results of your own function?

I'm writing a short R package which contains a function. The function returns a list of vectors. I would like to use the plot function in order to plot by default a plot done with some of those vectors, add lines and add a new parameter.
As an example, if I use the survival package I can get the following:
library(survival)
data <- survfit(Surv(time, status == 2) ~ 1, data = pbc)
plot(data) # Plots the result of survfit
plot(data, conf.int = "none") # New parameter
In order to try to make a reproducible example:
f <- function(x, y){
b <- x^2
c <- y^2
d <- x+y
return(list(one = b, two = c, three = d))
}
dat <- f(3, 2)
So using plot(dat) I would like to get the same as plot(dat$one, dat$two). I would also like to add one more (new) parameter that could be set to TRUE/FALSE.
Is this possible?
I think you might be looking for classes. You can use the S3 system for this.
For your survival example, data has the class survfit (see class(data)). Then using plot(data) will look for a function called plot.survfit. That is actually a non-exported function in the survival package, at survival:::plot.survfit.
You can easily do the same for your package. For example, have a function that creates an object of class my_class, and then define a plotting method for that class:
f <- function(x, y){
b <- x^2
c <- y^2
d <- x+y
r <- list(one = b, two = c, three = d)
class(r) <- c('list', 'my_class') # this is the important bit.
r
}
plot.my_class <- function(x) {
plot(x$one, x$two)
}
Now your code should work:
dat <- f(3, 2)
plot(dat)
You can put anything in plot.my_class you want, including additional arguments, as long as your first argument is x and is the my_class object.
plot now calls plot.my_class, since dat is of class my_class.
You can also add other methods, e.g. for print.
There are many different plotting functions that can be called with plot for different classes, see methods(plot)
Also see Hadley's Advanced R book chapter on S3.

Unpacking lists programmatically in R

I am prototyping an application in R. I'm using the parallel library and parApply to run a function on columns of a data frame. I understand this will also be applicable to non-parallel/Apply application as well. I have a line similar to:
myBigList <- parApply(myCluster, myInputData, 2, myFunction)
where myFunction is a one that I have written, takes a vector as an input. The function itself performs quite a few operations that I can't go in to. It returns a list of variables of various classes. For the purposes of a MWE, say:
myFunction <- function(vectorIn){
# CODE GOES HERE
return(list(
mean = mean(vectorIn),
sd = mean(vectorIn),
vectorOut = sumUserFunction(vectorIn),
plot1 = aPlotGeneratingFunction(vectorIn),
))
What is returned to me is a list containing the results from the function. I can address elements from the list, eg:
myBigList$Column1$mean
But that isnt really helpful for my purposes. I'd like to know how to unpack the list so that I can look at all the mean values. eg:
listOfMeans <- myBigList$*ALL_ITEMS*$mean
so that listOfMeans is a vector with row.names, or data.frame with col.names.
Is this possible? I can think of a solution using a for loop but that doesnt seem very elegant.
I'd also like to do something similiar with the plots that I return so that I can automatically build a pdf containing all of them. I'm guessing learning the above will help.
tl;dr: What is the best methods of extracting common data names from a list?
EDIT: An actual MWE
library('ggplot2')
exampleData <- data.frame(Col1 = rnorm(100), Col2 = rnorm(100), Col3 = rnorm(100))
myFunction <- function(xIn){
meanX <- mean(xIn)
sdX <- sd(xIn)
vecX <- xIn^2 + xIn
plotX <-
ggplot(data.frame(xIn, vecX), aes(x = xIn, y = vecX)) +
geom_point()
return(list(
mean = meanX,
sd = sdX,
vect = vecX,
plot = plotX
))
}
myBigList <- apply(exampleData,
2,
myFunction)
from #docendo discusimus comment
mymeans <- sapply(myBigList, '[[', 'mean')
returns a vector of all the values stores in mean. To return a list, which is useful for storing the plot class the command should be:
myplots <- lapply(myBigList, '[[', 'plot')

Exclude Node in semPaths {semPlot}

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()

Looping over attributes vector to produce combined graphs

Here is some code that tries to compute the marginal effects of each of the predictors in a model (using the effects package) and then plot the results. To do this, I am looping over the "term.labels" attribute of the glm terms object).
library(DAAG)
library(effects)
formula = pres.abs ~ altitude + distance + NoOfPools + NoOfSites + avrain + meanmin + meanmax
summary(logitFrogs <- glm(formula = formula, data = frogs, family = binomial(link = "logit")))
par(mfrow = c(4, 2))
for (predictorName in attr(logitFrogs$terms, "term.labels")) {
print(predictorName)
effLogitFrogs <- effect(predictorName, logitFrogs)
plot(effLogitFrogs)
}
This produces no picture at all. On the other hand, explicitly stating the predictor names does work:
effLogitFrogs <- effect("distance", logitFrogs)
plot(effLogitFrogs)
What am I doing wrong?
Although you call function plot(), actually it calls function plot.eff() and it is lattice plot and so par() argument is ignored. One solution is to use function allEffects() and then plot(). This will call function plot.efflist(). With this function you do not need for loop because all plots are made automatically.
effLogitFrogs <- allEffects(predictorName, logitFrogs)
plot(effLogitFrogs)
EDIT - solution with for loop
There is "ugly" solution to use with for() loop. For this we need also package grid. First, make as variables number of rows and columns (now it works only with 1 or 2 columns). Then grid.newpage() and pushViewport() set graphical window.
Predictor names are stored in vector outside the loop. Using functions pushViewport() and popViewport() all plots are put in the same graphical window.
library(lattice)
library(grid)
n.col=2
n.row= 4
grid.newpage()
pushViewport(viewport(layout = grid.layout(n.row,n.col)))
predictorName <- attr(logitFrogs$terms, "term.labels")
for (i in 1:length(predictorName)) {
print(predictorName[i])
effLogitFrogs <- effect(predictorName[i], logitFrogs)
pushViewport(viewport(layout.pos.col=ceiling(i/n.row), layout.pos.row=ifelse(i-n.row<=0,i,i-n.row)))
p<-plot(effLogitFrogs)
print(p,newpage=FALSE)
popViewport(1)
}
add print to your loop resolve the problem.
print(plot(effLogitFrogs))
plot call plot.eff , which create the plot without printing it.
allEffects generete an object of type eff.list. When we try to plot this object, its calls plot.efflist function which prints the plot so no need to call print like plot.eff.

Resources