Skip to content

Commit 46d7a80

Browse files
committed
Rewrite of default label handling
1 parent ddb3782 commit 46d7a80

File tree

10 files changed

+84
-72
lines changed

10 files changed

+84
-72
lines changed

NEWS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,10 @@ ggplot2 0.8.5 (2009-XX-XX) ----------------------------------------
2222
value. This was always a good idea, but now it is enforced with an
2323
informative error message.
2424
* xlim, ylim: fix bug when setting limits of discrete scales
25+
* labels are now stored in the options, rather than in individual scales.
26+
This fixes a long standing bug where it was not easy to set the label for
27+
computed variable, such as the y axis on a histogram. Additionally, it means
28+
default scales are only added to the plot until just prior to plotting,
29+
instead of the previous behaviour where scales where added as layers were
30+
added - this could cause problems if you layer modified the plot.
31+
(Implements #28)

R/aes.r

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
# @alias str.uneval
3737
# @alias print.uneval
3838
# @alias [.uneval
39+
# @alias as.character.uneval
3940
# @seealso \code{\link{aes_string}}
4041
#X aes(x = mpg, y = wt)
4142
#X aes(x = mpg ^ 2, y = wt / cyl)
@@ -118,6 +119,12 @@ print.uneval <- function(x, ...) str(unclass(x))
118119
str.uneval <- function(object, ...) str(unclass(object), ...)
119120
"[.uneval" <- function(x, i, ...) structure(unclass(x)[i], class = "uneval")
120121

122+
as.character.uneval <- function(x, ...) {
123+
char <- as.character(unclass(x))
124+
names(char) <- names(x)
125+
char
126+
}
127+
121128
# Aesthetic defaults
122129
# Convenience method for setting aesthetic defaults
123130
#

R/facet-.r

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ Facet <- proto(TopLevel, {
1717
params[setdiff(names(params), c(".","variable"))]
1818
}
1919

20-
xlabel <- function(., theme)
21-
.$scales$x[[1]]$name
20+
xlabel <- function(., theme) {
21+
nulldefault(.$scales$x[[1]]$name, theme$labels$x)
22+
}
23+
2224
ylabel <- function(., theme)
23-
.$scales$y[[1]]$name
25+
nulldefault(.$scales$y[[1]]$name, theme$labels$y)
2426
})

R/guides-legend.r

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,25 @@ guide_legends_box <- function(scales, layers, default_mapping, horizontal = FALS
6161
#X qplot(mpg, wt, data = mtcars, colour = cyl2)
6262
#X theme_set(theme_grey())
6363
guide_legends <- function(scales, layers, default_mapping, theme) {
64-
legends <- scales$legend_desc()
65-
if (length(legends) == 0) return()
64+
legend <- scales$legend_desc(theme)
65+
if (length(legend$titles) == 0) return()
6666

67-
lapply(names(legends), function(var) {
68-
build_legend(var, legends[[var]], layers, default_mapping, theme)
67+
titles <- unique(legend$titles)
68+
lapply(titles, function(title) {
69+
keys <- legend$keys[sapply(legend$titles, identical, title)]
70+
if (length(keys) > 1) {
71+
# Multiple scales for this legend
72+
keys <- merge_recurse(keys, by = c(".value", ".label"))
73+
} else {
74+
keys <- keys[[1]]
75+
}
76+
77+
build_legend(title, keys, layers, default_mapping, theme)
6978
})
7079
}
7180

7281
build_legend <- function(name, mapping, layers, default_mapping, theme) {
7382
legend_data <- llply(layers, build_legend_data, mapping, default_mapping)
74-
# if (length(legend_data) == 0) return(zeroGrob())
75-
# browser()
7683

7784
# Calculate sizes for keys - mainly for v. large points and lines
7885
size_mat <- do.call("cbind", llply(legend_data, "[[", "size"))
@@ -82,10 +89,6 @@ build_legend <- function(name, mapping, layers, default_mapping, theme) {
8289
key_heights <- apply(size_mat, 1, max)
8390
}
8491

85-
# points <- laply(layers, function(l) l$geom$objname == "point")
86-
width <- max(unlist(llply(legend_data, "[[", "size")), 0)
87-
88-
name <- eval(parse(text = name))
8992
title <- theme_render(
9093
theme, "legend.title",
9194
name, x = 0, y = 0.5
@@ -96,6 +99,8 @@ build_legend <- function(name, mapping, layers, default_mapping, theme) {
9699
hgap <- vgap <- unit(0.3, "lines")
97100

98101
label_width <- max(stringWidth(mapping$.label))
102+
103+
width <- max(unlist(llply(legend_data, "[[", "size")), 0)
99104
key_width <- max(theme$legend.key.size, unit(width, "mm"))
100105

101106
widths <- unit.c(

R/labels.r

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,7 @@
1111
#X update_labels(p, list(colour = "Fail silently"))
1212
update_labels <- function(p, labels) {
1313
p <- plot_clone(p)
14-
15-
for(name in names(labels)) {
16-
scale <- p$scales$get_scales(name)$clone()
17-
p$scales$add(scale)
18-
scale$name <- labels[[name]]
19-
}
20-
21-
p
14+
p + opts(labels = labels)
2215
}
2316

2417
# Change axis labels and legend titles

R/plot-construction.r

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
if (is.data.frame(object)) {
2323
p$data <- object
2424
} else if (inherits(object, "options")) {
25+
object$labels <- defaults(object$labels, p$options$labels)
2526
p$options <- defaults(object, p$options)
2627
} else if(inherits(object, "labels")) {
2728
p <- update_labels(p, object)
@@ -39,9 +40,13 @@
3940
p <- switch(object$class(),
4041
layer = {
4142
p$layers <- append(p$layers, object)
42-
data <- if(empty(object$data)) p$data else object$data
43-
mapping <- object$mapping %||% p$mapping
44-
p$scales$add_defaults(data, mapping, p$plot_env)
43+
44+
# Add any new labels
45+
mapping <- as.list(as.character(object$mapping))
46+
default <- as.list(as.character(object$stat$default_aes()))
47+
48+
new_labels <- defaults(mapping, default)
49+
p$options$labels <- defaults(p$options$labels, new_labels)
4550
p
4651
},
4752
coord = {

R/plot-render.r

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ ggplotGrob <- function(plot, drop = plot$options$drop, keep = plot$options$keep,
5353
horiz <- any(c("top", "bottom") %in% position)
5454
vert <- any(c("left", "right") %in% position)
5555

56-
56+
5757
# Generate grobs -----------------------------------------------------------
5858
# each of these grobs has a vp set
5959

@@ -66,8 +66,8 @@ ggplotGrob <- function(plot, drop = plot$options$drop, keep = plot$options$keep,
6666
title <- theme_render(theme, "plot.title", plot$options$title)
6767

6868
labels <- cs$labels(list(
69-
x = pieces$facet$xlabel(),
70-
y = pieces$facet$ylabel())
69+
x = pieces$facet$xlabel(theme),
70+
y = pieces$facet$ylabel(theme))
7171
)
7272
xlabel <- theme_render(theme, "axis.title.x", labels$x)
7373
ylabel <- theme_render(theme, "axis.title.y", labels$y)

R/plot.r

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ ggplot.data.frame <- function(data, mapping=aes(), ..., environment = globalenv(
3333
plot_env = environment
3434
), class="ggplot")
3535

36-
p$scales$add_defaults(p$data, p$mapping, p$plot_env)
36+
p$options$labels <- as.list(as.character(mapping))
3737

3838
set_last_plot(p)
3939
p

R/quick-plot.r

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ qplot <- function(x, y = NULL, z=NULL, ..., data, facets = . ~ ., margins=FALSE,
8888
stat <- "qq"
8989
} else if (missing(y)) {
9090
geom[geom == "auto"] <- "histogram"
91+
if (is.null(ylab)) ylab <- "count"
9192
} else {
9293
if (missing(x)) {
9394
aesthetics$x <- bquote(seq_along(.(y)), aesthetics)

R/scales-.r

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,11 @@ Scales <- proto(Scale, expr={
1212
n <- function(.) length(.$.scales)
1313

1414
add <- function(., scale) {
15+
# Remove old scale if it exists
1516
old <- .$find(scale$output())
16-
17-
if (length(old) > 0 && sum(old) == 1 && is.null(scale$name)) {
18-
scale <- scale$clone()
19-
scale$name <- .$.scales[old][[1]]$name
20-
}
21-
2217
.$.scales[old] <- NULL
18+
19+
# Add new scale
2320
.$.scales <- append(.$.scales, scale)
2421
}
2522

@@ -56,30 +53,33 @@ Scales <- proto(Scale, expr={
5653
Filter(function(x) x$trained(), .$.scales)
5754
}
5855

59-
get_scales_by_name <- function(., input) {
60-
Filter(function(s) deparse(s$name) == input, .$get_trained_scales())
61-
}
62-
63-
variables <- function(.) {
64-
unique(sapply(.$.scales, function(scale) deparse(scale$name)))
65-
}
66-
67-
legend_desc <- function(.) {
68-
# For each input aesthetic, get breaks and labels
69-
vars <- .$variables()
70-
names(vars) <- vars
71-
compact(lapply(vars, function(var) {
72-
scales <- .$get_scales_by_name(var)
73-
# Remove scales with legend == FALSE
74-
scales <- Filter(function(y) y$legend, scales)
75-
if (length(scales) == 0) return()
56+
legend_desc <- function(., theme) {
57+
# Loop through all scales, creating a list of titles, and a list of keys
58+
keys <- titles <- vector("list", .$n())
59+
60+
for(i in seq_len(.$n())) {
61+
scale <- .$.scales[[i]]
62+
if (!scale$legend) next
7663

77-
breaks <- as.data.frame(lapply(scales, function(s) s$output_breaks()))
78-
names(breaks) <- lapply(scales, function(s) s$output())
64+
# Figure out legend title
65+
output <- scale$output()
66+
if (!is.null(scale$name)) {
67+
titles[[i]] <- scale$name
68+
} else {
69+
titles[[i]] <- theme$labels[[output]]
70+
}
7971

80-
breaks$.labels <- scales[[1]]$labels()
81-
breaks
82-
}))
72+
key <- data.frame(
73+
scale$output_breaks(), scale$input_breaks(), I(scale$labels()))
74+
names(key) <- c(output, ".value", ".label")
75+
76+
keys[[i]] <- key
77+
}
78+
79+
empty <- sapply(titles, is.null)
80+
81+
list(titles = titles[!empty], keys = keys[!empty])
82+
8383
}
8484

8585
position_scales <- function(.) {
@@ -138,9 +138,8 @@ Scales <- proto(Scale, expr={
138138
# Add default scales.
139139
# Add default scales to a plot.
140140
#
141-
# Called everytime a layer is added to the plot, so that default
142-
# scales are always available for modification. The type of a scale is
143-
# fixed by the first use in a layer.
141+
# Called during final construction to ensure that all aesthetics have
142+
# a scale
144143
add_defaults <- function(., data, aesthetics, env) {
145144
if (is.null(aesthetics)) return()
146145
names(aesthetics) <- laply(names(aesthetics), aes_to_scale)
@@ -150,9 +149,6 @@ Scales <- proto(Scale, expr={
150149
# No new aesthetics, so no new scales to add
151150
if(is.null(new_aesthetics)) return()
152151

153-
# Compute default scale names
154-
names <- as.vector(sapply(aesthetics[new_aesthetics], deparse))
155-
156152
# Determine variable type for each column -------------------------------
157153
vartype <- function(x) {
158154
if (inherits(x, "Date")) return("date")
@@ -177,18 +173,14 @@ Scales <- proto(Scale, expr={
177173
scale_name_generic <- paste("scale", vartypes, sep="_")
178174

179175
for(i in 1:length(new_aesthetics)) {
180-
s <- tryNULL(get(scale_name_type[i]))
181-
if (!is.null(s)) {
182-
.$add(s(name=names[i]))
176+
scale <- tryNULL(get(scale_name_type[i]))
177+
if (!is.null(scale)) {
178+
.$add(scale())
183179
} else {
184-
s <- tryNULL(get(scale_name[i]))
185-
if (!is.null(s)) {
186-
.$add(s(name=names[i]))
180+
scale <- tryNULL(get(scale_name[i]))
181+
if (!is.null(scale)) {
182+
.$add(scale())
187183
}
188-
# } else {
189-
# s <- tryNULL(get(scale_name_generic[i]))
190-
# .$add(s(name=names[i], variable=new_aesthetics[i]))
191-
# }
192184
}
193185
}
194186

0 commit comments

Comments
 (0)