|
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 |
| - } |
27 | 1 |
|
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) { |
29 | 12 |
|
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" |
54 | 15 |
|
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) |
59 | 21 |
|
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) |
71 | 62 | )
|
72 | 63 |
|
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 | + ) |
79 | 72 | }
|
80 | 73 |
|
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 |
108 | 79 | )
|
109 | 80 |
|
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 |
121 | 87 | ),
|
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") |
132 | 101 | )
|
133 | 102 |
|
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 |
140 | 109 | )
|
141 | 110 |
|
142 | 111 | absoluteGrob(
|
143 |
| - gList(line, gt), |
| 112 | + gList(line_grob, gt), |
144 | 113 | width = gtable_width(gt),
|
145 | 114 | height = gtable_height(gt),
|
146 | 115 | vp = justvp
|
|
0 commit comments