I am creating a custom geom which displays a little plot-in-plot, a small mini barplot that can be displayed somewhere on the plot. You will see an example below (don't ask me why I do it, I need it Because Of Reasons).
My questions:
- How does ggplot2 choose the colors of the bar? I don't see how they were defined. They magically appear when
coord$transform
is called. Why are colors for the same cylinder number on different parts of the plot different? - How can I make the colors matching between the mini barplots?
- How can I add a legend describing the bars? I assume that would have to be called from a setup function of the geom or an associated stat, because normally each group gets only one key (and here we need several key per group).
Example: using the mpg data set, we plot mean displacement over time. At each year, we put a small bar plot showing relative proportions of cars with a given number of cylinders (still working on the labels, though).
# library(ggplot2)
# library(grid)
## per year summary – mean displacement
point.data <- mpg %>% group_by(year) %>% summarise(mean_displ=mean(displ))
## per year, number of models with the given number of cylinders
bar.data <- mpg %>% group_by(year) %>% count(cyl) %>% left_join(point.data)
## position of the mini barplot
bar.data$x <- bar.data$year
bar.data$y <- bar.data$mean_displ + .15
I use my custom geom to show the bar plots (code for the geom is below)
ggplot(point.data, aes(x=year, y=mean_displ)) +
geom_point(size=8, col="lightblue") +
geom_line(size=3, col="lightblue") +
geom_bar_widget(data=bar.data,
aes(x=x, y=y, width=.2, height=.15,
group=year, value=n, fill=factor(n))) +
xlim(1995, 2010) + ylim(3, 4)
Result:
And here is the code for the geom:
## calculate the mini barplot
.bar_widget_bars <- function(x, y, w, h, v, fill) {
nv <- length(v)
v <- h * v / max(v) # scale the values
dx <- w / nv # width of a bar
# xx and yy are the mid positions of the rectangles
xx <- x - w/2 + seq(dx/2, w - dx/2, length.out=nv)
yy <- y - h/2 + v/2
## widths and heights of the rectangles
ww <- rep(dx, nv)
hh <- v
list(rectGrob(xx, yy, ww, hh, gp=gpar(fill=fill)))
}
## draw a mini barplot
.bar_widget_draw_group <- function(data, panel_params, coord, wgdata) {
ct <- coord$transform(data, panel_params)
grobs <- .bar_widget_bars(x=ct$x[1], y=ct$y[1],
w=ct$width[1], h=ct$height[1],
v=data$value, fill=ct$fill)
class(grobs) <- "gList"
gTree("bar_widget_grob", children=grobs)
}
## the widget for the mini barplot
GeomBarWidget <- ggproto("GeomPieWidget",
Geom,
required_aes=c("x", "y", "width", "height", "group", "value"),
default_aes=aes(shape=19, colour="black", fill=NULL, labels=NULL),
draw_key=draw_key_blank(),
draw_group=.bar_widget_draw_group,
extra_params=c("na.rm")
)
geom_bar_widget <- function(mapping = NULL, data = NULL,
stat = "identity",
position = "identity", na.rm = FALSE,
show.legend = FALSE,
inherit.aes = TRUE, ...) {
layer(
geom = GeomBarWidget, mapping = mapping,
data = data, stat = stat,
position = position, show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(na.rm = na.rm, ...)
)
}