I have a problem with my plotting function. I already asked kind of a similar question and Here are all the data and the plotting function.
When I try to apply my plotting function to my list of dfs, the title gets changed and the title condition I specified in the function is not respected. Is there a way to rename all the plots in the list or fix the function/loop so that the title stays the same?
Thanks in advance
This works as intended:
mynames <- sapply(names(tbls), function(x) {
paste("How do they rank? -",gsub("\\.",": ",x))
})
myfilenames <- names(tbls)
plot_likert <- function(x, myname, myfilename){
p <- plot(likert(x),
type ="bar",center=3,
group.order=names(x))+
labs(x = "Theme", subtitle=paste("Number of observations:",nrow(x)))+
guides(fill=guide_legend("Rank"))+
ggtitle(myname)
p
}
list_plots <- lapply(1:length(tbls),function(i) {
plot_likert(tbls[[i]], mynames[i], myfilenames[i])
})
When in doubt, keep things stupid and simple. Non-standard evaluation like deparse(substitute( will throw you right into Burns' R inferno.
Related
First off fair warning that this is relevant to a quiz question from coursera.org practical machine learning. However, my question does not deal with the actual question asked, but is a tangential question about plotting.
I have a training set of data and I am trying to create a plot for each predictor that includes the outcome on the y axis, the index of the data set on the x axis, and colors the plot by the predictor in order to determine the cause of bias along the index. To make the color argument more clear I am trying to use cut2() from the Hmisc package.
Here is my data:
library(ggplot2)
library(caret)
library(AppliedPredictiveModeling)
library(Hmisc)
data(concrete)
set.seed(1000)
inTrain = createDataPartition(mixtures$CompressiveStrength, p = 3/4)[[1]]
training = mixtures[ inTrain,]
testing = mixtures[-inTrain,]
training$index <- 1:nrow(training)
I tried this and it makes all the plots but they are all the same color.
plotCols <- function(x) {
cols <- names(x)
for (i in 1:length(cols)) {
assign(paste0("cutEx",i), cut2(x[ ,i]))
print(qplot(x$index, x$CompressiveStrength, color=paste0("cutEx",i)))
}
}
plotCols(training)
Then I tried this and it makes all the plots, and this time they are colored but the cut doesn't work.
plotCols <- function(x) {
cols <- names(x)
for (i in 1:length(cols)) {
assign(cols[i], cut2(x[ ,i]))
print(qplot(x$index, x$CompressiveStrength, color=x[ ,cols[i]]))
}
}
plotCols(training)
It seems qplot() doesn't like having paste() in the color argument. Does anyone know another way to loop through the color argument and still keep my cuts? Any help is greatly appreciated!
Your desired output is easier to achieve using ggplot() instead of qplot(), since you can use aes_string(), that accepts strings as arguments.
plotCols <- function(x) {
cols <- names(x)
for (i in 1:length(cols)) {
assign(paste0("cutEx", i), cut2(x[, i]))
p <- ggplot(x) +
aes_string("index", "CompressiveStrength", color = paste0("cutEx", i)) +
geom_point()
print(p)
}
}
plotCols(training)
I have data I'm plotting using ggplot's facet_grid:
My data:
species <- c("spcies1","species2")
conditions <- c("cond1","cond2","cond3")
batches <- 1:6
df <- expand.grid(species=species,condition=conditions,batch=batches)
set.seed(1)
df$y <- rnorm(nrow(df))
df$replicate <- 1
df$col.fill <- paste(df$species,df$condition,df$batch,sep=".")
My plot:
integerBreaks <- function(n = 5, ...)
{
library(scales)
breaker <- pretty_breaks(n, ...)
function(x){
breaks <- breaker(x)
breaks[breaks == floor(breaks)]
}
}
library(ggplot2)
p <- ggplot(df,aes(x=replicate,y=y,color=col.fill))+
geom_point(size=3)+facet_grid(~col.fill,scales="free_x")+
scale_x_continuous(breaks=integerBreaks())+
theme_minimal()+theme(legend.position="none",axis.title=element_text(size=8))
which gives:
Obviously the labels are long and come out pretty messed up in the figure so I was wondering if there's a way edit these labels in the ggplot object (p) or the gtable/gTree/grob/gDesc object (ggplotGrob(p)).
I am aware that one way of getting better labels is to use the labeller function when the ggplot object is created but in my case I'm specifically looking for a way to edit the facet labels after the ggplot object has been created.
As I mentioned in the comments, the facet names are nested quite deeply within the gtable that ggplotGrob() gives you. However, this is still possible and since the OP explicitly wants to edit them after being plotted, you can do this with:
library(grid)
gg <- ggplotGrob(p)
edited_grobs <- mapply(FUN = function(x, y) {
x[["grobs"]][[1]][["children"]][[2]][["children"]][[1]][["label"]] <- y
return(x)
},
gg$grobs[which(grepl("strip-t",gg$layout$name))],
unique(gsub("cond","c", df$condition)),
SIMPLIFY = FALSE)
gg$grobs[which(grepl("strip-t",gg$layout$name))] <- edited_grobs
grid.draw(gg)
Note that this extracts all the strips using gg$grobs[which(grepl("strip-t",gg$layout$name))] and passes them to the mapply to be reset with the gsub(...) that OP specified in their comment.
In general, if you want to access just one of the text labels, there is a very similar structure which I made use of in my mapply:
num_to_access <- 1
gg$grobs[which(grepl("strip-t",gg$layout$name))][[num_to_access]][["grobs"]][[1]][["children"]][[2]][["children"]][[1]]$label
So to access the 4th label for example all you would need to do is change num_to_acces to be 4. Hope this helps!
I am trying to create three different plots in a for loop and then plotting them together in the same graph.
I know that some questions regarding this topic have already been asked. But I do not know what I am doing wrong. Why is my plot being overwritten.
Nevertheless, I tried both solutions (creating a list or using assign function) and I do not know why I get my plot overwriten at the end of the loop.
So, the first solution is to create a list:
library(gridExtra)
library(ggplot2)
out<-list()
for (i in c(1,2,4)){
print(i)
name= paste("WT.1",colnames(WT.1#meta.data[i]), sep=" ")
print(name)
out[[length(out) + 1]] <- qplot(NEW.1#meta.data[i],
geom="density",
main= name)
print(out[[i]])
}
grid.arrange(out[[1]], out[[2]], out[[3]], nrow = 2)
When I print the plot inside the loop, I get what I want...but of course they are not together.
First Plot
When I plot them all together at the end, I get the same plot for all of the three: the last Plot I did.
All together
This is the second option: assign function. I have exactly the same problem.
for ( i in c(1,2,4)) {
assign(paste("WT.1",colnames(WT.1#meta.data[i]),sep="."),
qplot(NEW.1#meta.data[i],geom="density",
main=paste0("WT.1",colnames(WT.1#meta.data[i]))))
}
You're missing to dev.off inside the loop for every iteration. Reproducible code below:
library(gridExtra)
library(ggplot2)
out<-list()
for (i in c(1,2,3)){
print(i)
out[[i]] <- qplot(1:100, rnorm(100), colour = runif(100))
print(out[[i]])
dev.off()
}
grid.arrange(out[[1]], out[[2]], out[[3]], nrow = 2)
I've been dealing with user input for various graphs. My main aim was to ask the user for an input and then parse this to a plotting function. I managed to do this for scatterplot, but not boxplot and barplot. This is my working example:
n<- function(){
readline(prompt="enter x value to plot: ")
}
m<- function(){
readline(prompt="enter y value to plot: ")
}
plotfun <- function(dat) {
colx <- n()
coly <- m()
plot(dat[,colx], dat[,coly], main="Scatterplot", pch=20,xlab=[,colx] )
}
But when I try something similar with boxplot for example:
plot2<-function(infile){
a<-readline(prompt="which variable")
barplot(table(infile$a))
}
or
a<-readline(prompt="enter...")
Boxplot( ~ a, data=infile, id.method="y")
It doesn't work
Errors were something like: can't find the object, argument "infile" is missing, with no default.
What is infile?
plot2 <- function(){
a <- readline(prompt = "which variable")
barplot(table(a))
}
You cannot use "$" with character variable names. You must do the subsetting with [ as you did in the other cases
plot2<-function(infile){
a<-readline(prompt="which variable")
barplot(table(infile[,a]))
}
If your Boxplot function is the one from car, then
a<-readline(prompt="enter...")
Boxplot(infile[,a], labels=rownames(infile), id.method="y")
Is the variable friendly equivalent. You can't use character variables in formulas either. They are taken as literal values.
I would like to place the value for each bar in barchart (lattice) at the top of each bar. However, I cannot find any option with which I can achieve this. I can only find options for the axis.
Create a custom panel function, e.g.
library("lattice")
p <- barchart((1:10)^2~1:10, horiz=FALSE, ylim=c(0,120),
panel=function(...) {
args <- list(...)
panel.text(args$x, args$y, args$y, pos=3, offset=1)
panel.barchart(...)
})
print(p)
I would have suggested using the new directlabels package, which can be used with both lattice and ggplot (and makes life very easy for these labeling problems), but unfortunately it doesn't work with barcharts.
Since I had to do this anyway, here's a close-enough-to-figure it out code sample along the lines of what #Alex Brown suggests (scores is a 2D array of some sort, which'll get turned into a grouped vector):
barchart(scores, horizontal=FALSE, stack=FALSE,
xlab='Sample', ylab='Mean Score (max of 9)',
auto.key=list(rectangles=TRUE, points=FALSE),
panel=function(x, y, box.ratio, groups, errbars, ...) {
# We need to specify groups because it's not actually the 4th
# parameter
panel.barchart(x, y, box.ratio, groups=groups, ...)
x <- as.numeric(x)
nvals <- nlevels(groups)
groups <- as.numeric(groups)
box.width <- box.ratio / (1 + box.ratio)
for(i in unique(x)) {
ok <- x == i
width <- box.width / nvals
locs <- i + width * (groups[ok] - (nvals + 1)/2)
panel.arrows(locs, y[ok] + 0.5, scores.ses[,i], ...)
}
} )
I haven't tested this, but the important bits (the parts determining the locs etc. within the panel function) do work. That's the hard part to figure out. In my case, I was actually using panel.arrows to make errorbars (the horror!). But scores.ses is meant to be an array of the same dimension as scores.
I'll try to clean this up later - but if someone else wants to, I'm happy for it!
If you are using the groups parameter you will find the labels in #rcs's code all land on top of each other. This can be fixed by extending panel.text to work like panel.barchart, which is easy enough if you know R.
I can't post the code of the fix here for licencing reasons, sorry.