1 : |
tdhock |
268 |
uselegend.ggplot <- function
|
2 : |
|
|
### Show the ggplot2 legend, for comparison.
|
3 : |
|
|
(p,
|
4 : |
|
|
### The ggplot object.
|
5 : |
|
|
...
|
6 : |
|
|
### Ignored.
|
7 : |
|
|
){
|
8 : |
|
|
p
|
9 : |
|
|
}
|
10 : |
|
|
|
11 : |
tdhock |
490 |
geom_dl <- structure(function
|
12 : |
|
|
### Geom that will plot direct labels.
|
13 : |
|
|
(mapping=NULL,
|
14 : |
|
|
### aes(label=variable_that_will_be_used_as_groups_in_Positioning_Methods).
|
15 : |
|
|
method,
|
16 : |
|
|
### Positioning Method.
|
17 : |
tdhock |
685 |
...,
|
18 : |
tdhock |
497 |
### passed to GeomDirectLabel$new. ie stat= position= debug=
|
19 : |
tdhock |
685 |
show_guide=FALSE
|
20 : |
|
|
### show legend? default FALSE since direct labels replace a legend.
|
21 : |
tdhock |
490 |
){
|
22 : |
tdhock |
473 |
require(ggplot2)
|
23 : |
tdhock |
572 |
require(proto)
|
24 : |
tdhock |
473 |
## Geom for direct labeling that creates dlgrobs in the draw()
|
25 : |
|
|
## method.
|
26 : |
tdhock |
561 |
GeomDirectLabel <- proto(ggplot2:::Geom, {
|
27 : |
tdhock |
473 |
draw_groups <- function(., ...) .$draw(...)
|
28 : |
|
|
draw <- function(., data, scales, coordinates,
|
29 : |
|
|
method=NULL,debug=FALSE, ...) {
|
30 : |
|
|
data$rot <- as.integer(data$angle)
|
31 : |
tdhock |
474 |
data$groups <- data$label
|
32 : |
tdhock |
561 |
axes2native <- function(data){
|
33 : |
tdhock |
652 |
ggplot2:::coord_transform(coordinates,data,scales)
|
34 : |
tdhock |
561 |
}
|
35 : |
tdhock |
652 |
converted <- axes2native(data)
|
36 : |
|
|
dldata <- converted[,names(converted)!="group"]
|
37 : |
|
|
dlgrob(dldata,
|
38 : |
tdhock |
499 |
method,debug=debug,
|
39 : |
tdhock |
561 |
axes2native=axes2native)
|
40 : |
tdhock |
473 |
}
|
41 : |
tdhock |
474 |
draw_legend <- function(.,data,...){
|
42 : |
tdhock |
678 |
nullGrob()
|
43 : |
tdhock |
474 |
}
|
44 : |
|
|
objname <- "dl"
|
45 : |
|
|
desc <- "Direct labels"
|
46 : |
tdhock |
652 |
default_stat <- function(.) ggplot2:::StatIdentity
|
47 : |
tdhock |
474 |
required_aes <- c("x", "y", "label")
|
48 : |
tdhock |
473 |
default_aes <- function(.)
|
49 : |
|
|
aes(colour="black", size=5 , angle=0, hjust=0.5, vjust=0.5, alpha = 1)
|
50 : |
tdhock |
469 |
})
|
51 : |
tdhock |
685 |
GeomDirectLabel$new(mapping, method=method, show_guide=show_guide, ...)
|
52 : |
tdhock |
490 |
### Layer that will plot direct labels.
|
53 : |
tdhock |
474 |
},ex=function(){
|
54 : |
tdhock |
501 |
library(ggplot2)
|
55 : |
tdhock |
474 |
vad <- as.data.frame.table(VADeaths)
|
56 : |
|
|
names(vad) <- c("age","demographic","deaths")
|
57 : |
tdhock |
497 |
## color + legend
|
58 : |
|
|
leg <- ggplot(vad,aes(deaths,age,colour=demographic))+
|
59 : |
tdhock |
518 |
geom_line(aes(group=demographic))+
|
60 : |
|
|
xlim(8,80)
|
61 : |
|
|
print(direct.label(leg,list("last.points",rot=30)))
|
62 : |
|
|
## this is what direct.label is doing internally:
|
63 : |
|
|
labeled <- leg+
|
64 : |
|
|
geom_dl(aes(label=demographic),list("last.points",rot=30))+
|
65 : |
tdhock |
561 |
scale_colour_discrete(guide="none")
|
66 : |
tdhock |
518 |
print(labeled)
|
67 : |
tdhock |
474 |
## no color, just direct labels!
|
68 : |
|
|
p <- ggplot(vad,aes(deaths,age))+
|
69 : |
|
|
geom_line(aes(group=demographic))+
|
70 : |
|
|
geom_dl(aes(label=demographic),method="top.qp")
|
71 : |
|
|
print(p)
|
72 : |
|
|
## add color:
|
73 : |
|
|
p+aes(colour=demographic)+
|
74 : |
tdhock |
561 |
scale_colour_discrete(guide="none")
|
75 : |
tdhock |
474 |
## add linetype:
|
76 : |
|
|
p+aes(linetype=demographic)+
|
77 : |
tdhock |
561 |
scale_linetype(guide="none")
|
78 : |
tdhock |
474 |
## no color, just direct labels
|
79 : |
tdhock |
648 |
library(nlme)
|
80 : |
tdhock |
476 |
bwbase <- ggplot(BodyWeight,aes(Time,weight,label=Rat))+
|
81 : |
tdhock |
474 |
geom_line(aes(group=Rat))+
|
82 : |
tdhock |
561 |
facet_grid(.~Diet)
|
83 : |
tdhock |
476 |
bw <- bwbase+geom_dl(method="last.qp")
|
84 : |
tdhock |
474 |
print(bw)
|
85 : |
|
|
## add some more direct labels
|
86 : |
|
|
bw2 <- bw+geom_dl(method="first.qp")
|
87 : |
|
|
print(bw2)
|
88 : |
|
|
## add color
|
89 : |
tdhock |
518 |
colored <- bw2+aes(colour=Rat)+
|
90 : |
tdhock |
561 |
scale_colour_discrete(guide="none")
|
91 : |
tdhock |
518 |
print(colored)
|
92 : |
|
|
## or just use direct.label if you use color:
|
93 : |
|
|
direct.label(bwbase+aes(colour=Rat),dl.combine("first.qp","last.qp"))
|
94 : |
|
|
|
95 : |
|
|
## iris data example
|
96 : |
|
|
giris <- ggplot(iris,aes(Petal.Length,Sepal.Length))+
|
97 : |
|
|
geom_point(aes(shape=Species))
|
98 : |
|
|
giris.labeled <- giris+
|
99 : |
|
|
geom_dl(aes(label=Species),method="smart.grid")+
|
100 : |
|
|
scale_shape_manual(values=c(setosa=1,virginica=6,versicolor=3),
|
101 : |
tdhock |
561 |
guide="none")
|
102 : |
tdhock |
518 |
##png("~/R/directlabels/www/scatter-bw-ggplot2.png",h=503,w=503)
|
103 : |
|
|
print(giris.labeled)
|
104 : |
|
|
##dev.off()
|
105 : |
tdhock |
474 |
})
|
106 : |
tdhock |
475 |
|
107 : |
tdhock |
122 |
direct.label.ggplot <- function
|
108 : |
|
|
### Direct label a ggplot2 grouped plot.
|
109 : |
|
|
(p,
|
110 : |
|
|
### The ggplot object.
|
111 : |
|
|
method=NULL,
|
112 : |
tdhock |
659 |
### Method for direct labeling as described in
|
113 : |
|
|
### \code{\link{apply.method}}.
|
114 : |
tdhock |
122 |
debug=FALSE
|
115 : |
|
|
### Show debug output?
|
116 : |
|
|
){
|
117 : |
tdhock |
394 |
require(ggplot2)
|
118 : |
tdhock |
678 |
getData <- function(colour.or.fill){
|
119 : |
|
|
for(L in p$layers){
|
120 : |
|
|
m <- p$mapping
|
121 : |
|
|
m[names(L$mapping)] <- L$mapping
|
122 : |
|
|
## TODO: what if this is an expression and not a variable name?
|
123 : |
|
|
colvar <- m[[colour.or.fill]]
|
124 : |
|
|
if(!is.null(colvar)){
|
125 : |
|
|
return(list(layer=L, colvar=as.character(colvar)))
|
126 : |
|
|
}
|
127 : |
|
|
}
|
128 : |
|
|
}
|
129 : |
|
|
dl.info <- getData("colour")
|
130 : |
|
|
if(is.null(dl.info)){
|
131 : |
|
|
dl.info <- getData("fill")
|
132 : |
|
|
}
|
133 : |
|
|
if(is.null(dl.info)){
|
134 : |
|
|
stop("Need colour or fill aesthetic to infer default direct labels.")
|
135 : |
|
|
}
|
136 : |
|
|
L <- dl.info$layer
|
137 : |
|
|
colvar <- dl.info$colvar
|
138 : |
tdhock |
476 |
## Try to figure out a good default based on the colored geom
|
139 : |
tdhock |
399 |
geom <- L$geom$objname
|
140 : |
tdhock |
319 |
if(is.null(method))method <- default.picker("ggplot")
|
141 : |
tdhock |
591 |
data <- if( (!is.null(L$data)) && (length(L$data) > 0) ){
|
142 : |
|
|
L$data
|
143 : |
|
|
}else{
|
144 : |
|
|
NULL
|
145 : |
|
|
}
|
146 : |
tdhock |
678 |
a <- aes_string(label=colvar, colour=colvar)
|
147 : |
tdhock |
663 |
a2 <- structure(c(L$mapping, a), class="uneval")
|
148 : |
|
|
dlgeom <- geom_dl(a2,method,
|
149 : |
tdhock |
591 |
stat=L$stat,debug=debug,data=data)
|
150 : |
tdhock |
649 |
dlgeom$stat_params <- L$stat_params
|
151 : |
tdhock |
678 |
## Look through legends for a colour/fill legend.
|
152 : |
|
|
leg.info <- legends2hide(p)
|
153 : |
|
|
guide.args <- as.list(rep("none", length(leg.info$hide)))
|
154 : |
|
|
names(guide.args) <- leg.info$hide
|
155 : |
|
|
guide.args$colour <- "none"
|
156 : |
|
|
guide <- do.call(guides, guide.args)
|
157 : |
|
|
p+dlgeom+guide
|
158 : |
tdhock |
122 |
### The ggplot object with direct labels added.
|
159 : |
|
|
}
|
160 : |
tdhock |
319 |
|
161 : |
tdhock |
678 |
### Extract guides to hide from a ggplot.
|
162 : |
|
|
legends2hide <- function(p){
|
163 : |
tdhock |
683 |
plistextra <- ggplot2::ggplot_build(p)
|
164 : |
tdhock |
678 |
plot <- plistextra$plot
|
165 : |
|
|
scales = plot$scales
|
166 : |
|
|
layers = plot$layers
|
167 : |
|
|
default_mapping = plot$mapping
|
168 : |
|
|
theme <- ggplot2:::plot_theme(plot)
|
169 : |
|
|
position <- theme$legend.position
|
170 : |
|
|
# by default, guide boxes are vertically aligned
|
171 : |
|
|
theme$legend.box <- if(is.null(theme$legend.box)) "vertical" else theme$legend.box
|
172 : |
|
|
|
173 : |
|
|
# size of key (also used for bar in colorbar guide)
|
174 : |
|
|
theme$legend.key.width <- if(is.null(theme$legend.key.width)) theme$legend.key.size
|
175 : |
|
|
theme$legend.key.height <- if(is.null(theme$legend.key.height)) theme$legend.key.size
|
176 : |
|
|
# by default, direction of each guide depends on the position of the guide.
|
177 : |
|
|
theme$legend.direction <- if(is.null(theme$legend.direction)){
|
178 : |
|
|
if (length(position) == 1 && position %in% c("top", "bottom", "left", "right"))
|
179 : |
|
|
switch(position[1], top =, bottom = "horizontal", left =, right = "vertical")
|
180 : |
|
|
else
|
181 : |
|
|
"vertical"
|
182 : |
|
|
}
|
183 : |
|
|
# justification of legend boxes
|
184 : |
|
|
theme$legend.box.just <-
|
185 : |
|
|
if(is.null(theme$legend.box.just)) {
|
186 : |
|
|
if (length(position) == 1 && position %in% c("top", "bottom", "left", "right"))
|
187 : |
|
|
switch(position, bottom =, top = c("center", "top"), left =, right = c("left", "top"))
|
188 : |
|
|
else
|
189 : |
|
|
c("center", "center")
|
190 : |
|
|
}
|
191 : |
|
|
|
192 : |
|
|
position <- theme$legend.position
|
193 : |
|
|
defaults <- function (x, y) {
|
194 : |
|
|
c(x, y[setdiff(names(y), names(x))])
|
195 : |
|
|
}
|
196 : |
|
|
|
197 : |
|
|
guides <- defaults(plot$guides, guides(colour="legend", fill="legend"))
|
198 : |
|
|
labels <- plot$labels
|
199 : |
|
|
gdefs <- ggplot2:::guides_train(scales = scales, theme = theme,
|
200 : |
|
|
guides = guides, labels = labels)
|
201 : |
|
|
if (length(gdefs) != 0) {
|
202 : |
|
|
gdefs <- ggplot2:::guides_merge(gdefs)
|
203 : |
|
|
gdefs <- ggplot2:::guides_geom(gdefs, layers, default_mapping)
|
204 : |
|
|
} else (ggplot2:::zeroGrob())
|
205 : |
|
|
var.list <- lapply(gdefs, getLegendVariables)
|
206 : |
|
|
for(v in c("colour", "fill")){
|
207 : |
|
|
for(L in var.list){
|
208 : |
|
|
if(v %in% L$var){
|
209 : |
|
|
return(list(colour=v, hide=L$var, data=L$data))
|
210 : |
|
|
}
|
211 : |
|
|
}
|
212 : |
|
|
}
|
213 : |
|
|
### NULL if no legends with colour or fill to hide.
|
214 : |
|
|
}
|
215 : |
|
|
|
216 : |
|
|
### get the aes which are variable in one legend.
|
217 : |
|
|
getLegendVariables <- function(mb){
|
218 : |
|
|
guidetype <- mb$name
|
219 : |
|
|
key <- mb$key
|
220 : |
|
|
results <- list()
|
221 : |
|
|
for(g in mb$geoms){
|
222 : |
|
|
orig <- g$data
|
223 : |
|
|
geom <- g$geom$objname
|
224 : |
|
|
if(nrow(orig)==0) return(data.frame()); # if no rows, return an empty df.
|
225 : |
|
|
orig$order <- 1:nrow(orig)
|
226 : |
|
|
count.na <- function(x)sum(is.na(x))
|
227 : |
|
|
orig.na <- sapply(orig, count.na)>0
|
228 : |
|
|
key.na <- sapply(key, count.na)>0
|
229 : |
|
|
by <- intersect(names(orig.na)[!orig.na], names(key.na)[!key.na])
|
230 : |
|
|
data <- merge(orig, key, by=by)
|
231 : |
|
|
data <- data[order(data$order),]
|
232 : |
|
|
## old code above.
|
233 : |
|
|
data <- data.frame(orig, key)
|
234 : |
|
|
## if there are no labels, return an empty df.
|
235 : |
|
|
if(!".label"%in%names(data)) return(data.frame());
|
236 : |
|
|
## remove cols that are entirely na
|
237 : |
|
|
results[[length(results)+1]] <- data[,which(colSums(!is.na(data))>0)]
|
238 : |
|
|
}
|
239 : |
|
|
results <- results[which(sapply(results, nrow)>0)]
|
240 : |
|
|
df <- merge_recurse(results)
|
241 : |
|
|
variable <- c()
|
242 : |
|
|
for(v in c("colour", "fill", "size", "shape", "linetype")){
|
243 : |
|
|
vals <- df[[v]]
|
244 : |
|
|
first <- vals[1]
|
245 : |
|
|
if(!is.null(first) && !is.na(first)){
|
246 : |
|
|
constant <- all(first == vals)
|
247 : |
|
|
if(!constant){
|
248 : |
|
|
variable <- c(variable, v)
|
249 : |
|
|
}
|
250 : |
|
|
}
|
251 : |
|
|
}
|
252 : |
|
|
list(variable=variable,
|
253 : |
|
|
data=df)
|
254 : |
|
|
}
|
255 : |
|
|
|
256 : |
|
|
### Copied from reshape.
|
257 : |
|
|
merge_recurse <- function (dfs, ...) {
|
258 : |
|
|
if (length(dfs) == 1) {
|
259 : |
|
|
dfs[[1]]
|
260 : |
|
|
}
|
261 : |
|
|
else if (length(dfs) == 2) {
|
262 : |
|
|
merge(dfs[[1]], dfs[[2]], all.x = TRUE, sort = FALSE, ...)
|
263 : |
|
|
}
|
264 : |
|
|
else {
|
265 : |
|
|
merge(dfs[[1]], Recall(dfs[-1]), all.x = TRUE, sort = FALSE,
|
266 : |
|
|
...)
|
267 : |
|
|
}
|
268 : |
|
|
}
|
269 : |
|
|
|
270 : |
tdhock |
319 |
defaultpf.ggplot <- function
|
271 : |
|
|
### Default method selection method for ggplot2 plots.
|
272 : |
tdhock |
542 |
(geom,p,L,colvar,...){
|
273 : |
tdhock |
319 |
switch(geom,
|
274 : |
tdhock |
476 |
density="top.bumptwice",
|
275 : |
tdhock |
319 |
line={
|
276 : |
tdhock |
581 |
groups <- L$data[[colvar]]
|
277 : |
|
|
if(is.null(groups))groups <- p$data[[colvar]]
|
278 : |
|
|
if(nlevels(groups)==2)"lines2" else "maxvar.qp"
|
279 : |
tdhock |
319 |
},
|
280 : |
tdhock |
476 |
point="smart.grid",
|
281 : |
tdhock |
487 |
path="bottom.pieces",
|
282 : |
tdhock |
678 |
ribbon="maxvar.qp",
|
283 : |
tdhock |
319 |
stop("No default label placement for this type of ggplot."))
|
284 : |
|
|
}
|
285 : |
|
|
|