I'm trying to produce a facetted pie-chart with ggplot and facing problems with placing text in the middle of each slice:
dat = read.table(text = "Channel Volume Cnt
AGENT high 8344
AGENT medium 5448
AGENT low 23823
KIOSK high 19275
KIOSK medium 13554
KIOSK low 38293", header=TRUE)
vis = ggplot(data=dat, aes(x=factor(1), y=Cnt, fill=Volume)) +
geom_bar(stat="identity", position="fill") +
coord_polar(theta="y") +
facet_grid(Channel~.) +
geom_text(aes(x=factor(1), y=Cnt, label=Cnt, ymax=Cnt),
position=position_fill(width=1))
The output:
What parameters of geom_text
should be adjusted in order to place numerical labels in the middle of piechart slices?
Related question is Pie plot getting its text on top of each other but it doesn't handle case with facet.
UPDATE: following Paul Hiemstra advice and approach in the question above I changed code as follows:
---> pie_text = dat$Cnt/2 + c(0,cumsum(dat$Cnt)[-length(dat$Cnt)])
vis = ggplot(data=dat, aes(x=factor(1), y=Cnt, fill=Volume)) +
geom_bar(stat="identity", position="fill") +
coord_polar(theta="y") +
facet_grid(Channel~.) +
geom_text(aes(x=factor(1),
---> y=pie_text,
label=Cnt, ymax=Cnt), position=position_fill(width=1))
As I expected tweaking text coordiantes is absolute but it needs be within facet data:
NEW ANSWER: With the introduction of ggplot2 v2.2.0,
position_stack()
can be used to position the labels without the need to calculate a position variable first. The following code will give you the same result as the old answer:To remove "hollow" center, adapt the code to:
OLD ANSWER: The solution to this problem is creating a position variable, which can be done quite easily with base R or with the data.table, plyr or dplyr packages:
Step 1: Creating the position variable for each Channel
Step 2: Creating the facetted plot
The result:
I would like to speak out against the conventional way of making pies in ggplot2, which is to draw a stacked barplot in polar coordinates. While I appreciate the mathematical elegance of that approach, it does cause all sorts of headaches when the plot doesn't look quite the way it's supposed to. In particular, precisely adjusting the size of the pie can be difficult. (If you don't know what I mean, try to make a pie chart that extends all the way to the edge of the plot panel.)
I prefer drawing pies in a normal cartesian coordinate system, using
geom_arc_bar()
from ggforce. It requires a little bit of extra work on the front end, because we have to calculate angles ourselves, but that's easy and the level of control we get as a result is more than worth it. I've used this approach in previous answers here and here.The data (from the question):
The pie-drawing code:
To show why I think this this approach is so much more powerful than the conventional (
coord_polar()
) approach, let's say we want the labels on the outside of the pie rather than inside. This creates a couple of problems, such as we will have to adjusthjust
andvjust
depending on the side of the pie a label falls, and also we will have to make the plot panel wider than high to make space for the labels on the side without generating excessive space above and below. Solving these problems in the polar coordinate approach is not fun, but it's trivial in the cartesian coordinates:Following answer is partial, clunky and I won't accept it. The hope is that it will solicit better solution.
It produces following chart:
As you noticed I can't move labels for green (low).
To tweak the position of the label text relative to the coordinate, you can use the
vjust
andhjust
arguments ofgeom_text
. This will determine the position of all labels simultaneously, so this might not be what you need.Alternatively, you could tweak the coordinate of the label. Define a new
data.frame
where you average theCnt
coordinate (label_x[i] = Cnt[i+1] + Cnt[i]
) to position the label in the center of that particular pie. Just pass this newdata.frame
togeom_text
in replacement of the originaldata.frame
.In addition, piecharts have some visual interpretation flaws. In general I would not use them, especially where good alternatives exist, e.g. a dotplot:
For example, from this plot it is obvious that
Cnt
is higher for Kiosk than for Agent, this information is lost in the piechart.