Skip to content

Commit 0f929a1

Browse files
authored
Rewrite guide_axis() and rename to draw_axis() (#3349)
2 parents be4d1b1 + 22fc480 commit 0f929a1

File tree

7 files changed

+142
-150
lines changed

7 files changed

+142
-150
lines changed

R/coord-.r

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ expand_default <- function(scale, discrete = c(0, 0.6, 0, 0.6), continuous = c(0
158158
# generated
159159
render_axis <- function(panel_params, axis, scale, position, theme) {
160160
if (axis == "primary") {
161-
guide_axis(panel_params[[paste0(scale, ".major")]], panel_params[[paste0(scale, ".labels")]], position, theme)
161+
draw_axis(panel_params[[paste0(scale, ".major")]], panel_params[[paste0(scale, ".labels")]], position, theme)
162162
} else if (axis == "secondary" && !is.null(panel_params[[paste0(scale, ".sec.major")]])) {
163-
guide_axis(panel_params[[paste0(scale, ".sec.major")]], panel_params[[paste0(scale, ".sec.labels")]], position, theme)
163+
draw_axis(panel_params[[paste0(scale, ".sec.major")]], panel_params[[paste0(scale, ".sec.labels")]], position, theme)
164164
} else {
165165
zeroGrob()
166166
}

R/coord-map.r

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,8 @@ CoordMap <- ggproto("CoordMap", Coord,
308308
pos <- self$transform(x_intercept, panel_params)
309309

310310
axes <- list(
311-
top = guide_axis(pos$x, panel_params$x.labels, "top", theme),
312-
bottom = guide_axis(pos$x, panel_params$x.labels, "bottom", theme)
311+
top = draw_axis(pos$x, panel_params$x.labels, "top", theme),
312+
bottom = draw_axis(pos$x, panel_params$x.labels, "bottom", theme)
313313
)
314314
axes[[which(arrange == "secondary")]] <- zeroGrob()
315315
axes
@@ -332,8 +332,8 @@ CoordMap <- ggproto("CoordMap", Coord,
332332
pos <- self$transform(x_intercept, panel_params)
333333

334334
axes <- list(
335-
left = guide_axis(pos$y, panel_params$y.labels, "left", theme),
336-
right = guide_axis(pos$y, panel_params$y.labels, "right", theme)
335+
left = draw_axis(pos$y, panel_params$y.labels, "left", theme),
336+
right = draw_axis(pos$y, panel_params$y.labels, "right", theme)
337337
)
338338
axes[[which(arrange == "secondary")]] <- zeroGrob()
339339
axes

R/coord-polar.r

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ CoordPolar <- ggproto("CoordPolar", Coord,
190190
render_axis_h = function(panel_params, theme) {
191191
list(
192192
top = zeroGrob(),
193-
bottom = guide_axis(NA, "", "bottom", theme)
193+
bottom = draw_axis(NA, "", "bottom", theme)
194194
)
195195
},
196196

R/coord-sf.R

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,10 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
243243
tick_labels <- c(ticks1$degree_label, ticks2$degree_label)
244244

245245
if (length(tick_positions) > 0) {
246-
top <- guide_axis(
246+
top <- draw_axis(
247247
tick_positions,
248248
tick_labels,
249-
position = "top",
249+
axis_position = "top",
250250
theme = theme
251251
)
252252
} else {
@@ -279,10 +279,10 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
279279
tick_labels <- c(ticks1$degree_label, ticks2$degree_label)
280280

281281
if (length(tick_positions) > 0) {
282-
bottom <- guide_axis(
282+
bottom <- draw_axis(
283283
tick_positions,
284284
tick_labels,
285-
position = "bottom",
285+
axis_position = "bottom",
286286
theme = theme
287287
)
288288
} else {
@@ -321,10 +321,10 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
321321
tick_labels <- c(ticks1$degree_label, ticks2$degree_label)
322322

323323
if (length(tick_positions) > 0) {
324-
right <- guide_axis(
324+
right <- draw_axis(
325325
tick_positions,
326326
tick_labels,
327-
position = "right",
327+
axis_position = "right",
328328
theme = theme
329329
)
330330
} else {
@@ -357,10 +357,10 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
357357
tick_labels <- c(ticks1$degree_label, ticks2$degree_label)
358358

359359
if (length(tick_positions) > 0) {
360-
left <- guide_axis(
360+
left <- draw_axis(
361361
tick_positions,
362362
tick_labels,
363-
position = "left",
363+
axis_position = "left",
364364
theme = theme
365365
)
366366
} else {

R/guides-axis.r

Lines changed: 96 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,146 +1,115 @@
1-
# Grob for axes
2-
#
3-
# @param position of ticks
4-
# @param labels at ticks
5-
# @param position of axis (top, bottom, left or right)
6-
# @param range of data values
7-
guide_axis <- function(at, labels, position = "right", theme) {
8-
line <- switch(position,
9-
top = element_render(theme, "axis.line.x.top", c(0, 1), c(0, 0), id.lengths = 2),
10-
bottom = element_render(theme, "axis.line.x.bottom", c(0, 1), c(1, 1), id.lengths = 2),
11-
right = element_render(theme, "axis.line.y.right", c(0, 0), c(0, 1), id.lengths = 2),
12-
left = element_render(theme, "axis.line.y.left", c(1, 1), c(0, 1), id.lengths = 2)
13-
)
14-
position <- match.arg(position, c("top", "bottom", "right", "left"))
15-
16-
zero <- unit(0, "npc")
17-
one <- unit(1, "npc")
18-
19-
if (length(at) == 0) {
20-
vertical <- position %in% c("left", "right")
21-
return(absoluteGrob(
22-
gList(line),
23-
width = if (vertical) zero else one,
24-
height = if (vertical) one else zero
25-
))
26-
}
271

28-
at <- unit(at, "native")
2+
#' Grob for axes
3+
#'
4+
#' @param break_position position of ticks
5+
#' @param break_labels labels at ticks
6+
#' @param axis_position position of axis (top, bottom, left or right)
7+
#' @param theme A [theme()] object
8+
#'
9+
#' @noRd
10+
#'
11+
draw_axis <- function(break_positions, break_labels, axis_position, theme) {
2912

30-
theme$axis.ticks.length.x.bottom <- with(
31-
theme,
32-
axis.ticks.length.x.bottom %||%
33-
axis.ticks.length.x %||%
34-
axis.ticks.length
35-
)
36-
theme$axis.ticks.length.x.top <- with(
37-
theme,
38-
axis.ticks.length.x.top %||%
39-
axis.ticks.length.x %||%
40-
axis.ticks.length
41-
)
42-
theme$axis.ticks.length.y.left <- with(
43-
theme,
44-
axis.ticks.length.y.left %||%
45-
axis.ticks.length.y %||%
46-
axis.ticks.length
47-
)
48-
theme$axis.ticks.length.y.right <- with(
49-
theme,
50-
axis.ticks.length.y.right %||%
51-
axis.ticks.length.y %||%
52-
axis.ticks.length
53-
)
13+
axis_position <- match.arg(axis_position, c("top", "bottom", "right", "left"))
14+
aesthetic <- if (axis_position %in% c("top", "bottom")) "x" else "y"
5415

55-
label_render <- switch(position,
56-
top = "axis.text.x.top", bottom = "axis.text.x.bottom",
57-
left = "axis.text.y.left", right = "axis.text.y.right"
58-
)
16+
# resolve elements
17+
line_element_name <- paste0("axis.line.", aesthetic, ".", axis_position)
18+
tick_element_name <- paste0("axis.ticks.", aesthetic, ".", axis_position)
19+
tick_length_element_name <- paste0("axis.ticks.length.", aesthetic, ".", axis_position)
20+
label_element_name <- paste0("axis.text.", aesthetic, ".", axis_position)
5921

60-
label_x <- switch(position,
61-
top = ,
62-
bottom = at,
63-
right = theme$axis.ticks.length.y.right,
64-
left = one - theme$axis.ticks.length.y.left
65-
)
66-
label_y <- switch(position,
67-
top = theme$axis.ticks.length.x.top,
68-
bottom = one - theme$axis.ticks.length.x.bottom,
69-
right = ,
70-
left = at
22+
line_element <- calc_element(line_element_name, theme)
23+
tick_element <- calc_element(tick_element_name, theme)
24+
tick_length <- calc_element(tick_length_element_name, theme)
25+
label_element <- calc_element(label_element_name, theme)
26+
27+
# conditionally set parameters that depend on axis orientation
28+
is_vertical <- axis_position %in% c("left", "right")
29+
30+
position_dim <- if (is_vertical) "y" else "x"
31+
non_position_dim <- if (is_vertical) "x" else "y"
32+
position_size <- if (is_vertical) "height" else "width"
33+
non_position_size <- if (is_vertical) "width" else "height"
34+
label_margin_name <- if (is_vertical) "margin_x" else "margin_y"
35+
gtable_element <- if (is_vertical) gtable_row else gtable_col
36+
measure_gtable <- if (is_vertical) gtable_width else gtable_height
37+
measure_labels <- if (is_vertical) grobWidth else grobHeight
38+
39+
# conditionally set parameters that depend on which side of the panel
40+
# the axis is on
41+
is_second <- axis_position %in% c("right", "top")
42+
43+
tick_direction <- if (is_second) 1 else -1
44+
non_position_panel <- if (is_second) unit(0, "npc") else unit(1, "npc")
45+
tick_coordinate_order <- if (is_second) c(2, 1) else c(1, 2)
46+
47+
# conditionally set the gtable ordering
48+
labels_first_gtable <- axis_position %in% c("left", "top") # refers to position in gtable
49+
50+
table_order <- if (labels_first_gtable) c("labels", "ticks") else c("ticks", "labels")
51+
52+
# set common parameters
53+
n_breaks <- length(break_positions)
54+
opposite_positions <- c("top" = "bottom", "bottom" = "top", "right" = "left", "left" = "right")
55+
axis_position_opposite <- unname(opposite_positions[axis_position])
56+
57+
# draw elements
58+
line_grob <- exec(
59+
element_grob, line_element,
60+
!!position_dim := unit(c(0, 1), "npc"),
61+
!!non_position_dim := unit.c(non_position_panel, non_position_panel)
7162
)
7263

73-
if (is.list(labels)) {
74-
if (any(sapply(labels, is.language))) {
75-
labels <- do.call(expression, labels)
76-
} else {
77-
labels <- unlist(labels)
78-
}
64+
if (n_breaks == 0) {
65+
return(
66+
absoluteGrob(
67+
gList(line_grob),
68+
width = grobWidth(line_grob),
69+
height = grobHeight(line_grob)
70+
)
71+
)
7972
}
8073

81-
labels <- switch(position,
82-
top = ,
83-
bottom = element_render(theme, label_render, labels, x = label_x, margin_y = TRUE),
84-
right = ,
85-
left = element_render(theme, label_render, labels, y = label_y, margin_x = TRUE))
86-
87-
88-
89-
nticks <- length(at)
90-
91-
ticks <- switch(position,
92-
top = element_render(theme, "axis.ticks.x.top",
93-
x = rep(at, each = 2),
94-
y = rep(unit.c(zero, theme$axis.ticks.length.x.top), nticks),
95-
id.lengths = rep(2, nticks)),
96-
bottom = element_render(theme, "axis.ticks.x.bottom",
97-
x = rep(at, each = 2),
98-
y = rep(unit.c(one - theme$axis.ticks.length.x.bottom, one), nticks),
99-
id.lengths = rep(2, nticks)),
100-
right = element_render(theme, "axis.ticks.y.right",
101-
x = rep(unit.c(zero, theme$axis.ticks.length.y.right), nticks),
102-
y = rep(at, each = 2),
103-
id.lengths = rep(2, nticks)),
104-
left = element_render(theme, "axis.ticks.y.left",
105-
x = rep(unit.c(one - theme$axis.ticks.length.y.left, one), nticks),
106-
y = rep(at, each = 2),
107-
id.lengths = rep(2, nticks))
74+
labels_grob <- exec(
75+
element_grob, label_element,
76+
!!position_dim := unit(break_positions, "native"),
77+
!!label_margin_name := TRUE,
78+
label = break_labels
10879
)
10980

110-
# Create the gtable for the ticks + labels
111-
gt <- switch(position,
112-
top = gtable_col("axis",
113-
grobs = list(labels, ticks),
114-
width = one,
115-
heights = unit.c(grobHeight(labels), theme$axis.ticks.length.x.top)
116-
),
117-
bottom = gtable_col("axis",
118-
grobs = list(ticks, labels),
119-
width = one,
120-
heights = unit.c(theme$axis.ticks.length.x.bottom, grobHeight(labels))
81+
ticks_grob <- exec(
82+
element_grob, tick_element,
83+
!!position_dim := rep(unit(break_positions, "native"), each = 2),
84+
!!non_position_dim := rep(
85+
unit.c(non_position_panel + (tick_direction * tick_length), non_position_panel)[tick_coordinate_order],
86+
times = n_breaks
12187
),
122-
right = gtable_row("axis",
123-
grobs = list(ticks, labels),
124-
widths = unit.c(theme$axis.ticks.length.y.right, grobWidth(labels)),
125-
height = one
126-
),
127-
left = gtable_row("axis",
128-
grobs = list(labels, ticks),
129-
widths = unit.c(grobWidth(labels), theme$axis.ticks.length.y.left),
130-
height = one
131-
)
88+
id.lengths = rep(2, times = n_breaks)
89+
)
90+
91+
# create gtable
92+
table_order_int <- match(table_order, c("labels", "ticks"))
93+
non_position_sizes <- paste0(non_position_size, "s")
94+
95+
gt <- exec(
96+
gtable_element,
97+
name = "axis",
98+
grobs = list(labels_grob, ticks_grob)[table_order_int],
99+
!!non_position_sizes := unit.c(measure_labels(labels_grob), tick_length)[table_order_int],
100+
!!position_size := unit(1, "npc")
132101
)
133102

134-
# Viewport for justifying the axis grob
135-
justvp <- switch(position,
136-
top = viewport(y = 0, just = "bottom", height = gtable_height(gt)),
137-
bottom = viewport(y = 1, just = "top", height = gtable_height(gt)),
138-
right = viewport(x = 0, just = "left", width = gtable_width(gt)),
139-
left = viewport(x = 1, just = "right", width = gtable_width(gt))
103+
# create viewport
104+
justvp <- exec(
105+
viewport,
106+
!!non_position_dim := non_position_panel,
107+
!!non_position_size := measure_gtable(gt),
108+
just = axis_position_opposite
140109
)
141110

142111
absoluteGrob(
143-
gList(line, gt),
112+
gList(line_grob, gt),
144113
width = gtable_width(gt),
145114
height = gtable_height(gt),
146115
vp = justvp

R/theme.r

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -612,21 +612,38 @@ merge_element.element <- function(new, old) {
612612
new
613613
}
614614

615-
# Combine the properties of two elements
616-
#
617-
# @param e1 An element object
618-
# @param e2 An element object which e1 inherits from
615+
#' Combine the properties of two elements
616+
#'
617+
#' @param e1 An element object
618+
#' @param e2 An element object from which e1 inherits
619+
#'
620+
#' @noRd
621+
#'
619622
combine_elements <- function(e1, e2) {
620623

621624
# If e2 is NULL, nothing to inherit
622-
if (is.null(e2) || inherits(e1, "element_blank")) return(e1)
625+
if (is.null(e2) || inherits(e1, "element_blank")) {
626+
return(e1)
627+
}
628+
623629
# If e1 is NULL inherit everything from e2
624-
if (is.null(e1)) return(e2)
630+
if (is.null(e1)) {
631+
return(e2)
632+
}
633+
634+
# If neither of e1 or e2 are element_* objects, return e1
635+
if (!inherits(e1, "element") && !inherits(e2, "element")) {
636+
return(e1)
637+
}
638+
625639
# If e2 is element_blank, and e1 inherits blank inherit everything from e2,
626640
# otherwise ignore e2
627641
if (inherits(e2, "element_blank")) {
628-
if (e1$inherit.blank) return(e2)
629-
else return(e1)
642+
if (e1$inherit.blank) {
643+
return(e2)
644+
} else {
645+
return(e1)
646+
}
630647
}
631648

632649
# If e1 has any NULL properties, inherit them from e2

tests/testthat/test-theme.r

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,12 @@ test_that("elements can be merged", {
213213
)
214214
})
215215

216+
test_that("theme elements that don't inherit from element can be combined", {
217+
expect_identical(combine_elements(1, NULL), 1)
218+
expect_identical(combine_elements(NULL, 1), 1)
219+
expect_identical(combine_elements(1, 0), 1)
220+
})
221+
216222
test_that("complete plot themes shouldn't inherit from default", {
217223
default_theme <- theme_gray() + theme(axis.text.x = element_text(colour = "red"))
218224
base <- qplot(1, 1)

0 commit comments

Comments
 (0)