Faceted plot with horizontal bars; can it be done?

154 views
Skip to first unread message

Stuart Sharples

unread,
Aug 9, 2011, 5:09:18 AM8/9/11
to ggplot2
Hi people,

# I'm trying to produce a faceted plot with horizontal bars and I
# can't seem to get what I want. If you copy and paste everything below you'll
# get one plot containing my three attempts. For more detail see comments below.

# Here's my working example:

require(ggplot2)

# fake data
dat <- data.frame(
  type = c(rep("Veg", 4), rep("Fruit",2)),
  item = c("Potato", "Spinach", "Red onion", "Mixed leaves", "Tomato", "Lime"),
  proportion = c(0.03, 0.35, 0.95, 0.2, 0.57, 0.01)
)
dat$item <- reorder(dat$item, dat$proportion)


# First off, it's easy enough to produce the dot plot of what I want, so let's
# do that:

p.dot <- ggplot(dat, aes(x = proportion, y = item)) +
  geom_point() +
  facet_grid(type ~ ., scales = "free_y", space = "free") +
  opts(title = "Good, but I want bars not dots")

p.dot

# However, what I'm really after is a bar version of 'p.dot', so instead of dots
# we have horizontal bars starting out from zero. I can try and get this by
# doing something similar and using coord_flip():

p.bar <- ggplot(dat, aes(x = item, y = proportion)) +   # x and y are opposite
  geom_bar() +
  coord_flip() +
  facet_grid(type ~ ., scales = "free_y", space = "free") +
  opts(title = "Ugh, what's with all the inappropriate levels?")

p.bar

# As you can see it's almost there, but for some reason it's put all the levels
# in for each category, we didn't have that problem in 'p.dot'

# By removing the coord_flip() and swapping bits around in facet_grid() I can
# get a vertical version of what I want:

p.bar.vert <- ggplot(dat, aes(x = item, y = proportion)) +
  geom_bar() +
  facet_grid(. ~ type, scales = "free_x", space = "free") +
  opts(title = "Good, but I want it rotated 90 degrees")

p.bar.vert

# This is perfect, except I want it rotated 90 degrees, how should I go about
# it?


# For those who copy and pasted everything or if you want to see all three at
# once
pushViewport(viewport(layout = grid.layout(1,3)))
pushViewport(viewport(layout.
pos.col = 1))
print(p.dot, newpage = FALSE)
popViewport()
pushViewport(viewport(layout.pos.col = 2))
print(p.bar, newpage = FALSE)
popViewport()
pushViewport(viewport(layout.pos.col = 3))
print(p.bar.vert, newpage = FALSE)
popViewport()


# P.S. With 'p.dot' there also seems to be something wrong; there's white space
#      between the tick marks of 'Tomato' and Lime' and the plotting area

# What I'm using:
# Ubuntu 10.04, R version 2.13.1, ggplot2 version 0.8.9

Stuart Sharples

unread,
Aug 9, 2011, 10:35:56 AM8/9/11
to Ista Zahn, ggplot2
Thanks for your help, Ista.

Your code is an improvement over what I've managed so far.

Hmmm I wouldn't expect this to be fixed any time soon, that bug was submitted over a year ago, but at least there is one.

...

OK I think I have a workaround, what I have to do is create a 'line' rather than a bar for each item and then increase the line thickness so it looks like a bar. To do this I duplicate the data set and replace it's values with zeros, rbind it with the original data and then use geom_line() like this:

# create data set of zeros, as this is where we want all the lines to start from
zero.dat <- dat
zero.dat$proportion <- 0
hack.dat <- rbind(dat, zero.dat)

p.line <- ggplot(hack.dat, aes(x = proportion, y = item)) +
  geom_line(size = 10) +

  facet_grid(type ~ ., scales = "free_y", space = "free") +
  opts(title = "Perfect!")

p.line



This looks exactly like what I want. OK doubling the size of the data is bad but I don't have to use coord_flip.

Thanks again,

Stu


On 9 August 2011 13:14, Ista Zahn <iz...@psych.rochester.edu> wrote:
Hi Stuart,
>   opts(title = "Ugh, what's with all the inappropriatelevels?")

>
> p.bar
>
> # As you can see it's almost there, but for some reason it's put all the
> levels
> # in for each category, we didn't have that problem in 'p.dot'

I think the problem is that facet_grid sets the scales for each row
and / or column in the facet, not for individual "cells" in the facet.
And then it gets confused by coord_flip, and doesn't realize that the
rows and columns have switched.

There is already a bug report open on this issue
(https://github.com/hadley/ggplot2/issues/95) so hopefully it will be
fixed soon. In the meantime the closest I can get is


ggplot(dat, aes(x = item, y = proportion)) +
 geom_bar() +
 facet_wrap(~ type, scales = "free", ncol = 1) +
 coord_flip()


HTH,
Ista
> --
> 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
>



--
Ista Zahn
Graduate student
University of Rochester
Department of Clinical and Social Psychology
http://yourpsyche.org

Brian Diggs

unread,
Aug 9, 2011, 12:25:40 PM8/9/11
to ggplot2
On 8/9/2011 7:35 AM, Stuart Sharples wrote:
> Thanks for your help, Ista.
>
> Your code is an improvement over what I've managed so far.
>
> Hmmm I wouldn't expect this to be fixed any time soon, that bug was
> submitted over a year ago, but at least there is one.
>
> ...
>
> OK I think I have a workaround, what I have to do is create a 'line' rather
> than a bar for each item and then increase the line thickness so it looks
> like a bar. To do this I duplicate the data set and replace it's values with
> zeros, rbind it with the original data and then use geom_line() like this:
>
> # create data set of zeros, as this is where we want all the lines to start
> from
> zero.dat<- dat
> zero.dat$proportion<- 0
> hack.dat<- rbind(dat, zero.dat)
>
> p.line<- ggplot(hack.dat, aes(x = proportion, y = item)) +
> geom_line(size = 10) +
> facet_grid(type ~ ., scales = "free_y", space = "free") +
> opts(title = "Perfect!")
>
> p.line
>
>
>
> This looks exactly like what I want. OK doubling the size of the data is bad
> but I don't have to use coord_flip.
>
> Thanks again,
>
> Stu

If you really already have pre-summarized data, here is another work around:

GeomHbar <- proto(Geom, {

default_stat <- function(.) StatIdentity
default_pos <- function(.) PositionIdentity
default_aes <- function(.) aes(colour=NA, fill="grey20", size=0.5,
linetype=1, weight = 1, alpha = 1)

required_aes <- c("x", "y")

reparameterise <- function(., df, params) {
df$width <- df$width %||%
params$width %||% (resolution(df$y, FALSE) * 0.9)
transform(df,
xmin = pmin(x, 0), xmax = pmax(x, 0),
ymin = y - width / 2, ymax = y + width / 2, width = NULL
)
}

draw_groups <- function(., data, scales, coordinates, ...) {
GeomRect$draw_groups(data, scales, coordinates, ...)
}

# Documentation -----------------------------------------------
objname <- "hbar"
desc <- "Bars, rectangles with bases on y-axis"
guide_geom <- function(.) "polygon"

icon <- function(.) {
rectGrob(c(0.3, 0.7), c(0.4, 0.8), height=c(0.4, 0.8), width=0.3,
vjust=1, gp=gpar(fill="grey20", col=NA))
}
})
geom_hbar <- GeomHbar$build_accessor()


p.hbar <- ggplot(dat, aes(x = proportion, y = item)) +
geom_hbar() +


facet_grid(type ~ ., scales = "free_y", space = "free") +

opts(title = "Good, actual horizontal bars")

p.hbar


Note that geom_hbar is not nearly as general as geom_bar; for one thing
its default stat is identity, not bin. There isn't a stat which bins
along the y axis (although you could write one), so if you try to change
the stat to bin, I don't really know what would happen. Basically, I
just took geom_bar, flipped the x and y in the reparameterise function,
and changed the default stacking and stat.

>>> To post: email ggplot2-/JYPxA39Uh5...@public.gmane.org
>>> To unsubscribe: email ggplot2+unsubscribe-/JYPxA39Uh5...@public.gmane.org


>>> More options: http://groups.google.com/group/ggplot2
>>>
>>
>>
>>
>> --
>> Ista Zahn
>> Graduate student
>> University of Rochester
>> Department of Clinical and Social Psychology
>> http://yourpsyche.org
>>
>


--
Brian S. Diggs, PhD
Senior Research Associate, Department of Surgery
Oregon Health & Science University

Stu Sharples

unread,
Aug 10, 2011, 10:33:24 AM8/10/11
to Brian Diggs, ggplot2
Thanks for this Brian, like you say it does indeed produce "good, actual horizontal bars". just one question; when you say you "just took geom_bar" how did you get the code for it? Did you just go to the geom-bar-.r on github, or did you do it from within R?

Thanks again!

Stu


On 9 August 2011 13:14, Ista Zahn<izahn-7lguHJXwfyo6QsK68V2XfZVzexx5G7l...@public.gmane.org>  wrote:

Hi Stuart,

On Tue, Aug 9, 2011 at 5:09 AM, Stuart Sharples
To post: email ggplot2-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe: email ggplot2+unsubscribe-/JYPxA39Uh5TLH3M...@public.gmane.org



--
Ista Zahn
Graduate student
University of Rochester
Department of Clinical and Social Psychology
http://yourpsyche.org



--
Brian S. Diggs, PhD
Senior Research Associate, Department of Surgery
Oregon Health & Science University

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


Brian Diggs

unread,
Aug 10, 2011, 11:55:26 AM8/10/11
to Stu Sharples, ggplot2
On 8/10/11 7:33 AM, Stu Sharples wrote:
> Thanks for this Brian, like you say it does indeed produce "good, actual
> horizontal bars". just one question; when you say you "just took
> geom_bar" how did you get the code for it? Did you just go to the
> geom-bar-.r
> <https://github.com/hadley/ggplot2/blob/master/R/geom-bar-.r> on github,

> or did you do it from within R?

I did it from the source code, not from within R. (I got it from the
github website, although I do have a copy of the repository on my
machine so I could have gotten it from there.) Since ggplot uses
proto[*], I find it hard to track down appropriate source from within R.

[*] A lot of the guts are being re-written for ggplot2-0.9.0, including
the dependence on proto. That also means that this code for a
horizontal bar won't work with 0.9.0 when it is released.

> Thanks again!
>
> Stu
>
>
> On 9 August 2011 17:25, Brian Diggs <dig...@ohsu.edu

> <mailto:izahn-7lguHJXwfyo6Q...@public.gmane.org>> wrote:
>
> Hi Stuart,
>
> On Tue, Aug 9, 2011 at 5:09 AM, Stuart Sharples
> <stuart.sharples- Re5JQEeQqe8AvxtiuMwx3w@public. gmane.org

> <mailto:stuart.sharples-Re5...@public.gmane.org>>

> <https://github.com/hadley/ggplot2/issues/95>) so hopefully

> pushViewport(viewport(layout. pos.col = 2))


> print(p.bar, newpage = FALSE)
> popViewport()

> pushViewport(viewport(layout. pos.col = 3))


> print(p.bar.vert, newpage = FALSE)
> popViewport()
>
>
> # P.S. With 'p.dot' there also seems to be something
> wrong; there's white
> space
> # between the tick marks of 'Tomato' and Lime' and
> the plotting area
>
> # What I'm using:
> # Ubuntu 10.04, R version 2.13.1, ggplot2 version 0.8.9
>
> --
> 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 ggplot2-/JYPxA39Uh5TLH3MbocFFw
> @public.gmane.org

> <mailto:JYPxA39Uh5...@public.gmane.org>
> To unsubscribe: email ggplot2+unsubscribe-/JYPxA39Uh
> 5TLH3M...@public.gmane.org
> <mailto:JYPxA39Uh5...@public.gmane.org>
>
> More options: http://groups.google.com/ group/ggplot2


> <http://groups.google.com/group/ggplot2>
>
>
>
>
> --
> Ista Zahn
> Graduate student
> University of Rochester
> Department of Clinical and Social Psychology
> http://yourpsyche.org
>
>
>
>
> --
> Brian S. Diggs, PhD
> Senior Research Associate, Department of Surgery
> Oregon Health & Science University
>
> --
> 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

> <mailto:ggp...@googlegroups.com>
> To unsubscribe: email ggplot2+unsubscribe@ googlegroups.com
> <mailto:ggplot2%2Bunsu...@googlegroups.com>
> More options: http://groups.google.com/ group/ggplot2
> <http://groups.google.com/group/ggplot2>

Dennis Murphy

unread,
Aug 10, 2011, 1:33:45 PM8/10/11
to Stu Sharples, Brian Diggs, ggplot2
Hi:

Here's another approach using geom_segment():

ggplot(dat, aes(x = proportion, y = item)) +

geom_segment(aes(xend = 0, yend = item), size = 10) +


facet_grid(type ~ ., scales = 'free_y', space = 'free')

All this does is replace geom_point() with the equivalent code in
geom_segment(). Hopefully this is a bit more robust wrt the upcoming
changes in ggplot2.

HTH,
Dennis

>>> Zahn<izahn-7lguHJXwfyo6Q...@public.gmane.org>  wrote:


>>>
>>>> Hi Stuart,
>>>>
>>>> On Tue, Aug 9, 2011 at 5:09 AM, Stuart Sharples

>>>> <stuart.sharples-Re5...@public.gmane.org>  wrote:

>>>>> To post: email ggplot2-/JYPxA39Uh5...@public.gmane.org
>>>>> To unsubscribe: email
>>>>> ggplot2+unsubscribe-/JYPxA39Uh5...@public.gmane.org

>>>>> More options: http://groups.google.com/group/ggplot2
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Ista Zahn
>>>> Graduate student
>>>> University of Rochester
>>>> Department of Clinical and Social Psychology
>>>> http://yourpsyche.org
>>>>
>>>
>>
>>
>> --
>> Brian S. Diggs, PhD
>> Senior Research Associate, Department of Surgery
>> Oregon Health & Science University
>>
>> --
>> 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

> 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

Stu Sharples

unread,
Aug 12, 2011, 5:47:22 AM8/12/11
to Dennis Murphy, Brian Diggs, ggplot2
Thanks Dennis. Again this is better than my solution since you don't have to double the size of the data. Also like you say it looks like it will survive the update, but maybe it's worth my while putting something like Brian's geom_hbar together after the update because I do like my horizontal bars.

Thanks very much,

Stu
Reply all
Reply to author
Forward
0 new messages