Grouped Boxplots

586 views
Skip to first unread message

kawumba

unread,
Feb 9, 2011, 4:54:09 PM2/9/11
to ggplot2
Hello,

I am really new to ggplot2. I managed to produce a boxplot:

myplot1 <- qplot(V1_pos, R_V1_pos, data=data, geom="boxplot",
outlier.size=0)
myplot1 + stat_summary(fun.y=mean, geom="point") + ylim(0,4)


Now I want to add another boxplot to this figure, i.e. I want to plot
boxes for the variable "R_V2_pos", which also depends on V1_pos. The
boxes for R_V1_pos and R_V2_pos shall appear next to each other,
grouped by the factor V1_pos, like this:

^
|
| Var1 Var2 Var1 Var2 ....
|
-------------------------------->
level1 level2 .....


I've been trying for hours to produce such a plot, but to no avail :
( Could you please point me to the solution?

Thanks,

kawumba

Dennis Murphy

unread,
Feb 9, 2011, 6:48:25 PM2/9/11
to kawumba, ggplot2
Hi:

It's a lot easier to get useful help if you supply a small example, with data and code, that illustrates the problem you're having. For one thing, since no one has access to your data, it's impossible to run your code to see what it produces - one can only guess and hope that our imagination matches your reality. That's error prone.

Based on your graph outline below, perhaps you're looking for something like the following:

# Create a toy data set with three variables
df <- data.frame(grp = rep(c('A', 'B'), each = 20),
                   Y1 = rnorm(40),
                   Y2 = rnorm(40, mean = 3, sd = 2))

# To get 'side-by side' boxplots of the two variables by groups, the first step
# is to 'stack' the data by using the melt() function in the reshape package - it
# loads with ggplot2. The result is a data frame with a grp column (id variable),
# a factor named variable that identifies the variable name, and a variable named
# value that contains the values of the two variables Y1 and Y2 (which are assumed to
# be comparable in the graph below). This can be used to advantage in the ggplot() call.
dfm <- melt(df, id = 'grp')

# Note how the created factor 'variable' is used as an aesthetic:
ggplot(dfm, aes(x = grp, y = value)) +
     geom_boxplot(aes(fill = variable))

In this example, the fill aesthetic allows the boxplots to be 'dodged' next to one another within the same grp, with a legend that identifies the variables associated with each fill color.

If the response variables are different from each other, an alternative is to produce a faceted plot, with the variables generating individual facets:

ggplot(dfm, aes(x = grp, y = value)) + labs(fill = 'Group', x = 'Group', y = 'Response') +
     geom_boxplot(aes(fill = grp)) + facet_wrap( ~ variable, scales = 'free_y')

In this plot, the 'free_y' scale allows for different y-scales in each panel; without it, both facets have the same x- and y-scales. The labs() statement provides labels for the legend title (fill) as well as for the x and y axis; it is convenient and worth remembering, since AFAIR it wasn't mentioned in Hadley's book.

Hope this is what you were after,
Dennis


--
You received this message because you are subscribed to the ggplot2 mailing list.
Please provide a reproducible example: http://gist.github.com/270442

To post: email ggp...@googlegroups.com
To unsubscribe: email ggplot2+u...@googlegroups.com
More options: http://groups.google.com/group/ggplot2

kawumba

unread,
Feb 10, 2011, 9:35:14 AM2/10/11
to ggplot2
Hello Dennis,

many thanks for your quick and very helpful reply! Sorry I didn't
include any sample data in the first place, I ... missed that.

Using your example code, I managed to get the boxplots arranged the
way I like :) But there's still one problem:

myplot + stat_summary(fun.y=mean, geom="point")

doesn't calculate the mean for each response variable separately, but
instead a 'common' mean (a single one for each factor, that is; while
I'd like to have _two_ for each factor, since I am plotting two
response variables/factor).

Here ist my current code snippet:

===================
data <- read.delim("data.txt", sep="")

data$Trial <- factor(data$Trial)
data$Cond <- factor(data$Cond)
data$V_num <- factor(data$V_num)
data$V1_pos <- factor(data$V1_pos)
data$V2_pos <- factor(data$V2_pos)
data$Class <- factor(data$Class)

data.melted <- melt(data, measure = c('R_V1_pos', 'R_V2_pos'))

myplot <- ggplot(data.melted, aes(x = V1_pos, y = value)) +
geom_boxplot(aes(fill = variable), outlier.size = 0)
myplot + stat_summary(fun.y = mean, geom = "point")
===================


Sample data (can also be found at: http://bpaste.net/raw/13577/)

===================
"Trial" "Cond" "V_num" "V1_pos" "V2_pos" "R_V_num" "R_V1_pos"
"R_V2_pos" "Class"
"1" "11" "2" "0" "1" 1 2 2 "2F4A"
"2" "25" "2" "1" "2" 1 0 0 "2F0A"
"3" "9" "1" "3" "3" 1 0 0 "1F0A"
"4" "12" "2" "0" "2" 2 2 3 "2F4A"
"5" "10" "1" "4" "4" 1 0 0 "1F0A"
"6" "9" "1" "3" "3" 1 0 0 "1F0A"
"7" "21" "2" "0" "1" 1 0 0 "2F0A"
"8" "18" "2" "2" "3" 1 2 2 "2F4A"
"9" "5" "1" "4" "4" 1 0 0 "1F4A"
"10" "9" "1" "3" "3" 1 0 0 "1F0A"
"11" "26" "2" "1" "3" 1 0 0 "2F0A"
"12" "19" "2" "2" "4" 1 2 2 "2F4A"
"13" "25" "2" "1" "2" 1 0 0 "2F0A"
"14" "14" "2" "0" "4" 2 2 3 "2F4A"
"15" "15" "2" "1" "2" 2 2 3 "2F4A"
"16" "22" "2" "0" "2" 2 0 0 "2F0A"
"17" "3" "1" "2" "2" 1 2 2 "1F4A"
"18" "23" "2" "0" "3" 2 0 0 "2F0A"
"19" "30" "2" "3" "4" 1 0 0 "2F0A"
"20" "8" "1" "2" "2" 1 0 0 "1F0A"
===================

Any ideas how I can plot the 'mean' indicator for both variables at
every factor?

All the best,

kawumba

Allan

unread,
Feb 10, 2011, 10:58:55 AM2/10/11
to ggplot2
Hi kawumba,
when you specified fill=variable ggplot2 dodged to put the boxplots
for two different levels of fill next to each other. But ggplot needs
to be told of this grouping for your stat summary as well.
Furthermore, ggplot2 doesn't really know how to dodge point geoms
because they don't have a clear width and so you need to specify the
amount of dodging as well (not needed if you used bars for the
stat_summary). Note that I redid your example using dput() with your
data so that it is easier for others to run.
Hope this helps,
Allan (R 2.12.1, ggplot2 0.8.9)

data <- structure(list(Trial = structure(1:20, .Label = c("1", "2",
"3",
"4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15",
"16", "17", "18", "19", "20"), class = "factor"), Cond =
structure(c(6L,
15L, 4L, 7L, 5L, 4L, 12L, 10L, 2L, 4L, 16L, 11L, 15L, 8L, 9L,
13L, 1L, 14L, 17L, 3L), .Label = c("3", "5", "8", "9", "10",
"11", "12", "14", "15", "18", "19", "21", "22", "23", "25", "26",
"30"), class = "factor"), V_num = structure(c(2L, 2L, 1L, 2L,
1L, 1L, 2L, 2L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 2L, 2L, 1L
), .Label = c("1", "2"), class = "factor"), V1_pos = structure(c(1L,
2L, 4L, 1L, 5L, 4L, 1L, 3L, 5L, 4L, 2L, 3L, 2L, 1L, 2L, 1L, 3L,
1L, 4L, 3L), .Label = c("0", "1", "2", "3", "4"), class = "factor"),
V2_pos = structure(c(1L, 2L, 3L, 2L, 4L, 3L, 1L, 3L, 4L,
3L, 3L, 4L, 2L, 4L, 2L, 2L, 2L, 3L, 4L, 2L), .Label = c("1",
"2", "3", "4"), class = "factor"), R_V_num = c(1L, 1L, 1L,
2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 1L, 2L,
1L, 1L), R_V1_pos = c(2L, 0L, 0L, 2L, 0L, 0L, 0L, 2L, 0L,
0L, 0L, 2L, 0L, 2L, 2L, 0L, 2L, 0L, 0L, 0L), R_V2_pos = c(2L,
0L, 0L, 3L, 0L, 0L, 0L, 2L, 0L, 0L, 0L, 2L, 0L, 3L, 3L, 0L,
2L, 0L, 0L, 0L), Class = structure(c(4L, 3L, 1L, 4L, 1L,
1L, 3L, 4L, 2L, 1L, 3L, 4L, 3L, 4L, 4L, 3L, 2L, 3L, 3L, 1L
), .Label = c("1F0A", "1F4A", "2F0A", "2F4A"), class =
"factor")),
.Names = c("Trial", "Cond", "V_num", "V1_pos", "V2_pos", "R_V_num",
"R_V1_pos", "R_V2_pos", "Class"),
row.names = c(NA, -20L), class = "data.frame")

data.melted <- melt(data, measure = c('R_V1_pos', 'R_V2_pos'))

myplot <- ggplot(data.melted, aes(x = V1_pos, y = value)) +
geom_boxplot(aes(fill = variable), outlier.size = 0)

myplot + stat_summary(fun.y = mean, geom = "point",
aes(group = variable), position = position_dodge(width = 0.75))

Dennis Murphy

unread,
Feb 10, 2011, 3:38:46 PM2/10/11
to kawumba, ggplot2
Hi:

This is what I got when I made a table of your data (and thanks to Allan for the dput() form):

> with(data, table(R_V1_pos, V1_pos))
        V1_pos
R_V1_pos 0 1 2 3 4
       0 3 3 1 4 2
       2 3 1 3 0 0
> with(data, table(R_V2_pos, V1_pos))
        V1_pos
R_V2_pos 0 1 2 3 4
       0 3 3 1 4 2

       2 1 0 3 0 0
       3 2 1 0 0 0

Your responses are discrete, and I would humbly suggest that a boxplot is probably not the best visual device for discrete data, especially with small sample sizes. What is the goal here?

Dennis


kawumba

Wagner Moreira

unread,
May 10, 2013, 3:00:54 PM5/10/13
to ggp...@googlegroups.com
Hi Dennis,

I found your reply to Kawumba and I really liked the example you gave to build grouped boxplots.

Using your example, how would you build a grouped boxplot replacing the median by the mean, the hinges by mean +- sd and the whiskers by min and max? (I know that the concept of boxplot does not use those statistics, but the graph can be useful for other interpretations as well)

Thanks in advance

Wagner
Reply all
Reply to author
Forward
0 new messages