LouisMP
LouisMP

Reputation: 353

How to fix label annotation changing histogram

When I add a label annotation of bin height of a histogram, the bins shift height from the same plot without the annotation.

I manually added in the labels and it works until the last value is added for the last bin.

p2 <- ggplot(airquality)+ 
  geom_histogram(aes(x=Temp),bins=9,color="black",fill="white")+
  theme_classic()
p2 # correct plot without annotations

pg <- ggplot_build(p2)
pgx <- pg$data[[1]]$x # extract x values of bin centers
pgy <- pg$data[[1]]$y # extract y values of bins

# plot with label annotations at the x and y positions
p3 <- ggplot(airquality,aes(x=Temp))+ 
  geom_histogram(bins=9,color="black",fill="white")+
  theme_classic()+
  annotate("label",x=pgx,y=pgy,label=pgy)
p3
# bins are shifted a bit left and bin heights have been altered

# try to type locations and labels manually
p4 <- ggplot(airquality,aes(x=Temp))+ 
  geom_histogram(bins=9,color="black",fill="white")+
  theme_classic()+
  annotate("label",
           x=c(56.375, 61.5,66.625,71.75,76.875,82,87.125,92.25,97.375),
           y=c(6, 10,16,16,32,34,22,15,2),
           label=c(6, 10,16,16,32,34,22,15,2))
p4
# same plot as p3

# try to type locations and labels manually but without last label
p5 <- ggplot(airquality,aes(x=Temp))+ 
  geom_histogram(bins=9,color="black",fill="white")+
  theme_classic()+
  annotate("label",
           x=c(56.375, 61.5,66.625,71.75,76.875,82,87.125,92.25),
           y=c(6, 10,16,16,32,34,22,15),
           label=c(6, 10,16,16,32,34,22,15))
p5
# the plot needed but missing the last bin label

How do I get the correct histogram with all annotations?

Upvotes: 0

Views: 280

Answers (2)

Jon Spring
Jon Spring

Reputation: 66955

This seems to work, but I'm not sure exactly why it sidesteps the alignment issues introduced from using geom_histogram for the first layer.

ggplot(data = airquality, aes(Temp, label = ..count..)) +
  stat_bin(geom = "bar", color="black", fill="white", bins = 9) +
  stat_bin(geom = "label", bins = 9) +
  theme_classic()

enter image description here

Upvotes: 1

mnist
mnist

Reputation: 6954

The problem here is in the "reactiveness" of geom_histogram and that a ggplot is only rendered when it is called. As soon as the range of the plot is changed, the bins are calculated differently and therefor shift. I have two solutions for you and I am not very happy with either but here you go:

First: Basically convert your histogram into a barplot:

p1 <- ggplot()+ 
  geom_histogram(aes(x=airquality$Temp), bins=9, color="black", fill="white")+
  theme_classic()
p1 # correct plot without annotations

# get values of the histogram
pg1 <- ggplot_build(p1)
pg1x <- pg1$data[[1]]$x # extract x values of bin centers
pg1y <- pg1$data[[1]]$y # extract y values of bins


# mirror the histogram as a barplot
# a barplot is fixed and not responsive like a histogram
p2 <- ggplot() +
  geom_bar(aes(x = pg1x, y = pg1y), stat="identity")

# grab the labels and position from the barplot
pg2 <- ggplot_build(p2)
pg2x <- pg2$data[[1]]$x # extract x values of bin centers
pg2y <- pg2$data[[1]]$y # extract y values of bins

# final plot
p2 +
  annotate("label",x=pg1x,y=pg1y,label=pg1y)

Second: Define a binwidth formula rather than bins= that does not depend on the plot itself. You would have to tweak the formula however to get the same result

p2 <- ggplot(airquality)+ 
  geom_histogram(aes(x=Temp),
                 binwidth = function(x) 2 * IQR(x) / (length(x)^(1/3)),
                 color="black",fill="white")+
  theme_classic()
p2 # correct plot without annotations

pg <- ggplot_build(p2)
pgx <- pg$data[[1]]$x # extract x values of bin centers
pgy <- pg$data[[1]]$y # extract y values of bins

# plot with label annotations at the x and y positions
p3 <- ggplot(airquality,aes(x=Temp))+ 
  geom_histogram(aes(x=Temp),
                 binwidth = function(x) 2 * IQR(x) / (length(x)^(1/3)),
                 color="black",fill="white")+
  theme_classic()+
  annotate("label",x=pgx,y=pgy,label=pgy)
p3

Upvotes: 0

Related Questions