15

I'm plotting a large polar graph/pie chart of 40+ bars/rings with ggplot2 (using geom_bar and coord_polar(theta="y") ), and am finding that the y axis plot compression causes the innermost rings to have very poor polygon resolution.

Anyone know of a way to bump up the polygonal resolution?

df <- data.frame(
  x = sort(sample(1:40, 400, replace=TRUE)), 
  y = sample(0:9, 400, replace=TRUE)
)


ggplot(df, aes(x=x, y=y, fill=y)) + 
  geom_bar(stat='identity', position="fill") + 
  coord_polar(theta="y") + 
  scale_fill_continuous(low="blue", high="pink")

enter image description here

This is what I mean by the geometric resolution I'm trying to achieve. I managed this by plotting just 5 levels.

enter image description here

When I increase to 40 levels the central polygons lose their smoothness and become too jagged, like this:

enter image description here

geotheory
  • 22,624
  • 29
  • 119
  • 196
  • 2
    I'll upvote you if you stick in your code and some example data. – James Feb 28 '12 at 13:51
  • 1
    And I might even downvote if you don't post reproducible code and sample data. See http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example for tips on asking a great question. – Andrie Feb 28 '12 at 14:17
  • Cheers! This code reproduces the problem. If you save to PDF and zoom into the centre you'll see what I mean. `df <- data.frame( x = sort(sample(1:40, 400, replace=TRUE)), ` `y = sample(0:9, 400, replace=TRUE))` `ggplot(df, aes(x=x, y=y, fill=y)) + ` `geom_bar(stat='identity', position="fill") + ` `coord_polar(theta="y") + ` `scale_fill_continuous(low="blue", high="pink")` – geotheory Feb 28 '12 at 14:40
  • OK, so the real problem is not in your code, it is with getting more resolution in your pdf. What is your code for saving to pdf? You can adjust the resolution there. – Andrie Feb 28 '12 at 14:45
  • Thanks for the suggestion, but I've just tried increasing PDF document size but with the same result. Not sure how to increase PDF resolution, but anyway it outputs this kind of plot to vector so I don't see how it could make a difference. I'm using `pdf(file="filname.pdf", width=12, height=12) [plot code] dev.off()` – geotheory Feb 28 '12 at 15:05
  • 1
    I don't think this is an image resolution issue. I think the innermost rings are simply being drawn with too few polygonal segments. It's possible this is a bug. You might have more luck asking about this on the ggplot2 mailing list. – joran Feb 28 '12 at 16:17
  • 3
    This is because `coord_polar` determines the number of division by the physical length of the path. If the length of the circumference is short, the number of division is small. In most cases, this would be ok, but as you say there will be the case where you need the larger number of division. – kohske Feb 28 '12 at 16:44
  • Good advice thanks - I'll post back if I find a solution – geotheory Feb 28 '12 at 16:56
  • This was what I wanted to achieve: http://geotheorydotorg.files.wordpress.com/2012/03/pi-circle.png – geotheory Oct 04 '12 at 12:48

2 Answers2

10

The issue is with the ggplot2:::coord_munch function, which has an argument segment_length with a default value of 0.01:

https://github.com/hadley/ggplot2/blob/master/R/coord-munch.r

I don't think there's any place to pass in arguments that will make it down to coord_munch's segment_length argument. One way to deal with it for now is to replace coord_munch with a wrapper function that has a different default value for segment_length.

# Save the original version of coord_munch
coord_munch_old <- ggplot2:::coord_munch

# Make a wrapper function that has a different default for segment_length
coord_munch_new <- function(coord, data, range, segment_length = 1/500) {
  coord_munch_old(coord, data, range, segment_length)
}
# Make the new function run in the same environment
environment(coord_munch_new) <- environment(ggplot2:::coord_munch)

# Replace ggplot2:::coord_munch with coord_munch_new
assignInNamespace("coord_munch", coord_munch_new, ns="ggplot2")

Once that's done, you can run the example again:

set.seed(123)
df <- data.frame(
  x = sort(sample(1:40, 400, replace=TRUE)), 
  y = sample(0:9, 400, replace=TRUE)
)

pdf('polar.pdf')
ggplot(df, aes(x=x, y=y, fill=y)) + 
  geom_bar(stat='identity', position="fill") + 
  coord_polar(theta="y") + 
  scale_fill_continuous(low="blue", high="pink")
dev.off()

Assigning values in a namespace is only supposed to be used for development purposes, so this is not a good long-term solution.

wch
  • 4,069
  • 2
  • 28
  • 36
  • 1
    I believe this only works with version 0.9.0 or higher; version 0.8.9 does not have `coord_munch` – Brian Diggs Feb 28 '12 at 21:46
  • Works great, thanks so much. I had to add `is_closed=False` to the paramaters for `munch`'ing. Works great for more than a decade :-) – JZL003 Aug 25 '23 at 20:24
0

In addition to wch's correct diagnosis and workaround above, an alternative workaround is suggested by Jean-Olivier via the ggplot2 Google Group:

Instead, changing the data to increase the coordinate values in the data space, by doing something like this:

ggplot(df, aes(x=x+100, y=y, fill=y)) +
 geom_bar(stat='identity', position="fill") +
 coord_polar(theta="y") +
 scale_fill_continuous(low="blue", high="pink")

Thanks everyone.

geotheory
  • 22,624
  • 29
  • 119
  • 196