Skip to content

Commit 3ea5596

Browse files
author
Lindsay Carr
committed
callouts handling multiple angles
1 parent cb9c16c commit 3ea5596

File tree

1 file changed

+51
-22
lines changed

1 file changed

+51
-22
lines changed

R/callouts.R

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,12 @@ callouts.default <- function(x, y=NULL, labels=NA, length=0.1, angle='auto', cex
4949
return()
5050
}
5151

52-
stopifnot(angle=='auto' | (angle >= 0 & angle <= 360))
52+
stopifnot(all(angle=='auto' | is.na(angle) | (angle >= 0 & angle <= 360)))
5353

5454
x <- x[!is.na(labels)]
5555
y <- y[!is.na(labels)]
5656
labels <- labels[!is.na(labels)]
57+
angle <- angle[!is.na(labels)]
5758

5859
# // to do: possibly support angle and length as vectors equal in length to x
5960
x.usr <- par("usr")[c(1,2)]
@@ -66,30 +67,58 @@ callouts.default <- function(x, y=NULL, labels=NA, length=0.1, angle='auto', cex
6667
xrange <- diff(x.usr)
6768
yrange <- diff(y.usr)
6869

69-
if (angle != "auto") {
70-
x1 <- x + length * xrange * cos(2*pi*(angle/360))
71-
y1 <- y + length * yrange * sin(2*pi*(angle/360))
70+
calc_x1y1 <- function(x, y, angle, length, xrange, yrange, x.usr, y.usr){
71+
72+
if (is.na(angle) | angle == "auto") {
73+
auto.angle <- c(30, 330, 150, 210)
74+
x1 <- sapply(auto.angle, function(a) {
75+
x + length * xrange * cos(2*pi*(a/360))
76+
})
77+
y1 <- sapply(auto.angle, function(a) {
78+
y + length * yrange * sin(2*pi*(a/360))
79+
})
80+
81+
good.y1 <- y1 >= y.usr[1] & y1 <= y.usr[2]
82+
good.x1 <- x1 >= x.usr[1] & x1 <= x.usr[2]
83+
good.pt <- good.y1 & good.x1
84+
if (!is.null(dim(good.pt))){
85+
angle <- auto.angle[apply(good.pt, 1, function(z){
86+
ifelse(!any(z), 1, min(which(z)))
87+
})]
88+
} else {
89+
angle <- auto.angle[ifelse(!any(good.pt), 1, min(which(good.pt)))]
90+
}
91+
x1 <- x + length * xrange * cos(2*pi*(angle/360))
92+
y1 <- y + length * yrange * sin(2*pi*(angle/360))
93+
} else {
94+
x1 <- x + length * xrange * cos(2*pi*(angle/360))
95+
y1 <- y + length * yrange * sin(2*pi*(angle/360))
96+
}
97+
98+
return(list(x1 = x1, y1 = y1, angle = angle))
99+
}
100+
101+
if(length(angle) == 1){
102+
x1_y1_angle <- calc_x1y1(x = x, y = y, angle = angle,
103+
length, xrange, yrange, x.usr, y.usr)
104+
x1 <- x1_y1_angle$x1
105+
y1 <- x1_y1_angle$y1
106+
angle <- x1_y1_angle$angle
72107
} else {
73-
auto.angle <- c(30, 330, 150, 210)
74-
x1 <- sapply(auto.angle, function(a) {
75-
x + length * xrange * cos(2*pi*(a/360))
76-
})
77-
y1 <- sapply(auto.angle, function(a) {
78-
y + length * yrange * sin(2*pi*(a/360))
79-
})
108+
stopifnot(length(x)%%length(angle) == 0) #stop if the defined angles aren't a multiple of the points
109+
stopifnot(!is.character(angle)) #stop if it's not a numeric vector ('auto' is not used for the vector)
110+
111+
num_pts <- length(x)
112+
x1 <- vector(mode = "numeric", length = num_pts)
113+
y1 <- vector(mode = "numeric", length = num_pts)
80114

81-
good.y1 <- y1 >= y.usr[1] & y1 <= y.usr[2]
82-
good.x1 <- x1 >= x.usr[1] & x1 <= x.usr[2]
83-
good.pt <- good.y1 & good.x1
84-
if (!is.null(dim(good.pt))){
85-
angle <- auto.angle[apply(good.pt, 1, function(z){
86-
ifelse(!any(z), 1, min(which(z)))
87-
})]
88-
} else {
89-
angle <- auto.angle[ifelse(!any(good.pt), 1, min(which(good.pt)))]
115+
for(r in seq(num_pts)){
116+
x1_y1_angle <- calc_x1y1(x = x[r], y = y[r], angle = angle[r],
117+
length, xrange, yrange, x.usr, y.usr)
118+
x1[r] <- x1_y1_angle$x1
119+
y1[r] <- x1_y1_angle$y1
120+
angle[r] <- x1_y1_angle$angle
90121
}
91-
x1 <- x + length * xrange * cos(2*pi*(angle/360))
92-
y1 <- y + length * yrange * sin(2*pi*(angle/360))
93122
}
94123

95124
pos <- rep(1, length(angle))

0 commit comments

Comments
 (0)