Skip to content

element inheritance in themes #1579

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@
* Fixed a compatibility issue with `ggproto` and R versions prior to 3.1.2.
(#1444)

<<<<<<< HEAD
* All elements should now inherit correctly for all themes except theme_void(). (@Katiedaisey, #1555)

* Inheritance of elements pull from default if parent is element_blank(). (@Katiedaisey, #1565)

=======
>>>>>>> hadley/master
# ggplot2 2.0.0

## Major changes
Expand Down
17 changes: 7 additions & 10 deletions R/theme-defaults.r
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ theme_grey <- function(base_size = 11, base_family = "") {
),

axis.line = element_line(),
axis.line.x = element_blank(),
axis.line.y = element_blank(),
axis.text = element_text(size = rel(0.8), colour = "grey30"),
axis.text.x = element_text(margin = margin(t = 0.8 * half_line / 2), vjust = 1),
axis.text.y = element_text(margin = margin(r = 0.8 * half_line / 2), hjust = 1),
Expand Down Expand Up @@ -221,8 +219,6 @@ theme_minimal <- function(base_size = 12, base_family = "") {
strip.background = element_blank(),
plot.background = element_blank(),
axis.ticks = element_line(),
axis.ticks.x = element_blank(),
axis.ticks.y = element_blank(),
axis.ticks.length = unit(1, "lines")
)
}
Expand All @@ -234,12 +230,8 @@ theme_classic <- function(base_size = 12, base_family = ""){
theme(
panel.border = element_blank(),
axis.line = element_line(colour = "black"),
panel.grid.major = element_line(),
panel.grid.major.x = element_blank(),
panel.grid.major.y = element_blank(),
panel.grid.minor = element_line(),
panel.grid.minor.x = element_blank(),
panel.grid.minor.y = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
strip.background = element_rect(colour = "black", size = 0.5),
legend.key = element_blank()
)
Expand Down Expand Up @@ -284,13 +276,18 @@ theme_void <- function(base_size = 12, base_family = "") {
margin = margin(), debug = FALSE
),
plot.margin = unit(c(0, 0, 0, 0), "lines"),
panel.background = element_blank(),
panel.grid.major = element_blank(),
axis.line = element_blank(),
axis.ticks = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
legend.text = element_text(size = rel(0.8)),
legend.title = element_blank(),
strip.text = element_text(size = rel(0.8)),
strip.background = element_blank(),

complete = TRUE
)
Expand Down
2 changes: 1 addition & 1 deletion R/theme-elements.r
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) {
legend.title.align = el_def("character"),
legend.position = el_def("character"), # Need to also accept numbers
legend.direction = el_def("character"),
legend.justification = el_def("character"),
legend.justification = el_def("character"), # Need to also accept numbers
legend.box = el_def("character"),
legend.box.just = el_def("character"),

Expand Down
58 changes: 49 additions & 9 deletions R/theme.r
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,11 @@ add_theme <- function(t1, t2, t2name) {
t1[item] <- list(x)
}

# Update inherited items
for (item in names(t2)) {
t1[[item]] <- calc_element(item, t1)
}

# If either theme is complete, then the combined theme is complete
attr(t1, "complete") <- attr(t1, "complete") || attr(t2, "complete")
t1
Expand Down Expand Up @@ -537,6 +542,12 @@ calc_element <- function(element, theme, verbose = FALSE) {
# it is of the class specified in .element_tree
if (!is.null(theme[[element]]) &&
!inherits(theme[[element]], .element_tree[[element]]$class)) {
if (element != "legend.position" && element != "legend.justification") {
stop(element, " should have class ", .element_tree[[element]]$class)
}
}

if ((element == "legend.position" || element == "legend.justification") && (class(theme[[element]])[1] != "character" && class(theme[[element]])[1] != "numeric")) {
stop(element, " should have class ", .element_tree[[element]]$class)
}

Expand Down Expand Up @@ -571,20 +582,49 @@ calc_element <- function(element, theme, verbose = FALSE) {
# @param e2 An element object which e1 inherits from
combine_elements <- function(e1, e2) {

# If e2 is NULL, nothing to inherit
if (is.null(e2)) return(e1)
# If e1 is NULL or element_blank, inherit everything
if (is.null(e1) || inherits(e1, "element_blank")) {e1 <- e2}

# If e1 is not NULL or blank and e2 is element_blank, inherit everything from root
if ((!is.null(e1) || !inherits(e1, "element_blank")) && (is.null(e2) || inherits(e2, "element_blank"))) {
e3 <- base_class(e1)
n <- vapply(e1[names(e3)], is.null, logical(1))
e1[n] <- e3[n]
}

# If e1 is NULL, or if e2 is element_blank, inherit everything from e2
if (is.null(e1) || inherits(e2, "element_blank")) return(e2)
# If e1 and e2 are not NULL or blank, inherit from e2 then root
if ((!is.null(e1) && !inherits(e1, "element_blank")) && (!is.null(e2) && !inherits(e2, "element_blank"))) {
# inherit from e2
n <- vapply(e1[names(e2)], is.null, logical(1))
e1[n] <- e2[n]

# If e1 has any NULL properties, inherit them from e2
n <- vapply(e1[names(e2)], is.null, logical(1))
e1[n] <- e2[n]
# inherit missing from base
e3 <- base_class(e1 = e1)
n <- vapply(e1[names(e3)], is.null, logical(1))
e1[n] <- e3[n]
}

# Calculate relative sizes
if (is.rel(e1$size)) {
if (is.rel(e1$size) && !is.null(e2$size)) {
e1$size <- e2$size * unclass(e1$size)
} else if (is.rel(e1$size) && !is.null(e3$size)) {
e1$size <- e3$size * unclass(e1$size)
}

e1
return(e1)
}

# Fine default properities of element
#
# @param e1 An element object
base_class <- function(e1) {
line = element_line(colour = "black", size = 0.5, linetype = 1,lineend = "butt")
rect = element_rect(fill = "white", colour = "black",size = 0.5, linetype = 1)
text = element_text(family = "", face = "plain",colour = "black", size = 11, lineheight = 0.9, hjust = 0.5, vjust = 0.5, angle = 0, margin = margin(), debug = FALSE)
e3 <- class(e1)[1]
if (e3 == "element_line") {e3 <- line}
else if (e3 == "element_rect") {e3 <- rect}
else if (e3 == "element_text") {e3 <- text}

return(e3)
}