EntryLevelR - 1 year ago 59

R Question

I am going to use a dataset and plot that came from a previous problem (Here):

`dat <- read.table(text = " Division Year OperatingIncome`

1 A 2012 11460

2 B 2012 7431

3 C 2012 -8121

4 D 2012 15719

5 E 2012 364

6 A 2011 12211

7 B 2011 6290

8 C 2011 -2657

9 D 2011 14657

10 E 2011 1257

11 A 2010 12895

12 B 2010 5381

13 C 2010 -2408

14 D 2010 11849

15 E 2010 517",header = TRUE,sep = "",row.names = 1)

dat1 <- subset(dat,OperatingIncome >= 0)

dat2 <- subset(dat,OperatingIncome < 0)

ggplot() +

geom_bar(data = dat1, aes(x=Year, y=OperatingIncome, fill=Division),stat = "identity") +

geom_bar(data = dat2, aes(x=Year, y=OperatingIncome, fill=Division),stat = "identity") +

scale_fill_brewer(type = "seq", palette = 1)

It includes the following plot, which is where my question comes in:

I have seen this question asked in terms of dual y-axis for different scales (on opposite sides), but I specifically want this on the same y-axis. Appreciate any help - I also would prefer to use ggplot2 for this problem, if possible.

Answer Source

You can use `annotate`

to add labels for negative and positive income. To add text outside the plot panel, you'll need to turn off clipping. Below are examples of adding text both inside and outside the plot panel:

```
# Plot
p = ggplot() +
geom_bar(data = dat1, aes(x=Year, y=OperatingIncome, fill=Division),stat = "identity") +
geom_bar(data = dat2, aes(x=Year, y=OperatingIncome, fill=Division),stat = "identity") +
scale_fill_brewer(type = "seq", palette = 1) +
geom_hline(yintercept=0, lwd=0.3, colour="grey20") +
scale_x_continuous(breaks=sort(unique(dat$Year))) +
theme_bw()
# Annotate inside plot area
p + coord_cartesian(xlim=range(dat$Year) + c(-0.45,0.4)) +
annotate(min(dat$Year) - 0.53 , y=c(-5000,5000), label=c("Negative Income","Positive Income"),
geom="text", angle=90, hjust=0.5, size=3, colour=c("red","blue"))
```

```
# Annotate outside plot area by turning off clipping
pp = p + coord_cartesian(xlim=range(dat$Year) + c(-0.4,0.4)) +
annotate(min(dat$Year) - 0.9, y=c(-6000,10000), label=c("Negative Income","Positive Income"),
geom="text", angle=90, hjust=0.5, size=4, colour=c("red","blue")) +
labs(y="")
pp <- ggplot_gtable(ggplot_build(pp))
pp$layout$clip <- "off"
grid.draw(pp)
```

You can also use `cowplot`

as suggested by @Gregor. I haven't tried this before, so maybe there's a better approach than what I've done below, but it looks like you have to use viewport coordinates, rather than data coordinates, to place the annotations.

```
# Use cowplot
library(cowplot)
ggdraw() +
draw_plot(p + labs(y=""), 0,0,1,1) +
draw_label("Positive Income", x=0.01, y = 0.5, col="blue", size = 10, angle=90) +
draw_label("Negative Income", x=0.01, y = 0.15, col="red", size = 10, angle=90)
```

I realize the data in the question is just for illustration, but for data like this, a line plot might prove easier to understand:

```
library(dplyr)
ggplot(dat, aes(x=Year, y=OperatingIncome, color=Division)) +
geom_hline(yintercept=0, lwd=0.3, colour="grey50") +
geom_line(position=position_dodge(0.2), alpha=0.5) +
geom_text(aes(label=Division), position=position_dodge(0.2), show.legend=FALSE) +
scale_x_continuous(breaks=sort(unique(dat$Year))) +
theme_bw() +
guides(colour=FALSE) +
geom_line(data=dat %>% group_by(Year) %>% summarise(Net=sum(OperatingIncome), Division=NA),
aes(x=Year, y=Net), alpha=0.4) +
geom_text(data=dat %>% group_by(Year) %>% summarise(Net=sum(OperatingIncome), Division=NA),
aes(x=Year, y=Net, label="Net"), colour="black")
```

Or, if a bar plot is required, maybe something like this:

```
ggplot() +
geom_bar(data = dat %>% arrange(OperatingIncome) %>%
mutate(Division=factor(Division,levels=unique(Division))),
aes(x=Year, y=OperatingIncome, fill=Division),
stat="identity", position="dodge") +
geom_hline(yintercept=0, lwd=0.3, colour="grey20") +
theme_bw()
```