-2

I've tough time with ggplot2 when used in function or S4. Here is my code without function:

rm(list=ls(all=TRUE))
library(nlme)
data(Oats)
Data <- Oats

Data$Env <- factor(Data$Block)
Data$Gen  <- factor(Data$Variety)

Data$Gen <- factor(Data$Gen)
Data$Env <- factor(Data$Env)
Gen.No <- length(levels(Data$Gen))
Env.No <- length(levels(Data$Env))
Min.G.E <- min(Gen.No, Env.No)

GGE.ANOVA <- aov(yield ~ Env + Env:Gen, data = Data)
GGE.Effs <- model.tables(GGE.ANOVA, type = "effects", cterms = "Env:Gen")$tables$"Env:Gen"
SVD <- svd(GGE.Effs)
D <- diag(SVD$d[1:Min.G.E])
E <- SVD$u%*%sqrt(D)
G <- SVD$v%*%sqrt(D)
Ecolnumb <- c(1:Min.G.E)
Ecolnames <- paste("PC", Ecolnumb, sep="")
dimnames(E) <- list(levels(Data$Env), Ecolnames)
dimnames(G) <- list(levels(Data$Gen), Ecolnames)
SVD.Values <- SVD$d
PC.No <- c(1:length(SVD.Values))
PC.SS <- SVD.Values^2
PC.Percent.SS <- PC.SS/sum(PC.SS)*100

library(grDevices)
con.hull.pos <- chull(G)
con.hull <- rbind(G[con.hull.pos, ], G[con.hull.pos[1], ])

getPerpPoints <- function(mat) {
x <- mat[,1]
y <- mat[,2]
out <- matrix(0, nrow = 2, ncol = 2)
if(diff(x) == 0) {
xnew <- x[1]
  }
  else {
xnew <- (diff(y) / diff(x)) * x[1] - y[1]
xnew <- xnew / (diff(y) / diff(x) + diff(x) / diff(y))
  }
  ynew <- -(diff(x) / diff(y)) * xnew
  out[2,] <- c(xnew, ynew)
  return(out = out)
    }
tmp <- t(sapply(1:(nrow(con.hull)-1),
     function(i) getPerpPoints(con.hull[i:(i+1),])[2, ]))
tmp <- as.data.frame(tmp)


library(ggplot2)
r <- 0.08
p <- ggplot(data = as.data.frame(G), aes(PC1, PC2)) + geom_point() + theme_bw()
p <- p + geom_text(aes(label = row.names(G)), size = 3, vjust = 1.25, colour = "black")
p <- p + geom_path(data = as.data.frame(con.hull), aes(PC1, PC2))
p <- p + geom_segment(data = as.data.frame(E), aes(xend = PC1, yend = PC2), x = 0, y = 0,
                  colour = "black", arrow = arrow(angle = 25, length = unit(0.25, "cm")))
p <- p + geom_text(data = as.data.frame(E), aes(label = row.names(E)),
               size = 3, vjust = 1.35, colour = "black")
p <- p + labs(list(x = sprintf("PC1 (%.1f%%)", PC.Percent.SS[1]),
               y = sprintf("PC2 (%.1f%%)", PC.Percent.SS[2])))
p <- p  + opts(axis.title.x = theme_text(size = 10, hjust = 0.54, vjust = 0))
p <- p  + opts(axis.title.y = theme_text(size = 10, angle = 90,  vjust = 0.25))
p <- p + xlim(range(c(E[ ,1], G[ ,1])) + range(c(E[ ,1], G[ ,1]))*r)
p <- p + ylim(range(c(E[ ,2], G[ ,2])) + range(c(E[ ,2], G[ ,2]))*r)
p <- p + geom_segment(data = as.data.frame(tmp), aes(xend = tmp$V1, yend = tmp$V2), x = 0, y = 0)
print(p)

and the output is enter image description here

But when I use the same code in the following function, I got error

rm(list=ls(all=TRUE))
PlotGGE <- function(Response, Env, Gen, Data) {

Data$Env <- factor(Data$Env)
Data$Gen  <- factor(Data$Gen)
Gen.No <- length(levels(Data$Gen))
Env.No <- length(levels(Data$Env))
Min.G.E <- min(Gen.No, Env.No)

GGE.ANOVA <- aov(yield ~ Env + Env:Gen, data = Data)
GGE.Effs <- model.tables(GGE.ANOVA, type = "effects", cterms = "Env:Gen")$tables$"Env:Gen"
SVD <- svd(GGE.Effs)
D <- diag(SVD$d[1:Min.G.E])
E <- SVD$u%*%sqrt(D)
G <- SVD$v%*%sqrt(D)
Ecolnumb <- c(1:Min.G.E)
Ecolnames <- paste("PC", Ecolnumb, sep="")
dimnames(E) <- list(levels(Data$Env), Ecolnames)
dimnames(G) <- list(levels(Data$Gen), Ecolnames)
SVD.Values <- SVD$d
PC.No <- c(1:length(SVD.Values))
PC.SS <- SVD.Values^2
PC.Percent.SS <- PC.SS/sum(PC.SS)*100

library(grDevices)
con.hull.pos <- chull(G)
con.hull <- rbind(G[con.hull.pos, ], G[con.hull.pos[1], ])

getPerpPoints <- function(mat) {
x <- mat[,1]
y <- mat[,2]
out <- matrix(0, nrow = 2, ncol = 2)
if(diff(x) == 0) {
xnew <- x[1]
  }
  else {
xnew <- (diff(y) / diff(x)) * x[1] - y[1]
xnew <- xnew / (diff(y) / diff(x) + diff(x) / diff(y))
  }
  ynew <- -(diff(x) / diff(y)) * xnew
  out[2,] <- c(xnew, ynew)
  return(out = out)
    }
tmp <- t(sapply(1:(nrow(con.hull)-1),
     function(i) getPerpPoints(con.hull[i:(i+1),])[2, ]))
tmp <- as.data.frame(tmp)


library(ggplot2)
r <- 0.08
p <- ggplot(data = as.data.frame(G), aes(PC1, PC2)) + geom_point() + theme_bw()
p <- p + geom_text(aes(label = row.names(G)), size = 3, vjust = 1.25, colour = "black")
p <- p + geom_path(data = as.data.frame(con.hull), aes(PC1, PC2))
p <- p + geom_segment(data = as.data.frame(E), aes(xend = PC1, yend = PC2), x = 0, y = 0,
                  colour = "black", arrow = arrow(angle = 25, length = unit(0.25, "cm")))
p <- p + geom_text(data = as.data.frame(E), aes(label = row.names(E)),
               size = 3, vjust = 1.35, colour = "black")
p <- p + labs(list(x = sprintf("PC1 (%.1f%%)", PC.Percent.SS[1]),
               y = sprintf("PC2 (%.1f%%)", PC.Percent.SS[2])))
p <- p  + opts(axis.title.x = theme_text(size = 10, hjust = 0.54, vjust = 0))
p <- p  + opts(axis.title.y = theme_text(size = 10, angle = 90,  vjust = 0.25))
p <- p + xlim(range(c(E[ ,1], G[ ,1])) + range(c(E[ ,1], G[ ,1]))*r)
p <- p + ylim(range(c(E[ ,2], G[ ,2])) + range(c(E[ ,2], G[ ,2]))*r)
p <- p + geom_segment(data = as.data.frame(tmp), aes(xend = tmp$V1, yend = tmp$V2), x = 0, y = 0)
print(p)
}

library(nlme)
data(Oats)

EDIT

Oats$Env <- factor(Oats$Block)
Oats$Gen <- factor(Oats$Variety)
PlotGGE(Response = yield, Env = Env, Gen = Gen, Data = Oats)

The error is

Error in row.names(G) : object 'G' not found

Any help and/or comments will be highly appreciated. Thanks in advance.

MYaseen208
  • 22,666
  • 37
  • 165
  • 309
  • 1
    Well, your code is not the same in both instances. The first line in your `PlotGGE` function is `Data$Env <- factor(Data$Env)`. Since you pass `Oats` to your function, this is equivalent to `Oats$Env <- factor(Oats$Env)`. Since `Oats` doesn't have an `Env` column, this causes your error. This has nothing to do with `ggplot`. – Andrie Aug 21 '11 at 20:29
  • 2
    i would not expect the very first line of your function to work as intended. Try `Data[[Env]]` instead, with `Env = "Block"`. More generally, try to debug smaller pieces at a time. – baptiste Aug 21 '11 at 20:30
  • FYI: Cross Posted, http://stats.stackexchange.com/questions/14603/ggplot2-in-function-or-s4 – Brandon Bertelsen Aug 22 '11 at 00:19
  • Sorry for cross posting. Next time I'll take care of this. Thanks – MYaseen208 Aug 22 '11 at 17:33

4 Answers4

3

Your version in the function is missing the following two lines at the very beginning compared to the original version:

Data$Env <- factor(Data$Block)
Data$Gen  <- factor(Data$Variety)

Have you experimented with using debug() to step through functions to find the source of errors?

joran
  • 169,992
  • 32
  • 429
  • 468
  • 2
    +1 for debug and I would also like to mention `?browser` (I find it more convenient). – Roman Luštrik Aug 21 '11 at 20:35
  • @Joran: I've edited the code. Please have a look again. Thanks – MYaseen208 Aug 21 '11 at 20:46
  • 2
    @MYaseen208 The corrected function runs fine for me, so there must be some other discrepancy between the code you're running and the code you posted. But now that you know about `debug()` you can easily find the problem yourself! ;) – joran Aug 21 '11 at 20:48
2

Just add a label columns to the data frames. Also, note that you should never have a $ inside aes.

This should work:

G1 <- data.frame(G, label=rownames(G))
E1 <- data.frame(E, label=rownames(E))

library(ggplot2)
r <- 0.08
p <- ggplot(data=G1, aes(PC1, PC2)) + geom_point() + theme_bw()
p <- p + geom_text(aes(label=label), size=3, vjust=1.25, colour="black")
p <- p + geom_path(data=as.data.frame(con.hull), aes(PC1, PC2))
p <- p + geom_segment(data=as.data.frame(E), aes(xend = PC1, yend=PC2),
                      x=0, y=0, colour="black",
                      arrow=arrow(angle=25, length=unit(0.25, "cm")))
p <- p + geom_text(data=E1, aes(label=label),
                   size=3, vjust=1.35, colour="black")
p <- p + labs(list(x=sprintf("PC1 (%.1f%%)", PC.Percent.SS[1]),
                   y=sprintf("PC2 (%.1f%%)", PC.Percent.SS[2])))
p <- p  + opts(axis.title.x=theme_text(size=10, hjust=0.54, vjust=0))
p <- p  + opts(axis.title.y=theme_text(size=10, angle=90, vjust=0.25))
p <- p + xlim(range(c(E[ ,1], G[ ,1])) + range(c(E[ ,1], G[ ,1]))*r)
p <- p + ylim(range(c(E[ ,2], G[ ,2])) + range(c(E[ ,2], G[ ,2]))*r)
p <- p + geom_segment(data=tmp, aes(xend=V1, yend=V2), x=0, y=0)
print(p)
rcs
  • 67,191
  • 22
  • 172
  • 153
2

You have to set as.data.frame(G) outside of your ggplot2 call if you want to be able to use rownames(G).

Set data=as.data.frame(G) in your call to geom_text.

Brandon Bertelsen
  • 43,807
  • 34
  • 160
  • 255
0
p <- p + geom_text(aes(label = row.names(G)), size = 3, vjust = 1.25, colour = "black")

You're providing it with a layer, but no data to plot. Either move label= into your original call to ggplot or provide geom_text() with a data= argument

Brandon Bertelsen
  • 43,807
  • 34
  • 160
  • 255