1
1
# ' Nudge labels to new positions
2
2
# '
3
- # ' \code{position_nudge_to()} is generally useful for adjusting the position of
4
- # ' labels or text, both on a discrete or continuous scale.
5
- # ' \code{position_nudge_to()} differs from \code{\link[ggplot2]{position_nudge}}
6
- # ' in that the coordinates of the new position are given directly, rather than
7
- # ' as a displacement from the original location. It optionally sets an even
8
- # ' distance among positions. As other position functions in this package, it
9
- # ' preserves the original position to allow the text to be linked back to its
10
- # ' original position with a segment or arrow.
3
+ # ' \code{position_dodgenudge_to()} is generally useful for adjusting the
4
+ # ' position of labels or text, both on a discrete or continuous scale.
5
+ # ' \code{position_dodgenudge_to()} and \code{position_nudge_to()} differ from
6
+ # ' \code{\link[ggplot2]{position_nudge}} in that the coordinates of the new
7
+ # ' position are given directly, rather than as a displacement from the original
8
+ # ' location. It optionally sets an even spacing among positions within a range.
9
+ # ' In \code{position_dodgenudge_to()} this nudging can be combined with dodging.
10
+ # ' As with other position functions in this package, the original positions are
11
+ # ' preserved to allow the text or labels to be linked back to their original
12
+ # ' position with a segment or arrow.
11
13
# '
12
14
# ' @family position adjustments
13
15
# '
16
+ # ' @param width Dodging width, when different to the width of the individual
17
+ # ' elements. This is useful when you want to align narrow geoms with wider
18
+ # ' geoms. See the examples.
19
+ # ' @param preserve Should dodging preserve the total width of all elements at a
20
+ # ' position, or the width of a single element?.
14
21
# ' @param x,y Coordinates of the destination position. A vector of mode
15
22
# ' \code{numeric}, that is extended if needed, to the same length as rows
16
23
# ' there are in \code{data}. The default, \code{NULL}, leaves the original
17
- # ' coordinates unchanged.
24
+ # ' coordinates unchanged after dodging .
18
25
# ' @param x.action,y.action character string, one of \code{"none"}, or
19
26
# ' \code{"spread"}. With \code{"spread"} distributing the positions
20
27
# ' within the range of argument \code{x} or \code{y}, if non-null, or the
23
30
# ' implemented.
24
31
# ' @param x.expansion,y.expansion numeric vectors of length 1 or 2, as a
25
32
# ' fraction of width of the range.
26
- # ' @param kept.origin One of \code{"original"} or \code{"none"}.
33
+ # ' @param kept.origin One of \code{"original"}, \code{"dodged"} or
34
+ # ' \code{"none"}.
27
35
# '
28
36
# ' @details The nudged to \code{x} and/or \code{y} values replace the original ones in
29
- # ' \code{data}, while the original coordinates are returned in \code{x_orig}
30
- # ' and \code{y_orig}. Values supported are those of \emph{mode} numeric,
31
- # ' thus including dates and times.
37
+ # ' \code{data}, while the original or the dodged coordinates are returned in \code{x_orig}
38
+ # ' and \code{y_orig}. Nudge values supported are those of \emph{mode} numeric,
39
+ # ' thus including dates and times when they match the mapped data .
32
40
# '
33
41
# ' If the length of \code{x} and/or \code{y} is more than one but less than
34
42
# ' rows are present in the data, the vector is both recycled and reordered so
35
43
# ' that the nudges are applied sequentially based on the data values. If their
36
44
# ' length matches the number of rows in data, they are assumed to be already
37
45
# ' in data order.
38
46
# '
47
+ # ' The applied dodge is identical to that by
48
+ # ' \code{\link[ggplot2]{position_dodge}} while nudging is different to that by
49
+ # ' \code{\link[ggplot2]{position_nudge}}.
50
+ # '
51
+ # ' There are two possible uses for these functions. First, without using dodging
52
+ # ' they can be used to obtain aligned labels when the labelled objects are not
53
+ # ' aligned. This is the most common use.
54
+ # '
55
+ # ' The second use is to label dodged bars, boxplots or points with labels
56
+ # ' aligned. In this case, it is mandatory to use
57
+ # ' the same argument to \code{width} when passing \code{position_dodge()} to
58
+ # ' \code{geom_col()} and \code{position_dodgenudge_to()} to \code{geom_text()} or
59
+ # ' \code{geom_label()} or their repulsive equivalents. Otherwise the arrows or
60
+ # ' segments will fail to connect to the labels. In other words dodging is
61
+ # ' computed twice. Dodge is identical to that obtained with the same arguments
62
+ # ' in \code{\link[ggplot2]{position_dodge}} as \code{position_dodgenudge_to()}
63
+ # ' simply calls the same code from package 'ggplot2' ahead of applying
64
+ # ' nudging.
65
+ # '
66
+ # ' When applying dodging, the return of original positions instead of the dodged
67
+ # ' ones is achieved by passing \code{origin = "original"} instead of the default
68
+ # ' of \code{origin = "dodged"}.
69
+ # '
39
70
# ' @note Irrespective of the action, the ordering of rows in \code{data} is
40
71
# ' preserved.
41
72
# '
42
73
# ' @return A \code{"Position"} object.
43
74
# '
44
75
# ' @seealso \code{\link[ggplot2]{position_nudge}},
76
+ # ' \code{\link[ggplot2]{position_dodge}},
45
77
# ' \code{\link[ggrepel]{position_nudge_repel}}.
46
78
# '
47
79
# ' @export
58
90
# ' geom_point() +
59
91
# ' geom_text(position = position_nudge_to())
60
92
# '
93
+ # ' ggplot(df, aes(x, y, label = label)) +
94
+ # ' geom_point() +
95
+ # ' geom_text(position = position_dodgenudge_to())
96
+ # '
61
97
# ' # a single y (or x) value nudges all observations to this data value
62
98
# ' ggplot(df, aes(x, y, label = label)) +
63
99
# ' geom_point() +
98
134
# ' ggplot(df, aes(x, y, label = label)) +
99
135
# ' geom_point() +
100
136
# ' geom_text_s(position =
101
- # ' position_nudge_to (y = 3, x.action = "spread", x.expansion = -0.1))
137
+ # ' position_dodgenudge_to (y = 3, x.action = "spread", x.expansion = -0.1))
102
138
# '
103
139
# ' # spread the values at equal distance within the range given by x
104
140
# ' ggplot(df, aes(x, y, label = label)) +
113
149
# ' position_nudge_to(y = 3, x = c(0,6), x.action = "spread"),
114
150
# ' hjust = "center")
115
151
# '
116
- position_nudge_to <-
117
- function (x = NULL ,
152
+ position_dodgenudge_to <-
153
+ function (width = 1 ,
154
+ preserve = c(" total" , " single" ),
155
+ x = NULL ,
118
156
y = NULL ,
119
157
x.action = c(" none" , " spread" ),
120
158
y.action = c(" none" , " spread" ),
@@ -123,6 +161,7 @@ position_nudge_to <-
123
161
x.expansion = 0 ,
124
162
y.expansion = 0 ,
125
163
kept.origin = c(" original" , " none" )) {
164
+ preserve <- rlang :: arg_match(preserve )
126
165
kept.origin <- rlang :: arg_match(kept.origin )
127
166
x.action <- rlang :: arg_match(x.action )
128
167
y.action <- rlang :: arg_match(y.action )
@@ -141,7 +180,7 @@ position_nudge_to <-
141
180
y <- as.numeric(y )
142
181
}
143
182
144
- ggplot2 :: ggproto(NULL , PositionNudgeTo ,
183
+ ggplot2 :: ggproto(NULL , PositionDodgeNudgeTo ,
145
184
x = x ,
146
185
y = y ,
147
186
x.action = x.action ,
@@ -150,17 +189,19 @@ position_nudge_to <-
150
189
y.distance = y.distance ,
151
190
x.expansion = rep_len(x.expansion , 2 ),
152
191
y.expansion = rep_len(y.expansion , 2 ),
153
- kept.origin = kept.origin
192
+ kept.origin = kept.origin ,
193
+ width = width ,
194
+ preserve = rlang :: arg_match(preserve )
154
195
)
155
196
}
156
197
157
198
# ' @rdname ggpp-ggproto
158
199
# ' @format NULL
159
200
# ' @usage NULL
160
201
# ' @export
161
- PositionNudgeTo <-
202
+ PositionDodgeNudgeTo <-
162
203
ggplot2 :: ggproto(
163
- " PositionNudgeTo " ,
204
+ " PositionDodgeNudgeTo " ,
164
205
Position ,
165
206
x = NULL ,
166
207
y = NULL ,
@@ -181,6 +222,11 @@ PositionNudgeTo <-
181
222
},
182
223
183
224
compute_layer = function (self , data , params , layout ) {
225
+ # operate on the dodged positions
226
+ data = ggplot2 :: ggproto_parent(ggplot2 :: PositionDodge , self )$ compute_layer(data , params , layout )
227
+
228
+ x_dodged <- data $ x
229
+ y_dodged <- data $ y
184
230
x_orig <- data $ x
185
231
y_orig <- data $ y
186
232
@@ -273,11 +319,48 @@ PositionNudgeTo <-
273
319
data <- transform_position(data , NULL , function (y ) y + params $ y )
274
320
}
275
321
# add original position
276
- if (params $ kept.origin == " original" ) {
322
+ if (params $ kept.origin == " dodged" ) {
323
+ data $ x_orig <- x_dodged
324
+ data $ y_orig <- y_dodged
325
+ } else if (params $ kept.origin == " original" ) {
277
326
data $ x_orig <- x_orig
278
327
data $ y_orig <- y_orig
279
328
}
280
329
281
330
data
331
+ },
332
+
333
+ compute_panel = function (self , data , params , scales ) {
334
+ ggplot2 :: ggproto_parent(PositionDodge , self )$ compute_panel(data , params , scales )
282
335
}
283
336
)
337
+
338
+ # ' @rdname position_dodgenudge_to
339
+ # '
340
+ # ' @export
341
+ # '
342
+ # for backwards compatibility with arguments passed by position
343
+ position_nudge_to <-
344
+ function (x = NULL ,
345
+ y = NULL ,
346
+ x.action = c(" none" , " spread" ),
347
+ y.action = c(" none" , " spread" ),
348
+ x.distance = " equal" ,
349
+ y.distance = " equal" ,
350
+ x.expansion = 0 ,
351
+ y.expansion = 0 ,
352
+ kept.origin = c(" original" , " none" )) {
353
+
354
+ position_dodgenudge_to(width = 1 ,
355
+ preserve = " total" ,
356
+ x = x ,
357
+ y = y ,
358
+ x.action = x.action ,
359
+ y.action = y.action ,
360
+ x.distance = x.distance ,
361
+ y.distance = y.distance ,
362
+ x.expansion = x.expansion ,
363
+ y.expansion = y.expansion ,
364
+ kept.origin = kept.origin
365
+ )
366
+ }
0 commit comments