Skip to content

Commit 5e29f33

Browse files
authored
TLC for polar coordinates: coord_radial() (#5334)
* allow alignment of upside-down labels * allow alignment of upside-down labels * Allow `angle` to be a waiver * First implementation of guide_axis_theta * Add theta/r to available aes * theta guide refuses regular positions * Don't set labels to NULL when guide cannot be found * opposite_position helper * Fallback for regular positions * Simplify tickmarks * regular axis sets opposite aesthetic * accommodate secondary theta scale * First implementation of coord_polar2 * Polishes * Write tests * update minor ticks implementation * Rename file * rename coord_polar2 -> coord_radial * unify helpers * document * Add theta guide topic * Drop minor ticks example * vectorise `rotate_just()` * Don't `Map()` labels * accept snapshot * Clean up references to CoordPolar2 * comments and remove return statements * add news bullet
1 parent 851233f commit 5e29f33

27 files changed

+1998
-212
lines changed

DESCRIPTION

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ Collate:
115115
'coord-munch.R'
116116
'coord-polar.R'
117117
'coord-quickmap.R'
118+
'coord-radial.R'
118119
'coord-sf.R'
119120
'coord-transform.R'
120121
'data.R'
@@ -174,6 +175,7 @@ Collate:
174175
'grouping.R'
175176
'guide-.R'
176177
'guide-axis.R'
178+
'guide-axis-theta.R'
177179
'guide-legend.R'
178180
'guide-bins.R'
179181
'guide-colorbar.R'

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ export(CoordFlip)
157157
export(CoordMap)
158158
export(CoordPolar)
159159
export(CoordQuickmap)
160+
export(CoordRadial)
160161
export(CoordSf)
161162
export(CoordTrans)
162163
export(Facet)
@@ -302,6 +303,7 @@ export(coord_map)
302303
export(coord_munch)
303304
export(coord_polar)
304305
export(coord_quickmap)
306+
export(coord_radial)
305307
export(coord_sf)
306308
export(coord_trans)
307309
export(cut_interval)
@@ -418,6 +420,7 @@ export(ggproto_parent)
418420
export(ggsave)
419421
export(ggtitle)
420422
export(guide_axis)
423+
export(guide_axis_theta)
421424
export(guide_bins)
422425
export(guide_colorbar)
423426
export(guide_colorsteps)

NEWS.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# ggplot2 (development version)
22

3+
* `coord_radial()` is a successor to `coord_polar()` with more customisation
4+
options. `coord_radial()` can:
5+
6+
* integrate with the new guide system via a dedicated `guide_axis_theta()` to
7+
display the angle coordinate.
8+
* in addition to drawing full circles, also draw circle sectors by using the
9+
`end` argument.
10+
* avoid data vanishing in the center of the plot by setting the `donut`
11+
argument.
12+
* adjust the `angle` aesthetic of layers, such as `geom_text()`, to align
13+
with the coordinate system using the `rotate_angle` argument.
14+
315
* By default, `guide_legend()` now only draws a key glyph for a layer when
416
the value is is the layer's data. To revert to the old behaviour, you
517
can still set `show.legend = c({aesthetic} = TRUE)` (@teunbrand, #3648).

R/coord-polar.R

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#' Polar coordinates
22
#'
33
#' The polar coordinate system is most commonly used for pie charts, which
4-
#' are a stacked bar chart in polar coordinates.
4+
#' are a stacked bar chart in polar coordinates. `coord_radial()` has extended
5+
#' options.
56
#'
67
#' @param theta variable to map angle to (`x` or `y`)
78
#' @param start Offset of starting point from 12 o'clock in radians. Offset
@@ -80,12 +81,14 @@ CoordPolar <- ggproto("CoordPolar", Coord,
8081
aspect = function(details) 1,
8182

8283
distance = function(self, x, y, details) {
84+
arc <- self$start + c(0, 2 * pi)
85+
dir <- self$direction
8386
if (self$theta == "x") {
8487
r <- rescale(y, from = details$r.range)
85-
theta <- theta_rescale_no_clip(self, x, details)
88+
theta <- theta_rescale_no_clip(x, details$theta.range, arc, dir)
8689
} else {
8790
r <- rescale(x, from = details$r.range)
88-
theta <- theta_rescale_no_clip(self, y, details)
91+
theta <- theta_rescale_no_clip(y, details$theta.range, arc, dir)
8992
}
9093

9194
dist_polar(r, theta)
@@ -163,10 +166,12 @@ CoordPolar <- ggproto("CoordPolar", Coord,
163166
},
164167

165168
transform = function(self, data, panel_params) {
169+
arc <- self$start + c(0, 2 * pi)
170+
dir <- self$direction
166171
data <- rename_data(self, data)
167172

168-
data$r <- r_rescale(self, data$r, panel_params$r.range)
169-
data$theta <- theta_rescale(self, data$theta, panel_params)
173+
data$r <- r_rescale(data$r, panel_params$r.range)
174+
data$theta <- theta_rescale(data$theta, panel_params$theta.range, arc, dir)
170175
data$x <- data$r * sin(data$theta) + 0.5
171176
data$y <- data$r * cos(data$theta) + 0.5
172177

@@ -176,11 +181,10 @@ CoordPolar <- ggproto("CoordPolar", Coord,
176181
render_axis_v = function(self, panel_params, theme) {
177182
arrange <- panel_params$r.arrange %||% c("primary", "secondary")
178183

179-
x <- r_rescale(self, panel_params$r.major, panel_params$r.range) + 0.5
184+
x <- r_rescale(panel_params$r.major, panel_params$r.range) + 0.5
180185
panel_params$r.major <- x
181186
if (!is.null(panel_params$r.sec.major)) {
182187
panel_params$r.sec.major <- r_rescale(
183-
self,
184188
panel_params$r.sec.major,
185189
panel_params$r.sec.range
186190
) + 0.5
@@ -201,14 +205,16 @@ CoordPolar <- ggproto("CoordPolar", Coord,
201205

202206
render_bg = function(self, panel_params, theme) {
203207
panel_params <- rename_data(self, panel_params)
208+
arc <- self$start + c(0, 2 * pi)
209+
dir <- self$direction
204210

205211
theta <- if (length(panel_params$theta.major) > 0)
206-
theta_rescale(self, panel_params$theta.major, panel_params)
212+
theta_rescale(panel_params$theta.major, panel_params$theta.range, arc, dir)
207213
thetamin <- if (length(panel_params$theta.minor) > 0)
208-
theta_rescale(self, panel_params$theta.minor, panel_params)
214+
theta_rescale(panel_params$theta.minor, panel_params$theta.range, arc, dir)
209215
thetafine <- seq(0, 2 * pi, length.out = 100)
210216

211-
rfine <- c(r_rescale(self, panel_params$r.major, panel_params$r.range), 0.45)
217+
rfine <- c(r_rescale(panel_params$r.major, panel_params$r.range), 0.45)
212218

213219
# This gets the proper theme element for theta and r grid lines:
214220
# panel.grid.major.x or .y
@@ -247,8 +253,10 @@ CoordPolar <- ggproto("CoordPolar", Coord,
247253
if (is.null(panel_params$theta.major)) {
248254
return(element_render(theme, "panel.border"))
249255
}
256+
arc <- self$start + c(0, 2 * pi)
257+
dir <- self$direction
250258

251-
theta <- theta_rescale(self, panel_params$theta.major, panel_params)
259+
theta <- theta_rescale(panel_params$theta.major, panel_params$theta.range, arc, dir)
252260
labels <- panel_params$theta.labels
253261

254262
# Combine the two ends of the scale if they are close
@@ -305,18 +313,16 @@ rename_data <- function(coord, data) {
305313
}
306314
}
307315

308-
theta_rescale_no_clip <- function(coord, x, panel_params) {
309-
rotate <- function(x) (x + coord$start) * coord$direction
310-
rotate(rescale(x, c(0, 2 * pi), panel_params$theta.range))
316+
theta_rescale_no_clip <- function(x, range, arc = c(0, 2 * pi), direction = 1) {
317+
rescale(x, to = arc, from = range) * direction
311318
}
312319

313-
theta_rescale <- function(coord, x, panel_params) {
314-
x <- squish_infinite(x, panel_params$theta.range)
315-
rotate <- function(x) (x + coord$start) %% (2 * pi) * coord$direction
316-
rotate(rescale(x, c(0, 2 * pi), panel_params$theta.range))
320+
theta_rescale <- function(x, range, arc = c(0, 2 * pi), direction = 1) {
321+
x <- squish_infinite(x, range)
322+
rescale(x, to = arc, from = range) %% (2 * pi) * direction
317323
}
318324

319-
r_rescale <- function(coord, x, range) {
325+
r_rescale <- function(x, range, donut = c(0, 0.4)) {
320326
x <- squish_infinite(x, range)
321-
rescale(x, c(0, 0.4), range)
327+
rescale(x, donut, range)
322328
}

0 commit comments

Comments
 (0)