[R] adding error bars to lattice plots
Daniel E. Bunker
deb37 at columbia.edu
Fri Oct 13 21:14:45 CEST 2006
Dear Deepayan and Sundar,
Thank you so much for your help with this. However, I may have phrased
my problem too specifically, assuming that *in general* I could apply
your response to all Lattice graphics.
What I need is a barchart or vertical dotchart, with error bars, across
three treatments, with a form that should look something like:
barchart(median~fac1|by1, groups=group1).
Your solution works great with the problem I had posed
<xyplot(voice.part ~ median|by1, groups=group1, [snip]>, yet when I
switch the axes for a vertical dotchart <xyplot(median~voice.part|by1,
groups=group1, [snip]> the error bars remain horizontal and do not
follow the switched axes.
I tried to alter all 'lx' and 'ux' to 'ly' and 'uy' in panel.ci and
prepanel.ci, but to no avail. I'm afraid I have not (YET) managed to
understand just how Lattice works.
Re. moving panel.abline() from panel.groups to panel, does that mean I
need to rewrite panel.superpose?
Again, any advice would be greatly appreciated.
Thanks, Dan
Deepayan Sarkar wrote:
> On 10/12/06, Daniel E. Bunker <deb37 at columbia.edu> wrote:
>> Dear R users,
>>
>> About a year ago Deepayan offered a suggestion to incorporate error bars
>> into a dotplot using the singer data as an example
>> <<http://finzi.psych.upenn.edu/R/Rhelp02a/archive/63875.html>>.
>>
>> When I try to utilize this code with a grouping variable, I get an error
>> stating that the subscripts argument is missing. I have tried to insert
>> them in various ways, but cannot figure out where they should go.
>>
>> Deepayan's original code follows, with additions from me for factor,
>> grouping and by variables.
>>
>> (Note that I could use xYplot (Dotplot), but I need my response variable
>> on the vertical axis.)
>>
>> Any suggestions would be greatly appreciated.
>>
>> Thanks, Dan
>>
>> prepanel.ci <- function(x, y, lx, ux, subscripts, ...) {
>> x <- as.numeric(x)
>> lx <- as.numeric(lx[subscripts])
>> ux <- as.numeric(ux[subscripts])
>> list(xlim = range(x, ux, lx, finite = TRUE))
>> }
>>
>> panel.ci <- function(x, y, lx, ux, subscripts, pch = 16, ...) {
>> x <- as.numeric(x)
>> y <- as.numeric(y)
>> lx <- as.numeric(lx[subscripts])
>> ux <- as.numeric(ux[subscripts])
>> panel.abline(h = unique(y), col = "grey")
>> panel.arrows(lx, y, ux, y, col = 'black',
>> length = 0.25, unit = "native",
>> angle = 90, code = 3)
>> panel.xyplot(x, y, pch = pch, ...)
>> }
>>
>> singer.split <-
>> with(singer,
>> split(height, voice.part))
>>
>> singer.ucl <-
>> sapply(singer.split,
>> function(x) {
>> st <- boxplot.stats(x)
>> c(st$stats[3], st$conf)
>> })
>>
>> singer.ucl <- as.data.frame(t(singer.ucl))
>> names(singer.ucl) <- c("median", "lower", "upper")
>> singer.ucl$voice.part <-
>> factor(rownames(singer.ucl),
>> levels = rownames(singer.ucl))
>>
>> # add factor, grouping and by variables
>> singer.ucl$fac1=c("level1","level1", "level2", "level2")
>> singer.ucl$by1=c("two","one")
>> singer.ucl$group1=c(rep(letters[1],4),rep(letters[2],4))
>>
>> ## show the data frame
>> singer.ucl
>>
>> # Deepayan's original example
>> with(singer.ucl,
>> xyplot(voice.part ~ median,
>> lx = lower, ux = upper,
>> prepanel = prepanel.ci,
>> panel = panel.ci),
>> horizontal=FALSE)
>>
>> # with by variable, works fine
>> with(singer.ucl,
>> xyplot(voice.part ~ median|by1,
>> lx = lower, ux = upper,
>> prepanel = prepanel.ci,
>> panel = panel.ci))
>>
>> # with groups, fails for lack of subscripts.
>> with(singer.ucl,
>> xyplot(voice.part ~ median, groups=group1,
>> lx = lower, ux = upper,
>> prepanel = prepanel.ci,
>> panel = panel.ci))
>
> Although that does seem to be the eventual error message, this fails
> not due to the lack of subscripts, but because 'panel.ci' does not
> know how to deal with groups. One solution to this is Sundar's
> approach, which is to change the panel function to handle groups.
> Another generic solution is to use 'panel.superpose', which _does_
> know how to handle groups, and also accepts a custom panel function to
> be called for each group. Often (but not always), you can use a panel
> function designed for a non-groups aware display for this. In this
> case, the following gives results similar to Sundar's code:
>
> with(singer.ucl,
> xyplot(voice.part ~ median, groups=group1,
> lx = lower, ux = upper,
> prepanel = prepanel.ci,
> panel = panel.superpose,
> panel.groups = panel.ci,
> pch = 16))
>
> Note the need for an explicit pch=16, since the default in panel.ci is
> overridden by panel.groups.
>
>> # what I need, ultimately, is something like this, with error bars:
>>
>> with(singer.ucl,
>> dotplot(median~fac1|by1, groups=group1))
>
> If you have more than one interval (from different groups) for any
> level of your categorical variable - which seems to be the case in
> this example - you will encounter a problem. The problem is this: the
> grey reference lines are drawn once for every group, and will draw
> over intervals drawn by calls corresponding to earlier levels. This
> can be easily fixed by moving that part of the code from
> 'panel.groups' to 'panel', I'll leave that as an exercise.
>
> -Deepayan
--
Daniel E. Bunker
BioMERGE Associate Director
Post-Doctoral Research Scientist
Columbia University
Department of Ecology, Evolution and Environmental Biology
1200 Amsterdam Avenue
New York, NY 10027-5557
deb37ATcolumbiaDOTedu
212-851-1888 phone
212-854-8188 fax
More information about the R-help
mailing list