1

This answer shows how to use groups and panel.superpose to display overlapping histograms in the same panel, assigning different colors to each histogram. In addition, I want to give each histogram a different border color. (This will allow me to display one histogram as solid bars without a border, overlayed with a transparent, all-border histogram. The example below is a little different for the sake of clarity.)

Although it's possible to use border= to use different border colors in the plot, they are not assigned to groups as fill colors are with col=. If you give border= a sequence of colors, it seems to cycle through them one bar at at time. If the two histograms overlap, the effect is a bit silly (see below).

Is there a way to give each group a specific border color?

# This illustrates the problem: Assignment of border colors to bars ignores grouping:

# make some data
foo.df <- data.frame(x=c(rnorm(10),rnorm(10)+2), cat=c(rep("A", 10),rep("B", 10)))

# plot it
histogram(~ x, groups=cat, data=foo.df, ylim=c(0,75), breaks=seq(-3, 5, 0.5), lwd=2,
          panel=function(...)panel.superpose(..., panel.groups=panel.histogram, 
                                             col=c("transparent", "cyan"), 
                                             border=c(rep("black", 3), rep("red", 3))))

Note that you can't just count how many bars there are in each group and provide those numbers to rep in the border setting. If the two histograms overlap, at least one of the histograms will use two border colors.

overlapping histograms showing cycling border colors

(It's the panel.superpose code that places the groups on the same panel and that assigns the colors. I don't have a deep understanding of it.)

Community
  • 1
  • 1
Mars
  • 8,689
  • 2
  • 42
  • 70

1 Answers1

3

panel.histogram() doesn't have a formal groups= argument, and if you examine its code, you'll see that it handles any supplied groups= argument differently and in a less standard way than panel.*() functions that do. The upshot of that design decision is that (as you've found) it's not in general easy to pass in to it vectors of graphical parameters specifying per-group appearance

As a workaround, I'd suggest using latticeExtra's +() and as.layer() functions to overlay a number of separate histogram() plots, one for each group. Here's how you might do that:

library(lattice)
library(latticeExtra)

## Split your data by group into separate data.frames
foo.df <- data.frame(x=c(rnorm(10),rnorm(10)+2), cat=c(rep("A", 10),rep("B", 10)))
foo.A <- subset(foo.df, cat=="A")
foo.B <- subset(foo.df, cat=="B")

## Use calls to `+ as.layer()` to layer each group's histogram onto previous ones  
histogram(~ x, data=foo.A, ylim=c(0,75), breaks=seq(-3, 5, 0.5), 
          lwd=2, col="transparent", border="black") +
as.layer(
histogram(~ x, data=foo.B, ylim=c(0,75), breaks=seq(-3, 5, 0.5), 
          lwd=2, col="cyan", border="red") 
)

enter image description here

Josh O'Brien
  • 159,210
  • 26
  • 366
  • 455
  • Thanks Josh. Cool--I'll try this. In the first line of the answer, you mean `panel.histogram`, right? (It's unfortunate that breaks have to be handled manually. Another solution I found has the same drawback. That's not a big problem, but one of the points of Lattice is to do that for you. I think that Sarkar probably felt that groups in histograms were a bad idea, which they are, usually, but it's clear that there are a few cases in which that's not so.) – Mars Nov 25 '15 at 18:15
  • @Mars Thanks for catching that typo. And yeah, I agree that Sarkar probably didn't include support for groups in histograms because there's so little legitimate need for it! – Josh O'Brien Dec 02 '15 at 04:36