Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

improved print methods for theme and element classes #693

Closed
wants to merge 3 commits into from

2 participants

@jrnold

I added new print methods for theme and element objects which are easier to understand than the existing methods. Additionally, the output of print can be evaluated to recreate the object. This makes it easy to create a new theme by printing an existing theme and making edits to the output.

Example of print output for theme_gray

> print(theme_gray()$rect)
element(fill = "white", colour = "black", size = 0.5, linetype = 1) 
> print(theme_gray())
theme(line = element(colour = "black", size = 0.5, linetype = 1, lineend = "butt"),
rect = element(fill = "white", colour = "black", size = 0.5, linetype = 1),
text = element(family = "", face = "plain", colour = "black", size = 12, hjust = 0.5, vjust = 0.5, angle = 0, lineheight = 0.9),
axis.text = element(colour = "grey50", size = rel(0.8)),
strip.text = element(size = rel(0.8)),
axis.line = element(),
axis.text.x = element(vjust = 1),
axis.text.y = element(hjust = 1),
axis.ticks = element(colour = "grey50"),
axis.title.x = element(),
axis.title.y = element(angle = 90),
axis.ticks.length = unit(0.15, "cm"),
axis.ticks.margin = unit(0.1, "cm"),
legend.background = element(colour = NA),
legend.margin = unit(0.2, "cm"),
legend.key = element(fill = "grey95", colour = "white"),
legend.key.size = unit(1.2, "lines"),
legend.key.height = NULL,
legend.key.width = NULL,
legend.text = element(size = rel(0.8)),
legend.text.align = NULL,
legend.title = element(face = "bold", size = rel(0.8), hjust = 0),
legend.title.align = NULL,
legend.position = "right",
legend.direction = NULL,
legend.justification = "center",
legend.box = NULL,
panel.background = element(fill = "grey90", colour = NA),
panel.border = element(),
panel.grid.major = element(colour = "white"),
panel.grid.minor = element(colour = "grey95", size = 0.25),
panel.margin = unit(0.25, "lines"),
strip.background = element(fill = "grey80", colour = NA),
strip.text.x = element(),
strip.text.y = element(angle = -90),
plot.background = element(colour = "white"),
plot.title = element(size = rel(1.2)),
plot.margin = unit(c(1, 1, 0.5, 0.5), "lines"),
complete = TRUE) 

The print output evaluates to the original object.

> identical(eval(parse(text=as.character(theme_gray()))), theme_gray())
TRUE
R/theme-elements.r
@@ -87,6 +83,10 @@ rel <- function(x) {
structure(x, class = "rel")
}
+as.character.rel <- function(x) {
@hadley Owner
hadley added a note

I think this would be better as a format method. Also you need to export all S3 methods with a roxygen directive like @S3method format rel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
R/theme-elements.r
@@ -353,3 +353,25 @@ validate_element <- function(el, elname) {
}
invisible()
}
+
+as.character.element <- function(x) {
+ .f <- function(x) {
+ if (class(x) %in% c("rel", "unit")) {
+ as.character(x)
+ } else {
+ deparse(x)
+ }
+ }
+ element_type <- class(x)[2]
+ x <- lapply(Filter(notnull, x), .f)
@hadley Owner
hadley added a note

I prefer defining compact <- function(x) Filter(Negate(is.null), x)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
R/theme-elements.r
@@ -353,3 +353,25 @@ validate_element <- function(el, elname) {
}
invisible()
}
+
+as.character.element <- function(x) {
+ .f <- function(x) {
+ if (class(x) %in% c("rel", "unit")) {
@hadley Owner
hadley added a note

class(x) can be a vector so you need any here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@hadley
Owner

I made a few smaller comments, but I'm not entirely sure that printing the object should produce something you can easily copy and pasted.

@jrnold

This and #692 are really two solutions to the same problem. My workflow when extend a theme has generally gone as follows. I'd start with theme_gray, and make a few additions. Wonder why the axis ticks were still gray. Repeat those two steps a couple of times. Then give up and just copy the source code of theme_gray() and manually edit it. The later step arose because of the nature of the basic themes (as in #692), but also because the print output of themes makes it hard to get a quick global understanding of what is going on. I found that the source code used to create the theme was more understandable than the theme itself. #692 mitigates some of the need for this. However, this did come out of a real need in my workflow.

I'd generally agree with you on the dangers of copy and pasting. However, in this case, I tend to think of the themes more like data than code. Inheriting from other themes is a quick way to fill in the entries of the data. But once I have the set of elements in a theme, I don't mind if its entries are no longer tied to the themes that it was created from, and in many cases I may not want it to change if the definition of the other theme changes.

I myself do not put p=1 that this is the best way to do it, but I thought that I'd throw the idea out there and see whether it was useful.

jrnold added some commits
@jrnold jrnold incorporated suggestions from hadley
- register all S3 methods
- use format instead of as.character
- use Negate instead of adding a notnull function
- fix bug in checking classes
3c5f2de
@jrnold jrnold fix typos in previous commit
- whitespace line in utilities.r
- as.format.rel -> format.rel
a67689e
@hadley
Owner

Could you please rebase/merge against master, re-document with the development version of roxygen2 (install_github("klutometis/roxygen) and resubmit?

@hadley hadley closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 14, 2012
  1. @jrnold
Commits on Oct 15, 2012
  1. @jrnold

    incorporated suggestions from hadley

    jrnold authored
    - register all S3 methods
    - use format instead of as.character
    - use Negate instead of adding a notnull function
    - fix bug in checking classes
  2. @jrnold

    fix typos in previous commit

    jrnold authored
    - whitespace line in utilities.r
    - as.format.rel -> format.rel
This page is out of date. Refresh to see the latest.
Showing with 49 additions and 7 deletions.
  1. +28 −4 R/theme-elements.r
  2. +21 −3 R/theme.r
View
32 R/theme-elements.r
@@ -73,10 +73,6 @@ element_text <- function(family = NULL, face = NULL, colour = NULL,
}
-#' @S3method print element
-print.element <- function(x, ...) str(x)
-
-
#' Relative sizing for theme elements
#'
#' @param x A number representing the relative size
@@ -87,6 +83,11 @@ rel <- function(x) {
structure(x, class = "rel")
}
+#' @S3method format rel
+format.rel <- function(x) {
+ sprintf("rel(%s)", as.numeric(x))
+}
+
#' @S3method print rel
print.rel <- function(x, ...) print(noquote(paste(x, " *", sep = "")))
@@ -353,3 +354,26 @@ validate_element <- function(el, elname) {
}
invisible()
}
+
+#' @S3method format element
+format.element <- function(x) {
+ .f <- function(x) {
+ if (any(sapply(c("rel", "unit"), inherits, x=x))) {
+ format(x)
+ } else {
+ deparse(x)
+ }
+ }
+ element_type <- class(x)[1]
+ x <- lapply(Filter(Negate(is.null), x), .f)
+ sprintf("%s(%s)", element_type,
+ paste(names(x), x, sep=" = ", collapse=", "))
+}
+
+#' @S3method format unit
+format.unit <- function(x) {
+ sprintf("unit(%s, \"%s\")", deparse(as.numeric(x)), attr(x, "unit"))
+}
+
+#' @S3method print element
+print.element <- function(x, ...) cat(format(x), "\n")
View
24 R/theme.r
@@ -32,9 +32,6 @@ theme_update <- function(...) {
#' @export
is.theme <- function(x) inherits(x, "theme")
-#' @S3method print theme
-print.theme <- function(x, ...) str(x)
-
#' Set theme elements
#'
#'
@@ -611,3 +608,24 @@ combine_elements <- function(e1, e2) {
e1
}
+
+#' @S3method format theme
+format.theme <- function(x) {
+ .f <- function(x) {
+ if (is.character(x)) {
+ sprintf("\"%s\"", x)
+ } else if (is.null(x)) {
+ "NULL"
+ } else {
+ format(x)
+ }
+ }
+ complete <- attr(x, "complete")
+ newx <- c(lapply(x, .f), complete = complete)
+ sprintf("theme(%s)",
+ paste(names(newx), newx, sep=" = ", collapse=",\n"))
+}
+
+#' @S3method print theme
+print.theme <- function(x, ...) cat(format(x), "\n")
+
Something went wrong with that request. Please try again.