Reputation: 175
I have the data like below. I am trying to create a single bar chart to show the revenue against the goals.
The black bar indicates the current revenue from the first day of 2015.It is nearly real time data and updated daily or every 6 hours. So the black bar is increasing every day. Red bar indicates the amount of revenue to reach the first goal.The white bar indicates the amount of revenue to reach the second goal.
My question is how can I create the the labels to show the values of each bar like attached picture below. And the triangle on each bar is required. Thanks in advanced!df = data.frame(revenue = runif(306, min = 10, max = 20),
day = seq(1,306,1),
year = rep(2015,306))
df = aggregate(revenue~year, data = df, sum)
b1 = 5200
b2 = 6000
df = cbind(df,b1,b2)
df$year = as.factor(df$year)
ggplot(df, aes(year,b2)) +
geom_bar(fill = "white", width=.1, stat="identity")+
geom_bar(aes(year, b1), fill = "red", width=.1, stat="identity")+
geom_bar(aes(year, revenue), fill = "black",
width=.1, stat="identity") +
coord_flip()
I did some adjustments on the original code and try to add triangle in the plot by using geom_point()
. But I am not able to move the triangle under the bar. Any ideas?
df = data.frame(year = factor(2015),revenue = 4300, goal1 = 5200, goal2 = 6000)
df2 = data.frame(year=factor(2015),label=c("revenue","goal1","goal2"),value=c(4300,5200,6000))
ggplot(df, aes(year,goal2)) +
geom_bar(fill = "white", width=.1, stat="identity")+
geom_bar(aes(year, goal1), fill = "blue", width=.1, stat="identity")+
geom_bar(aes(year, revenue), fill = "red",
width=.1, stat="identity") +
geom_text(data = df2, aes(year,value, label=paste(label,"\n",value),
vjust=ifelse(label=="revenue",2,-1)), size = 5) +
geom_errorbar(aes(yintercept = goal1, ymax=goal1, ymin=goal1),
color = "black", size = 1, width=.1)+
geom_point(data = df, aes(year, revenue), shape = 17, size = 5, col = "firebrick4", bg = "firebrick4") + coord_flip()
Upvotes: 1
Views: 923
Reputation: 42912
First, you need to transpose your data, to make "goals" and "revenue" (which share a type (money) and a dimension (x) on the plot) into a single column, and their labels (annotations) into another column:
df2 = data.frame(year=factor(2015),
label=c("revenue","goal 1","goal 2"),
value=c(4533,5200,6000))
in order for the bars to overlap in the correct order, you originally added the geom_bars in that specific order (which will fail if your values aren't in the correct order). Now they will be plotted by a single call to geom_bar, and correct layering can be addressed by re-ordering the label factor and arranging the data according to the value:
ggplot(arrange(mutate(df2,label=reorder(label,value,sum)),-value)) +
scale_fill_manual(values=c(revenue="red",`goal 1`="blue",`goal 2`="white"),guide="none") +
geom_bar(aes(year, value, fill=label),stat="identity", position="identity",alpha=1,width=0.1) +
geom_text(aes(year,value, label=paste(label,"\n",value), vjust=ifelse(label=="revenue",2,-1))) +
coord_flip()
and adding geom_text to label them. I just chose random colors, sorry.
Notes:
vjust
is rather annoying to use, it's measured in terms of multiples of the height of the display box of the text. Just tweak it until it's correct. Possibly use two geom_texts to output the label and value.
The triangles can be added using geom_text or geom_point as required.
Alternatively, discard the automatic x axis labels and use the x axis to display the actual values. This would be in line with tuftes's recommendations. You may need to deal with the overlapping label problem if revenue is close to one of the goals (base plot deals with this but ggplot does not).
OP requested help positioning pointer triangles. Here's a possible solution using custom position adjustment. I have also set it so revenue is always on top (using new zorder column).
df2 = data.frame(year=factor(2015),label=c("revenue","goal 1","goal 2"),value=c(4533,5200,6000),zorder=c(3,2,1))
df2.ordered=arrange(mutate(df2,label=reorder(label,zorder,sum)),zorder)
ggplot(df2.ordered) + aes(x=year, y=value, fill=label) +
scale_fill_manual(values=c(revenue="red",`goal 1`="blue",`goal 2`="white"),guide="none") +
geom_bar(stat="identity", position="identity",alpha=1,width=0.1) +
geom_text(aes(label=paste(label,"\n",value), vjust=ifelse(label=="revenue",2,-1))) +
geom_point(aes(x=year, y=value, fill=2), hjust=100, fill= 1, shape = 17, size = 5, hjust=-300, col = "firebrick4",
bg = "firebrick4", position=c(adjust=function(data)mutate(data,x=x-0.05))) +
coord_flip()
The ticks are not on the same side as the text in this example - please fix this yourself.
Upvotes: 2