[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