简体   繁体   中英

How to wrap around the polar coordinates in ggplot2 with geom_rect?

I am having trouble with cutting off the boundaries of an object with polar coordinates. I am trying to plot the mean angles with a bounding rectangle showing the standard deviation of all the angles measured. However, because of the nature of circular coordinates, I am running into trouble where the sd is outside of the limits of the polar coordinates and I am having trouble getting it to appear. I have read this similar question , but for various reasons I need this data to be in a polar coordinate system, so I haven't had success in applying the geom_arc_bar solution from that question to my problem.

Here is a subset of the data:

test <- structure(
  list(group = structure(1:4, .Label = c("1", "2", "3", "4"),class = "factor"), 
       mang = c(100.346364791691, 61.6459563812475, -93.4372656495579, -150.308914571739), 
       mdisp = c(22.1760257078993, 16.1971728831951, 13.7224045052927, 16.3229969619169), 
       sd = c(88.7601477929364, 115.305326107927, 89.1303441207914, 75.4004747324955)), 
  row.names = c(NA, -4L),
  class = c("tbl_df", "tbl", "data.frame"), 
  .Names = c("group", "mang", "mdisp", "sd"))

Code:

library(tidyverse)
ggplot(test)+
  geom_rect(aes(xmin = mang - sd, xmax = mang + sd, ymin = 0,ymax = mdisp, fill = group))+
  geom_segment(aes(x = mang, y = 0, xend = mang, yend = mdisp))+
  scale_x_continuous(breaks = c(-90, 0, 90, 180, 270, 360), limits = c(-180, 180))+
  coord_polar(start = 2*pi, direction = -1)+
  facet_grid(~group)+
  ggtitle("polar plots with sd")

Which gives this graph:

具有正确比例的图

If I comment out the line setting the x-scale #scale_x_continuous(breaks=c(-90,0,90, 180, 270, 360),limits=c(-180, 180)) these rectangles will appear where I want them to as in this graph, but the scales are wrong:

测试没有规模

How to get both the scales and the bounding rectangles to appear on the same plot?

One way is to calculate the wrap around amount yourself & define separate rectangles. For example:

test2 <- test %>%
  mutate(xmin = mang - sd,
         xmax = mang + sd) %>%
  mutate(xmin1 = pmax(xmin, -180),
         xmax1 = pmin(xmax, 180),
         xmin2 = ifelse(xmin < -180, 2 * 180 + xmin, -180),
         xmax2 = ifelse(xmax > 180, 2 * -180 + xmax, 180))

> test2
# A tibble: 4 x 10
  group   mang mdisp    sd   xmin    xmax  xmin1   xmax1 xmin2 xmax2
  <fct>  <dbl> <dbl> <dbl>  <dbl>   <dbl>  <dbl>   <dbl> <dbl> <dbl>
1 1      100.   22.2  88.8   11.6  189.     11.6  180    -180  -171.
2 2       61.6  16.2 115.   -53.7  177.    -53.7  177.   -180   180 
3 3      -93.4  13.7  89.1 -183.    -4.31 -180     -4.31  177.  180 
4 4     -150.   16.3  75.4 -226.   -74.9  -180    -74.9   134.  180 

Plot:

ggplot(test2) +
  geom_rect(aes(xmin = xmin1, xmax = xmax1, ymin = 0, ymax = mdisp, fill = group)) +
  geom_rect(aes(xmin = xmin2, xmax = xmax2, ymin = 0, ymax = mdisp, fill = group)) +
  geom_segment(aes(x = mang, y = 0, xend = mang, yend = mdisp)) +
  scale_x_continuous(breaks = seq(-90, 180, 90), limits = c(-180, 180)) +
  coord_polar(start = 2 * pi, direction = -1) +
  facet_grid(~ group)

阴谋

I ended up getting a non-elegant but accurate version of these plots to work by combining my previous answer and the solution Z.lin gave. There might be a better way to do it, but I don't have that many categories in my actual data, so it's reasonable to do it manually like this.

test3<-filter(test2, group!="2") # filter out the one that doesn't work

ggplot(test)+
  geom_rect(aes(xmin = mang - sd, xmax = mang + sd, ymin = 0,ymax = mdisp))+
  geom_rect(data=test3, aes(xmin = xmin1, xmax = xmax1, ymin = 0, ymax = mdisp)) +
  geom_rect(data=test3, aes(xmin = xmin2, xmax = xmax2, ymin = 0, ymax = mdisp)) +
  geom_segment(aes(x = mang, y = 0, xend = mang, yend = mdisp), color=group)+
  scale_x_continuous(breaks = c(-90, 0, 90, 180, 270, 360), limits = c(-180, 180))+
  coord_polar(start = 2*pi, direction = -1)+
  facet_grid(~group)+
  ggtitle("polar plots with sd")

And this gave me this figure which was what I was looking for with the correct rectangles带有 sd 的极坐标图

Thanks.

A more general solution that works without excluding group 2. It is a corrected version of answer 1. The following function can be used to do the correct wrapping.

wrap_polar_seg <- function(x, w) {
  a1 = x-w/2
  a2 = x+w/2
  u = matrix(nrow=length(x),ncol=5)
  u[,5] = ifelse(a1 < 0, ifelse(a1 > -180 & a2 > -180, 0,1), 
                         ifelse(a2 < 180 & a2 < 180,0,2)) 
  u[,1] = ifelse(u[,5] == 2,a1,     ifelse(u[,5]==1,360+a1,a1))
  u[,2] = ifelse(u[,5] == 2,180,    ifelse(u[,5]==1,180,   a2))
  u[,3] = ifelse(u[,5] == 2,a2-360, ifelse(u[,5]==1,a2,    a1))
  u[,4] = ifelse(u[,5] == 2,-180,   ifelse(u[,5]==1,-180,  a2))
  u
}  

Applying this code to current problem

test3 = test
k = wrap_polar_seg(test$mang,test$sd*2)
test3$xmin1 = k[,1]
test3$xmax1 = k[,2]
test3$xmin2 = k[,3]
test3$xmax2 = k[,4]


ggplot(test3) +
  geom_rect(aes(xmin = xmin1, xmax = xmax1, ymin = 0, ymax = mdisp), fill = "gray") +
  geom_rect(aes(xmin = xmin2, xmax = xmax2, ymin = 0, ymax = mdisp), fill = "gray") +
  geom_segment(aes(x = mang, y = 0, xend = mang, yend = mdisp,color=group),size=2) +
  scale_x_continuous(breaks = seq(-90, 180, 90), limits = c(-180, 180)) +
  coord_polar(start = 2 * pi, direction = -1) +
  facet_grid(~ group) +
  theme_bw()


The result is:

plot resulting from the code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM