Browse code

Merge pull request #493 from xiangpin/geom_striplab

add geom_striplab

Guangchuang Yu authored on 22/04/2022 08:55:41 • GitHub committed on 22/04/2022 08:55:41
Showing 10 changed files

... ...
@@ -42,6 +42,7 @@ Suggests:
42 42
     emojifont,
43 43
     ggimage,
44 44
     ggplotify,
45
+    shadowtext,
45 46
     grDevices,
46 47
     knitr,
47 48
     prettydoc,
... ...
@@ -29,6 +29,7 @@ S3method(ggplot_add,hilight)
29 29
 S3method(ggplot_add,layout_ggtree)
30 30
 S3method(ggplot_add,range_xaxis)
31 31
 S3method(ggplot_add,scale_ggtree)
32
+S3method(ggplot_add,striplab)
32 33
 S3method(ggplot_add,striplabel)
33 34
 S3method(ggplot_add,taxalink)
34 35
 S3method(ggplot_add,tiplab)
... ...
@@ -82,6 +83,7 @@ export(geom_rootedge)
82 83
 export(geom_rootpoint)
83 84
 export(geom_segment2)
84 85
 export(geom_strip)
86
+export(geom_striplab)
85 87
 export(geom_taxalink)
86 88
 export(geom_text)
87 89
 export(geom_text2)
... ...
@@ -39,7 +39,7 @@
39 39
 ##' aesthetics are in bold):
40 40
 ##'     \itemize{
41 41
 ##'        \item \strong{\code{node}} selected node to hight light, it is required.
42
-##'        \item \strong{\code{label}} labels showed, it is required.
42
+##'        \item \strong{\code{label}} labels to be shown, it is required.
43 43
 ##'        \item \code{colour} the colour of text, defaults to "black".
44 44
 ##'        \item \code{size} the size of text, defaults to 3.88.
45 45
 ##'        \item \code{angle} the angle of text, defaults to 0.
... ...
@@ -58,7 +58,7 @@
58 58
 ##' aesthetics are in bold):
59 59
 ##'     \itemize{
60 60
 ##'        \item \strong{\code{node}} selected node to hight light, it is required.
61
-##'        \item \strong{\code{label}} labels to be showed, it is required.
61
+##'        \item \strong{\code{label}} labels to be shown, it is required.
62 62
 ##'        \item \code{colour} the colour of text, defaults to "black".
63 63
 ##'        \item \code{fill} the background colour of the label, defaults to "white".
64 64
 ##'        \item \code{size} the size of text, defaults to 3.88.
... ...
@@ -78,7 +78,7 @@
78 78
 ##' aesthetics are in bold):
79 79
 ##'     \itemize{
80 80
 ##'        \item \strong{\code{node}} selected node to hight light, it is required.
81
-##'        \item \strong{\code{label}} labels to be showed, it is required.
81
+##'        \item \strong{\code{label}} labels to be shown, it is required.
82 82
 ##'        \item \code{colour} the colour of text, defaults to "black".
83 83
 ##'        \item \code{bg.colour} the background colour of text, defaults to 'black'.
84 84
 ##'        \item \code{bg.r} the width of background text, defaults to 0.1.
... ...
@@ -99,7 +99,7 @@
99 99
 ##' aesthetics are in bold):
100 100
 ##'     \itemize{
101 101
 ##'        \item \strong{\code{node}} selected node to hight light, it is required.
102
-##'        \item \strong{\code{label}} labels to be showed, it is required.
102
+##'        \item \strong{\code{label}} labels to be shown, it is required.
103 103
 ##'        \item \strong{\code{image}} the image to be annotated, when geom="phylopic", 
104 104
 ##'         the uid of phylopic databases, it is required.
105 105
 ##'        \item \code{colour} the color of image, defaults to NULL.
... ...
@@ -13,6 +13,8 @@
13 13
 #' unrooted and daylight layout tree use will use encircle layer. You can specify this parameter to
14 14
 #' `rect` (rectangular layer) or `encircle` (encircle layer), 'gradient' (gradient color), 
15 15
 #' 'roundrect' (round rectangular layer).
16
+#' @param to.bottom logical, whether set the high light layer to the bottom in all layers of 'ggtree'
17
+#' object, default is FALSE.
16 18
 #' @param ... additional parameters, see also the below and Aesthetics section.
17 19
 #'     \itemize{
18 20
 #'        \item \code{align} control the align direction of the edge of high light rectangular.
... ...
@@ -82,12 +84,14 @@ geom_hilight <- function(data=NULL,
82 84
                          mapping=NULL,
83 85
                          node=NULL,
84 86
                          type="auto",
87
+                         to.bottom=FALSE,
85 88
                           ...){
86 89
     params <- list(...)
87 90
     structure(list(data    = data,
88 91
                    mapping = mapping,
89 92
                    node    = node,
90 93
                    type    = type,
94
+                   to.bottom = to.bottom,
91 95
                    params  = params),
92 96
               class = 'hilight')
93 97
 }
... ...
@@ -59,6 +59,161 @@ geom_strip <- function(taxa1, taxa2, label, offset=0, offset.text=0,
59 59
               class = "striplabel")
60 60
 }
61 61
 
62
+#' annotate associated taxa (from taxa1 to taxa2, can be Monophyletic, Polyphyletic or Paraphyletc Taxa) with bar and (optional) text label or image
63
+#'
64
+#' @title geom_striplab
65
+#' @param taxa1 can be label or node number
66
+#' @param taxa2 can be label or node number
67
+#' @param label character, character to be showed, when data and mapping is NULL, it is required.
68
+#' @param data data.frame, the data to be displayed in the annotation, default is NULL.
69
+#' @param mapping Set of aesthetic mappings, default is NULL. The detail see the following explanation.
70
+#' @param geom character, one of 'text', 'label', 'shadowtext', 'image' and 'phylopic',
71
+#' default is 'text', and the parameter see the Aesthetics For Specified Geom.
72
+#' @param parse logical, whether parse label to emoji font, default is FALSE.
73
+#' @param ... additional parameters, see also following section.
74
+#'
75
+#' additional parameters can refer the following parameters.                                                                                                                                                      ##'     \itemize{
76
+#'        \item \code{offset} distance bar and tree, offset of bar and text from
77
+#'         the clade, default is 0.
78
+#'        \item \code{offset.text} distance bar and text, offset of text from bar,
79
+#'         default is 0.
80
+#'        \item \code{align} logical, whether align clade lab, default is FALSE.
81
+#'        \item \code{extend} numeric, extend the length of bar, default is 0.
82
+#'        \item \code{angle} numeric or 'auto', if angle is auto, the angle of text will
83
+#'         be calculated automatically, which is useful for the circular etc layout, default is 0.
84
+#'        \item \code{horizontal} logical, whether set label to horizontal, default is TRUE.
85
+#'        \item \code{barsize} the width of line, default is 0.5.
86
+#'        \item \code{barcolour} the colour of line, default is 'black'.
87
+#'        \item \code{fontsize} the size of text, default is 3.88.
88
+#'        \item \code{textcolour} the colour of text, default is 'black'.
89
+#'        \item \code{imagesize} the size of image, default is 0.05.
90
+#'        \item \code{imagecolor} the colour of image, default is NULL, when
91
+#'        geom="phylopic", it should be required.
92
+#'     }
93
+#' The parameters also can be set in mapping, when data is provided. Note: the barsize, barcolour,
94
+#' fontsize, textcolour, imagesize and imagecolor should not be set in mapping (aesthetics). When
95
+#' the color and size are not be set in mapping, user can modify them to adjust the attributes of
96
+#' specified geom.
97
+#'
98
+#' @section Aesthetics For Specified Geom:
99
+#' \code{geom_striplab()} understands the following aesthetics for geom="text"(required
100
+#' aesthetics are in bold):
101
+#'     \itemize{
102
+#'        \item \strong{\code{taxa1}} selected tip label or tip node, it is required.
103
+#'        \item \strong{\code{taxa2}} selected another tip label or tip node, it is required.
104
+#'        \item \strong{\code{label}} labels to be shown, it is required.
105
+#'        \item \code{colour} the colour of text, default is "black".
106
+#'        \item \code{size} the size of text, default is 3.88.
107
+#'        \item \code{angle} the angle of text, default is 0.
108
+#'        \item \code{hjust} A numeric vector specifying horizontal justification, default is 0.
109
+#'        \item \code{vjust} A numeric vector specifying vertical justification, default is 0.5.
110
+#'        \item \code{alpha} the transparency of text, default is NA.
111
+#'        \item \code{family} the family of text, default is 'sans'.
112
+#'        \item \code{fontface} the font face of text, default is 1 (plain), others are
113
+#'         2 (bold), 3 (italic), 4 (bold.italic).
114
+#'        \item \code{lineheight} The height of a line as a multiple of the size of text, default is 1.2 .
115
+#'     }
116
+#'  when the colour, size are not be set in mapping, and user want to modify the colour of text,
117
+#'  they should use textcolour, fontsize to avoid the confusion with bar layer annotation.
118
+#'
119
+#' \code{geom_striplab()} understands the following aesthethics for geom="label" (required
120
+#' aesthetics are in bold):
121
+#'     \itemize{
122
+#'        \item \strong{\code{taxa1}} selected node to hight light, it is required.
123
+#'        \item \strong{\code{taxa2}} selected another tip label or tip node, it is required.
124
+#'        \item \strong{\code{label}} labels to be shown, it is required.
125
+#'        \item \code{colour} the colour of text, default is "black".
126
+#'        \item \code{fill} the background colour of the label, default is "white".
127
+#'        \item \code{size} the size of text, default is 3.88.
128
+#'        \item \code{angle} the angle of text, default is 0.
129
+#'        \item \code{hjust} A numeric vector specifying horizontal justification, default is 0.
130
+#'        \item \code{vjust} A numeric vector specifying vertical justification, default is 0.5.
131
+#'        \item \code{alpha} the transparency of text, default is NA.
132
+#'        \item \code{family} the family of text, default is 'sans'.
133
+#'        \item \code{fontface} the font face of text, default is 1 (plain), others are
134
+#'         2 (bold), 3 (italic), 4 (bold.italic).
135
+#'        \item \code{lineheight} The height of a line as a multiple of the size of text, default is 1.2 .
136
+#'     }
137
+#'  when the colour, size are not be set in mapping, and user want to modify the colour of text,
138
+#'  they should use textcolour, fontsize to avoid the confusion with bar layer annotation.
139
+#'
140
+#' \code{geom_striplab()} understands the following aesthethics for geom="shadowtext" (required
141
+#' aesthetics are in bold):
142
+#'     \itemize{
143
+#'        \item \strong{\code{taxa1}} selected node to hight light, it is required.
144
+#'        \item \strong{\code{taxa2}} selected another tip label or tip node, it is required.
145
+#'        \item \strong{\code{label}} labels to be shown, it is required.
146
+#'        \item \code{colour} the colour of text, default is "black".
147
+#'        \item \code{bg.colour} the background colour of text, default is 'black'.
148
+#'        \item \code{bg.r} the width of background text, default is 0.1.
149
+#'        \item \code{size} the size of text, default is 3.88.
150
+#'        \item \code{angle} the angle of text, default is 0.
151
+#'        \item \code{hjust} A numeric vector specifying horizontal justification, default is 0.
152
+#'        \item \code{vjust} A numeric vector specifying vertical justification, default is 0.5.
153
+#'        \item \code{alpha} the transparency of text, default is NA.
154
+#'        \item \code{family} the family of text, default is 'sans'.
155
+#'        \item \code{fontface} the font face of text, default is 1 (plain), others are
156
+#'         2 (bold), 3 (italic), 4 (bold.italic).
157
+#'        \item \code{lineheight} The height of a line as a multiple of the size of text, default is 1.2 .
158
+#'     }
159
+#'  when the colour, size are not be set in mapping, and user want to modify the colour of text,
160
+#'  they should use textcolour, fontsize to avoid the confusion with bar layer annotation.
161
+#'
162
+#' \code{geom_striplab()} understands the following aesthethics for geom="image" or geom="phylopic" (required
163
+#' aesthetics are in bold):
164
+#'     \itemize{
165
+#'        \item \strong{\code{taxa1}} selected node to hight light, it is required.
166
+#'        \item \strong{\code{taxa2}} selected another tip label or tip node, it is required.
167
+#'        \item \strong{\code{label}} labels to be shown, it is required.
168
+#'        \item \strong{\code{image}} the image to be annotated, when geom="phylopic",
169
+#'         the uid of phylopic databases, it is required.
170
+#'        \item \code{colour} the color of image, default is NULL.
171
+#'        \item \code{size} the size of image, default is 0.05.
172
+#'        \item \code{alpha} the alpha of image, default is 0.8.
173
+#'     }
174
+#'  when the colour, size are not be set in mapping, and user want to modify the colour of image,
175
+#'  they should use imagecolour, imagesize to avoid the confusion with bar layer annotation.
176
+#' @export
177
+#' @examples
178
+#' set.seed(123)
179
+#' tr <- rtree(10)
180
+#' dt <- data.frame(ta1=c("t5", "t1"), ta2=c("t6", "t3"), group=c("A", "B"))
181
+#' p <- ggtree(tr) + geom_tiplab()
182
+#' p2 <- p + 
183
+#'       geom_striplab(
184
+#'         data = dt,
185
+#'         mapping = aes(taxa1 = ta1, taxa2 = ta2, 
186
+#'                       label = group, color=group),
187
+#'         align = TRUE,
188
+#'         show.legend = FALSE
189
+#'       )
190
+#' p2
191
+geom_striplab <- function(
192
+               taxa1 = NULL, 
193
+               taxa2 = NULL,
194
+               label = NULL,
195
+               data = NULL,
196
+               mapping = NULL,
197
+               geom = "text",
198
+               parse = FALSE,
199
+               ...
200
+    ){
201
+
202
+    params <- list(inherit.aes = FALSE, ...)
203
+    structure(
204
+       list(
205
+         data = data, 
206
+         mapping = mapping, 
207
+         taxa1 = taxa1,
208
+         taxa2 = taxa2,
209
+         label = label, 
210
+         geom = geom, 
211
+         parse = parse, 
212
+         params = params
213
+       ),
214
+       class = "striplab")
215
+
216
+}
62 217
 
63 218
 ## geom_strip <- function(taxa1, taxa2, label, offset=0, offset.text=0,
64 219
 ##                            align=TRUE, barsize=0.5, extend=0, fontsize=3.88,
... ...
@@ -183,6 +338,44 @@ geom_strip <- function(taxa1, taxa2, label, offset=0, offset.text=0,
183 338
 ##                         required_aes = c("x", "y", "xend", "yend")
184 339
 ##                         )
185 340
 
341
+get_striplab_position <- function(data, taxa1, taxa2, offset, angle="auto", 
342
+                                  align = TRUE, extend = 0, adjustRatio = 1.02, 
343
+                                  horizontal = TRUE){
344
+    df <- get_striplab_position_(data = data, taxa1 = taxa1, taxa2 = taxa2, 
345
+                                 angle = angle, extend = extend, horizontal = horizontal)
346
+    if (align){
347
+        mx <- max(data$x, na.rm = TRUE)
348
+    }else{
349
+        mx <- df$x
350
+    }
351
+    angle <- df$angle
352
+    mx <- mx * adjustRatio + offset
353
+    data.frame(x = mx, xend = mx, y = df$y, yend=df$yend, angle = angle)
354
+}
355
+
356
+get_striplab_position_ <- function(data, taxa1, taxa2, angle, extend = 0, horizontal){
357
+    if (length(extend) == 1) {
358
+        extend <- rep(extend, 2)
359
+    }
360
+
361
+    node1 <- taxa2node(data, taxa1)
362
+    node2 <- taxa2node(data, taxa2)
363
+
364
+    xx <- with(data, c(x[node == node1], x[node == node2]))
365
+    yy <- with(data, c(y[node == node1], y[node == node2]))
366
+
367
+    d <- data.frame(x=max(xx), y=min(yy)-extend[2], yend=max(yy)+extend[1])
368
+    if (missing(angle))
369
+        return(d)
370
+    if (angle == "auto") {
371
+        anglerange <- with(data, c(angle[node == node1], angle[node == node2]))
372
+        d$angle <- mean(anglerange)
373
+        d$angle <- adjust_cladelabel_angle(angle=d$angle, horizontal=horizontal)
374
+    } else {
375
+        d$angle <- angle
376
+    }
377
+    return(d)    
378
+}
186 379
 
187 380
 get_striplabel_position <- function(data, taxa1, taxa2, offset, align, barextend, adjustRatio) {
188 381
     df <- get_striplabel_position_(data, taxa1, taxa2, barextend)
... ...
@@ -76,6 +76,48 @@ remapping <- function(mapping, samevars){
76 76
     return(mapping)
77 77
 }
78 78
 
79
+build_striplabel_df <- function(trdf, taxa1, taxa2, label, offset, align, angle, horizontal){
80
+    dat <- mapply(get_striplab_position,
81
+                     taxa1 = taxa1,
82
+                     taxa2 = taxa2,
83
+                     offset = offset,
84
+                     angle = angle,
85
+                     align = align,
86
+                     horizontal = horizontal,
87
+                  MoreArgs = list(
88
+                     data = trdf,
89
+                     adjustRatio = 1.03
90
+                  ),
91
+                  SIMPLIFY = FALSE
92
+           )
93
+    dat <- do.call("rbind", dat)
94
+    dat$y <- unlist(mapply(function(x, y){mean(c(x, y))}, dat$y, dat$yend, SIMPLIFY=FALSE))
95
+    dat$taxa1 <- taxa1
96
+    dat$taxa2 <- taxa2
97
+    dat$label <- label
98
+    return(dat)
99
+}
100
+
101
+build_stripbar_df <- function(trdf, taxa1, taxa2, offset, align, extend){
102
+    dat <- mapply(get_striplab_position,
103
+                     taxa1 = taxa1,
104
+                     taxa2 = taxa2,
105
+                     offset = offset,
106
+                     align = align,
107
+                     extend = extend,
108
+                  MoreArgs = list(
109
+                     data = trdf,
110
+                     angle = 0,
111
+                     adjustRatio = 1.02
112
+                  ),
113
+                  SIMPLIFY = FALSE
114
+           )
115
+    dat <- do.call("rbind", dat)
116
+    dat$taxa1 <- taxa1
117
+    dat$taxa2 <- taxa2
118
+    return(dat)
119
+}
120
+
79 121
 build_cladelabel_df <- function(trdf, nodeids, label, offset, align, angle, horizontal){
80 122
     dat <- mapply(function(i, o, a, g, h){get_cladelabel_position(data=trdf, 
81 123
                                           node=i, 
... ...
@@ -117,6 +159,44 @@ build_cladebar_df <- function(trdf, nodeids, offset, align, extend){
117 159
 
118 160
 }
119 161
 
162
+#build_striplabel_df2 <- function(trdf, taxa1, taxa2, label, offset, align, angle, horizontal){
163
+#    dat <- mapply(get_striplab_position2,
164
+#                           taxa1 = taxa1,
165
+#                           taxa2 = taxa2,
166
+#                           offset = offset,
167
+#                           align = align,
168
+#                           angle = angle,
169
+#                           horizontal = horizontal,
170
+#                           MoreArgs = list(
171
+#                               datai = trdf,
172
+#                               adjustRatio = 1.2
173
+#                           ),
174
+#                  SIMPLIFY=FALSE)
175
+#    dat <- do.call("rbind", dat)
176
+#    dat$taxa1 <- taxa1
177
+#    dat$taxa2 <- taxa2
178
+#    dat$label <- label
179
+#    return (dat)
180
+#}
181
+#
182
+#build_stripbar_df2 <- function(trdf, taxa1, taxa2, offset, align){
183
+#    dat <- mapply(get_striplab_position_bar,
184
+#                    taxa1 = taxa1,
185
+#                    taxa2 = taxa2,
186
+#                    offset = offset,
187
+#                    align = align,
188
+#                  MoreArgs = list(
189
+#                    data = trdf,
190
+#                    adjustRatio = 1.1),
191
+#               SIMPLIFY = FALSE
192
+#           )
193
+#    dat <- do.call("rbind", dat)
194
+#    colnames(dat) <- c("x", "y", "xend", "yend")
195
+#    dat$taxa1 <- taxa1
196
+#    dat$taxa2 <- taxa2
197
+#    return(dat)
198
+#}
199
+
120 200
 build_cladelabel_df2 <- function(trdf, nodeids, label, offset, align, angle, horizontal){
121 201
     dat <- mapply(get_cladelabel2_position_label,
122 202
                            node=nodeids,
... ...
@@ -341,7 +341,7 @@ ggplot_add.cladelab <- function(object, plot, object_name){
341 341
         flagnode <- da_node_label$node[is.na(flagnode)]
342 342
         abort(paste0("ERROR: clade node id ", paste(flagnode, collapse='; ')," can not be found in tree data."))
343 343
     }
344
-    if (layout == "unrooted" || layout == "daylight"){
344
+    if (layout %in% c("unrooted", "daylight", "ape", "equal_angle")){
345 345
         textdata <- build_cladelabel_df2(trdf=plot$data,
346 346
                                          nodeids=da_node_label$node,
347 347
                                          label=da_node_label$label,
... ...
@@ -384,6 +384,9 @@ ggplot_add.cladelab <- function(object, plot, object_name){
384 384
     bar_obj$data <- bardata
385 385
     bar_default_aes <- list(barcolour="black", barcolor="black", barsize=0.5, colour="black", size=0.5, 
386 386
                             linetype=1, alpha=NA, inherit.aes=FALSE, show.legend=NA)
387
+    if (layout %in% c("unrooted", "daylight", "equal_angle", "ape")){
388
+        bar_default_aes <- c(bar_default_aes, list(curvature = .5, ncp = 5))
389
+    }
387 390
     bar_obj$mapping <- reset_mapping(defaultm=bar_default_aes, inputm=object$mapping)
388 391
     ifelse(is.null(bar_obj$mapping),bar_obj$mapping <- aes_(x=~x, xend=~xend, y=~y, yend=~yend),
389 392
            bar_obj$mapping <- modifyList(bar_obj$mapping, aes_(x=~x, xend=~xend, y=~y, yend=~yend)))
... ...
@@ -392,7 +395,7 @@ ggplot_add.cladelab <- function(object, plot, object_name){
392 395
                                        default_aes=bar_default_aes,
393 396
                                        params=object$params)
394 397
     bar_obj <- c(bar_obj, bar_dot_params)
395
-    if (layout == "unrooted" || layout == "daylight"){
398
+    if (layout %in% c("unrooted", "daylight", "equal_angle", "ape")){
396 399
         bar_obj <- do.call(ggplot2::geom_curve, bar_obj)
397 400
     }else{
398 401
         bar_obj <- do.call("geom_segment", bar_obj)
... ...
@@ -488,7 +491,7 @@ ggplot_add.hilight <- function(object, plot, object_name){
488 491
         flagnode <- clade_node[is.na(flagnode)]
489 492
         abort(paste0("ERROR: clade node id ", paste(flagnode, collapse='; ')," can not be found in tree data."))
490 493
     }
491
-    if (layout == "unrooted" || layout == "daylight"){
494
+    if (layout %in% c("unrooted", "daylight", "equal_angle", "ape")){
492 495
         data <- switch(object$type,
493 496
                        auto = build_cladeids_df(trdf=framedat, nodeids=clade_node),
494 497
                        rect = build_cladeids_df2(trdf=framedat, nodeids=clade_node),
... ...
@@ -515,11 +518,11 @@ ggplot_add.hilight <- function(object, plot, object_name){
515 518
     }else{
516 519
         object$data <- data
517 520
     }
518
-    if (layout == "unrooted" || layout == "daylight"){
521
+    if (layout %in% c("unrooted", "daylight", "equal_angle", "ape")){
519 522
         ly <- switch(object$type,
520 523
                      auto = choose_hilight_layer(object = object, type = "encircle"),
521 524
                      rect = choose_hilight_layer(object = object, type = "rect"),
522
-                     encircle = choose_hilight_layer(object = object, type="encircle"),
525
+                     encircle = choose_hilight_layer(object = object, type = "encircle"),
523 526
                      gradient = choose_hilight_layer(object = object, type = "gradient"),
524 527
                      roundrect = choose_hilight_layer(object = object, type = "roundrect")
525 528
                   )
... ...
@@ -532,7 +535,12 @@ ggplot_add.hilight <- function(object, plot, object_name){
532 535
                      roundrect = choose_hilight_layer(object = object, type = "roundrect")	 
533 536
                   )
534 537
     }
535
-    ggplot_add(ly, plot, object_name) 
538
+    plot <- ggplot_add(ly, plot, object_name)
539
+    if (object$to.bottom){
540
+        idx <- length(plot$layers)
541
+        plot$layers <- c(plot$layers[idx], plot$layers[-idx])
542
+    }
543
+    plot    
536 544
 }
537 545
 
538 546
 
... ...
@@ -578,6 +586,125 @@ ggplot_add.striplabel <- function(object, plot, object_name) {
578 586
     ggplot_add(list(ly_bar, ly_text), plot, object_name)
579 587
 }
580 588
 
589
+##' @method ggplot_add striplab
590
+##' @export
591
+ggplot_add.striplab <- function(object, plot, object_name){
592
+    layout <- get_layout(plot) 
593
+    if (is.null(object$data) && is.null(object$taxa1) && is.null(object$taxa2) && is.null(object$label)){
594
+        abort("data and taxa1, taxa2, label can't be NULL simultaneously!")
595
+    }
596
+    if (!is.null(object$data)){
597
+        if (is.null(object$mapping) || 
598
+            is.null(object$mapping$taxa1) || 
599
+            is.null(object$mapping$taxa2) || 
600
+            is.null(object$mapping$label)){
601
+            abort("when data is provided, the mapping also should be provided, 
602
+                  and taxa1, taxa2, label are required aesthetics.")
603
+        }else{
604
+            if (!is.null(object$mapping$subset)){
605
+                object$data <- subset(object$data, eval(parse(text=quo_name(object$mapping$subset))))
606
+                object$mapping <- object$mapping[names(object$mapping)!="subset"]
607
+            }
608
+            da_taxa_label <- data.frame(
609
+                taxa1 = as.vector(object$data[[quo_name(object$mapping$taxa1)]]),
610
+                taxa2 = as.vector(object$data[[quo_name(object$mapping$taxa2)]]),
611
+                label = as.vector(object$data[[quo_name(object$mapping$label)]])
612
+            )
613
+        }
614
+    }else{
615
+        da_taxa_label <- data.frame(taxa1 = object$taxa1, taxa2 = object$taxa2, label = object$label)
616
+    }    
617
+
618
+    default_raw_aes <- list(offset=0, offset.text=0, align=TRUE, angle=0, extend=0, horizontal=TRUE)
619
+    default_raw_aes <- reset_params(defaultp=default_raw_aes, inputp=object$params, type="other")
620
+    bar_params <- list(barsize=0.5, barcolour = "black")
621
+    bar_params <- reset_params(defaultp=bar_params, inputp=object$params, type="bar")
622
+    text_params <- list(fontsize= 3.88, family = "sans", textcolour="black", hjust=0)
623
+    text_params <- reset_params(defaultp=text_params, inputp=object$params, type="text")
624
+    image_params <- list(imagesize=0.05, alpha=0.8, imagecolour=NULL)
625
+    image_params <- reset_params(defaultp=image_params, inputp=object$params, type="image")
626
+    da_taxa_label <- transform_df(data = da_taxa_label, object = object, default_aes = default_raw_aes)
627
+    object$mapping <- object$mapping[!names(object$mapping)%in%names(default_raw_aes)]
628
+    object$params <- object$params[!names(object$params) %in% c("angle", "size", "color", "colour", "hjust")]
629
+    taxa <- unique(c(da_taxa_label$taxa1, da_taxa_label$taxa2))
630
+    flagnode <- match(taxa, plot$data$label)
631
+    if (anyNA(flagnode)){
632
+        flagnode <- taxa[is.na(flagnode)]
633
+        abort(paste0("ERROR: The taxa id: ", paste(flagnode, collapse='; ')," can not be found in tree data."))
634
+    }
635
+
636
+    #if (layout %in% c("unrooted", "daylight", "equal_angle", "ape")){
637
+    #    textdata <- build_striplabel_df2(trdf = plot$data,
638
+    #                                     taxa1 = da_taxa_label$taxa1,
639
+    #                                     taxa2 = da_taxa_label$taxa2,
640
+    #                                     label = da_taxa_label$label,
641
+    #                                     offset = da_taxa_label$offset.text,
642
+    #                                     align = da_taxa_label$align,
643
+    #                                     angle = da_taxa_label$angle,
644
+    #                                     horizontal = da_taxa_label$horizontal)
645
+    #    bardata <- build_stripbar_df2(trdf = plot$data,
646
+    #                                  taxa1 = da_taxa_label$taxa1,
647
+    #                                  taxa2 = da_taxa_label$taxa2,
648
+    #                                  offset = da_taxa_label$offset,
649
+    #                                  align = da_taxa_label$align)
650
+    #}else{
651
+    textdata <- build_striplabel_df(trdf = plot$data,
652
+                                    taxa1 = da_taxa_label$taxa1,
653
+                                    taxa2 = da_taxa_label$taxa2,
654
+                                    label = da_taxa_label$label,
655
+                                    offset = da_taxa_label$offset.text,
656
+                                    align = da_taxa_label$align,
657
+                                    angle = da_taxa_label$angle,
658
+                                    horizontal = da_taxa_label$horizontal)
659
+    bardata <- build_stripbar_df(trdf = plot$data,
660
+                                 taxa1 = da_taxa_label$taxa1,
661
+                                 taxa2 = da_taxa_label$taxa2,
662
+                                 offset = da_taxa_label$offset,
663
+                                 align = da_taxa_label$align,
664
+                                 extend = da_taxa_label$extend)
665
+    #}
666
+
667
+    if (!is.null(object$data) && !is.null(object$mapping)){
668
+        object$data <- object$data[,!colnames(object$data) %in% c("x", "xend", "y", "yend", "label", "angle"),drop=FALSE]
669
+        textdata <- dplyr::left_join(textdata, object$data, 
670
+                                     by=c("taxa1"=quo_name(object$mapping$taxa1), 
671
+                                          "taxa2"=quo_name(object$mapping$taxa2))
672
+                    )
673
+        bardata <- dplyr::left_join(bardata, 
674
+                                    object$data, 
675
+                                    by=c("taxa1"=quo_name(object$mapping$taxa1), 
676
+                                         "taxa2"=quo_name(object$mapping$taxa2))
677
+                    )
678
+        object$mapping <- object$mapping[!names(object$mapping) %in% c("taxa1", "taxa2", "node", "label")]
679
+    }
680
+    annot_obj <- switch(object$geom,
681
+                        text = build_text_layer(data=textdata, object=object, params=text_params, layout=layout),
682
+                        label = build_text_layer(data=textdata, object=object, params=text_params, layout=layout),
683
+                        image = build_image_layer(data=textdata, object=object, params=image_params),
684
+                        phylopic = build_image_layer(data=textdata, object=object, params=image_params),
685
+                        shadowtext = build_text_layer(data=textdata, object=object, params=text_params),
686
+                       )
687
+    bar_obj <- list()
688
+    bar_obj$data <- bardata
689
+    bar_default_aes <- list(barcolour="black", barcolor="black", barsize=0.5, colour="black", size=0.5,
690
+                            linetype=1, alpha=NA, inherit.aes=FALSE, show.legend=NA)
691
+    bar_obj$mapping <- reset_mapping(defaultm=bar_default_aes, inputm=object$mapping)
692
+    ifelse(is.null(bar_obj$mapping),bar_obj$mapping <- aes_(x=~x, xend=~xend, y=~y, yend=~yend),
693
+           bar_obj$mapping <- modifyList(bar_obj$mapping, aes_(x=~x, xend=~xend, y=~y, yend=~yend)))
694
+    bar_dot_params <- reset_dot_params(mapping=bar_obj$mapping,
695
+                                       defaultp=bar_params,
696
+                                       default_aes=bar_default_aes,
697
+                                       params=object$params)
698
+    bar_obj <- c(bar_obj, bar_dot_params)
699
+    #if (layout %in% c("unrooted", "daylight", "ape", "equal_angle")){
700
+    #    bar_obj <- do.call(ggplot2::geom_curve, bar_obj)
701
+    #}else{
702
+    bar_obj <- do.call("geom_segment", bar_obj)
703
+    #}
704
+    obj <- list(annot_obj, bar_obj)
705
+    ggplot_add(obj, plot, object_name)
706
+}
707
+
581 708
 ##' @importFrom ggplot2 scale_x_continuous
582 709
 ##' @importFrom ggplot2 scale_x_date
583 710
 ##' @method ggplot_add scale_ggtree
... ...
@@ -5,9 +5,23 @@
5 5
 \alias{geom_highlight}
6 6
 \title{geom_hilight}
7 7
 \usage{
8
-geom_hilight(data = NULL, mapping = NULL, node = NULL, type = "auto", ...)
8
+geom_hilight(
9
+  data = NULL,
10
+  mapping = NULL,
11
+  node = NULL,
12
+  type = "auto",
13
+  to.bottom = FALSE,
14
+  ...
15
+)
9 16
 
10
-geom_highlight(data = NULL, mapping = NULL, node = NULL, type = "auto", ...)
17
+geom_highlight(
18
+  data = NULL,
19
+  mapping = NULL,
20
+  node = NULL,
21
+  type = "auto",
22
+  to.bottom = FALSE,
23
+  ...
24
+)
11 25
 }
12 26
 \arguments{
13 27
 \item{data}{data.frame, The data to be displayed in this layer, defaults to NULL.}
... ...
@@ -22,6 +36,9 @@ unrooted and daylight layout tree use will use encircle layer. You can specify t
22 36
 \code{rect} (rectangular layer) or \code{encircle} (encircle layer), 'gradient' (gradient color),
23 37
 'roundrect' (round rectangular layer).}
24 38
 
39
+\item{to.bottom}{logical, whether set the high light layer to the bottom in all layers of 'ggtree'
40
+object, default is FALSE.}
41
+
25 42
 \item{...}{additional parameters, see also the below and Aesthetics section.
26 43
 \itemize{
27 44
 \item \code{align} control the align direction of the edge of high light rectangular.
... ...
@@ -63,7 +63,7 @@ annotate a clade with bar and text label or (image)
63 63
 aesthetics are in bold):
64 64
 \itemize{
65 65
 \item \strong{\code{node}} selected node to hight light, it is required.
66
-\item \strong{\code{label}} labels showed, it is required.
66
+\item \strong{\code{label}} labels to be shown, it is required.
67 67
 \item \code{colour} the colour of text, defaults to "black".
68 68
 \item \code{size} the size of text, defaults to 3.88.
69 69
 \item \code{angle} the angle of text, defaults to 0.
... ...
@@ -82,7 +82,7 @@ they should use textcolour, fontsize to avoid the confusion with bar layer annot
82 82
 aesthetics are in bold):
83 83
 \itemize{
84 84
 \item \strong{\code{node}} selected node to hight light, it is required.
85
-\item \strong{\code{label}} labels to be showed, it is required.
85
+\item \strong{\code{label}} labels to be shown, it is required.
86 86
 \item \code{colour} the colour of text, defaults to "black".
87 87
 \item \code{fill} the background colour of the label, defaults to "white".
88 88
 \item \code{size} the size of text, defaults to 3.88.
... ...
@@ -102,7 +102,7 @@ they should use textcolour, fontsize to avoid the confusion with bar layer annot
102 102
 aesthetics are in bold):
103 103
 \itemize{
104 104
 \item \strong{\code{node}} selected node to hight light, it is required.
105
-\item \strong{\code{label}} labels to be showed, it is required.
105
+\item \strong{\code{label}} labels to be shown, it is required.
106 106
 \item \code{colour} the colour of text, defaults to "black".
107 107
 \item \code{bg.colour} the background colour of text, defaults to 'black'.
108 108
 \item \code{bg.r} the width of background text, defaults to 0.1.
... ...
@@ -123,7 +123,7 @@ they should use textcolour, fontsize to avoid the confusion with bar layer annot
123 123
 aesthetics are in bold):
124 124
 \itemize{
125 125
 \item \strong{\code{node}} selected node to hight light, it is required.
126
-\item \strong{\code{label}} labels to be showed, it is required.
126
+\item \strong{\code{label}} labels to be shown, it is required.
127 127
 \item \strong{\code{image}} the image to be annotated, when geom="phylopic",
128 128
 the uid of phylopic databases, it is required.
129 129
 \item \code{colour} the color of image, defaults to NULL.
130 130
new file mode 100644
... ...
@@ -0,0 +1,157 @@
1
+% Generated by roxygen2: do not edit by hand
2
+% Please edit documentation in R/geom_strip.R
3
+\name{geom_striplab}
4
+\alias{geom_striplab}
5
+\title{geom_striplab}
6
+\usage{
7
+geom_striplab(
8
+  taxa1 = NULL,
9
+  taxa2 = NULL,
10
+  label = NULL,
11
+  data = NULL,
12
+  mapping = NULL,
13
+  geom = "text",
14
+  parse = FALSE,
15
+  ...
16
+)
17
+}
18
+\arguments{
19
+\item{taxa1}{can be label or node number}
20
+
21
+\item{taxa2}{can be label or node number}
22
+
23
+\item{label}{character, character to be showed, when data and mapping is NULL, it is required.}
24
+
25
+\item{data}{data.frame, the data to be displayed in the annotation, default is NULL.}
26
+
27
+\item{mapping}{Set of aesthetic mappings, default is NULL. The detail see the following explanation.}
28
+
29
+\item{geom}{character, one of 'text', 'label', 'shadowtext', 'image' and 'phylopic',
30
+default is 'text', and the parameter see the Aesthetics For Specified Geom.}
31
+
32
+\item{parse}{logical, whether parse label to emoji font, default is FALSE.}
33
+
34
+\item{...}{additional parameters, see also following section.
35
+
36
+additional parameters can refer the following parameters.                                                                                                                                                      ##'     \itemize{
37
+\item \code{offset} distance bar and tree, offset of bar and text from
38
+the clade, default is 0.
39
+\item \code{offset.text} distance bar and text, offset of text from bar,
40
+default is 0.
41
+\item \code{align} logical, whether align clade lab, default is FALSE.
42
+\item \code{extend} numeric, extend the length of bar, default is 0.
43
+\item \code{angle} numeric or 'auto', if angle is auto, the angle of text will
44
+be calculated automatically, which is useful for the circular etc layout, default is 0.
45
+\item \code{horizontal} logical, whether set label to horizontal, default is TRUE.
46
+\item \code{barsize} the width of line, default is 0.5.
47
+\item \code{barcolour} the colour of line, default is 'black'.
48
+\item \code{fontsize} the size of text, default is 3.88.
49
+\item \code{textcolour} the colour of text, default is 'black'.
50
+\item \code{imagesize} the size of image, default is 0.05.
51
+\item \code{imagecolor} the colour of image, default is NULL, when
52
+geom="phylopic", it should be required.
53
+}
54
+The parameters also can be set in mapping, when data is provided. Note: the barsize, barcolour,
55
+fontsize, textcolour, imagesize and imagecolor should not be set in mapping (aesthetics). When
56
+the color and size are not be set in mapping, user can modify them to adjust the attributes of
57
+specified geom.}
58
+}
59
+\description{
60
+annotate associated taxa (from taxa1 to taxa2, can be Monophyletic, Polyphyletic or Paraphyletc Taxa) with bar and (optional) text label or image
61
+}
62
+\section{Aesthetics For Specified Geom}{
63
+
64
+\code{geom_striplab()} understands the following aesthetics for geom="text"(required
65
+aesthetics are in bold):
66
+\itemize{
67
+\item \strong{\code{taxa1}} selected tip label or tip node, it is required.
68
+\item \strong{\code{taxa2}} selected another tip label or tip node, it is required.
69
+\item \strong{\code{label}} labels to be shown, it is required.
70
+\item \code{colour} the colour of text, default is "black".
71
+\item \code{size} the size of text, default is 3.88.
72
+\item \code{angle} the angle of text, default is 0.
73
+\item \code{hjust} A numeric vector specifying horizontal justification, default is 0.
74
+\item \code{vjust} A numeric vector specifying vertical justification, default is 0.5.
75
+\item \code{alpha} the transparency of text, default is NA.
76
+\item \code{family} the family of text, default is 'sans'.
77
+\item \code{fontface} the font face of text, default is 1 (plain), others are
78
+2 (bold), 3 (italic), 4 (bold.italic).
79
+\item \code{lineheight} The height of a line as a multiple of the size of text, default is 1.2 .
80
+}
81
+when the colour, size are not be set in mapping, and user want to modify the colour of text,
82
+they should use textcolour, fontsize to avoid the confusion with bar layer annotation.
83
+
84
+\code{geom_striplab()} understands the following aesthethics for geom="label" (required
85
+aesthetics are in bold):
86
+\itemize{
87
+\item \strong{\code{taxa1}} selected node to hight light, it is required.
88
+\item \strong{\code{taxa2}} selected another tip label or tip node, it is required.
89
+\item \strong{\code{label}} labels to be shown, it is required.
90
+\item \code{colour} the colour of text, default is "black".
91
+\item \code{fill} the background colour of the label, default is "white".
92
+\item \code{size} the size of text, default is 3.88.
93
+\item \code{angle} the angle of text, default is 0.
94
+\item \code{hjust} A numeric vector specifying horizontal justification, default is 0.
95
+\item \code{vjust} A numeric vector specifying vertical justification, default is 0.5.
96
+\item \code{alpha} the transparency of text, default is NA.
97
+\item \code{family} the family of text, default is 'sans'.
98
+\item \code{fontface} the font face of text, default is 1 (plain), others are
99
+2 (bold), 3 (italic), 4 (bold.italic).
100
+\item \code{lineheight} The height of a line as a multiple of the size of text, default is 1.2 .
101
+}
102
+when the colour, size are not be set in mapping, and user want to modify the colour of text,
103
+they should use textcolour, fontsize to avoid the confusion with bar layer annotation.
104
+
105
+\code{geom_striplab()} understands the following aesthethics for geom="shadowtext" (required
106
+aesthetics are in bold):
107
+\itemize{
108
+\item \strong{\code{taxa1}} selected node to hight light, it is required.
109
+\item \strong{\code{taxa2}} selected another tip label or tip node, it is required.
110
+\item \strong{\code{label}} labels to be shown, it is required.
111
+\item \code{colour} the colour of text, default is "black".
112
+\item \code{bg.colour} the background colour of text, default is 'black'.
113
+\item \code{bg.r} the width of background text, default is 0.1.
114
+\item \code{size} the size of text, default is 3.88.
115
+\item \code{angle} the angle of text, default is 0.
116
+\item \code{hjust} A numeric vector specifying horizontal justification, default is 0.
117
+\item \code{vjust} A numeric vector specifying vertical justification, default is 0.5.
118
+\item \code{alpha} the transparency of text, default is NA.
119
+\item \code{family} the family of text, default is 'sans'.
120
+\item \code{fontface} the font face of text, default is 1 (plain), others are
121
+2 (bold), 3 (italic), 4 (bold.italic).
122
+\item \code{lineheight} The height of a line as a multiple of the size of text, default is 1.2 .
123
+}
124
+when the colour, size are not be set in mapping, and user want to modify the colour of text,
125
+they should use textcolour, fontsize to avoid the confusion with bar layer annotation.
126
+
127
+\code{geom_striplab()} understands the following aesthethics for geom="image" or geom="phylopic" (required
128
+aesthetics are in bold):
129
+\itemize{
130
+\item \strong{\code{taxa1}} selected node to hight light, it is required.
131
+\item \strong{\code{taxa2}} selected another tip label or tip node, it is required.
132
+\item \strong{\code{label}} labels to be shown, it is required.
133
+\item \strong{\code{image}} the image to be annotated, when geom="phylopic",
134
+the uid of phylopic databases, it is required.
135
+\item \code{colour} the color of image, default is NULL.
136
+\item \code{size} the size of image, default is 0.05.
137
+\item \code{alpha} the alpha of image, default is 0.8.
138
+}
139
+when the colour, size are not be set in mapping, and user want to modify the colour of image,
140
+they should use imagecolour, imagesize to avoid the confusion with bar layer annotation.
141
+}
142
+
143
+\examples{
144
+set.seed(123)
145
+tr <- rtree(10)
146
+dt <- data.frame(ta1=c("t5", "t1"), ta2=c("t6", "t3"), group=c("A", "B"))
147
+p <- ggtree(tr) + geom_tiplab()
148
+p2 <- p + 
149
+      geom_striplab(
150
+        data = dt,
151
+        mapping = aes(taxa1 = ta1, taxa2 = ta2, 
152
+                      label = group, color=group),
153
+        align = TRUE,
154
+        show.legend = FALSE
155
+      )
156
+p2
157
+}