Às vezes, escrevo funções que envolvem renomear/reetiquetar muitas variáveis em lugares diferentes, usando um reetiquetador. O reetiquetador é usado em vários contextos, tanto diretamente no meu código (por exemplo, para títulos) quanto passado para outras funções (por exemplo, facet_wrap). Isso é bom para usos típicos:
library(ggplot2)
library(dplyr)
plotfcn <- function(df, x, y, facet, fancy_labs){
# Strings of x & y (for axis titles)
xStr <- fancy_labs(deparse(substitute(x)))
yStr <- fancy_labs(deparse(substitute(y)))
#base plot
p <- ggplot(df, aes({{x}}, {{y}})) +
geom_point()
#add facets (with labels) and axis labels
p + facet_wrap(vars({{facet}}), labeller=fancy_labs) +
labs(x=xStr, y=yStr)
}
mylabs <- as_labeller(c(
'compact' = 'Small Family Car',
'midsize' = 'Medium Family Car',
'minivan' = 'For the Kids',
'pickup' = 'For the Stuff',
'displ' = 'Engine Displacement (L)',
'hwy' = 'Highway Mileage (mpg)'))
classlist <- c('compact', 'midsize', 'minivan', 'pickup')
mpg_lim <- mpg %>% filter(class %in% classlist)
mpg_lim %>% plotfcn(displ, hwy, class, fancy_labs = mylabs)
Agora eu gostaria de tornar o argumento labeller opcional. Envolver qualquer coisa que envolva rótulos em uma instrução if/else é fácil:
plotfcn <- function(df, x, y, facet, fancy_labs=NULL){
# Strings of x & y (for axis titles)
if(!is.null(fancy_labs)) {
xStr <- fancy_labs(deparse(substitute(x)))
yStr <- fancy_labs(deparse(substitute(y)))
}
#base plot
p <- ggplot(df, aes({{x}}, {{y}})) +
geom_point()
#optional: add labels using labeller
if(!is.null(fancy_labs)) {
p +
facet_wrap(vars({{facet}}), labeller=fancy_labs) +
labs(x=xStr, y=yStr)
} else {
p + facet_wrap(vars({{facet}}))
}
}
mpg_lim %>% plotfcn(displ, hwy, class, fancy_labs = mylabs)
mpg_lim %>% plotfcn(displ, hwy, class)
No entanto, se possível, gostaria de evitar colocar o argumento facet_wrap() na instrução if/else. (No meu código real, ele já está em uma sequência if/else, então adicionar este if/else adicional adicionará muitas ramificações e copiar/colar repetidamente, o que é trabalhoso de trabalhar.) Esta resposta sugere usar uma construção ellipse para passar o argumento labeller para facet_wrap, o que funciona muito bem - exceto que não consigo descobrir como chamar a mesma função labeller para os rótulos do eixo. Eu precisaria passar o mesmo argumento no meu código duas vezes com dois nomes diferentes, como mostrado abaixo, ou há alguma maneira de chamar o argumento labeller por meio da construção ellipses e independentemente no meu código?
plotfcn <- function(df, x, y, facet, fancy_labs=NULL, ...){
# Strings of x & y (for axis titles)
if(!is.null(fancy_labs)) {
xStr <- fancy_labs(deparse(substitute(x)))
yStr <- fancy_labs(deparse(substitute(y)))
}
#base plot - calls labeller using ...
p <- ggplot(df, aes({{x}}, {{y}})) +
geom_point() +
facet_wrap(vars({{facet}}), ...)
#optional: add labels using labeller
if(!is.null(fancy_labs)) {
p + labs(x=xStr, y=yStr)
} else {
p
}
}
#this works, but involves calling the same parameter (mylabs) twice under two different names, which is annoying
mpg_lim %>% plotfcn(displ, hwy, class, fancy_labs = mylabs, labeller=mylabs)
mpg_lim %>% plotfcn(displ, hwy, class)
Se eu configurar a função com um argumento labeller function(df, x, y, facet, labeller = NULL, ...)
, a construção ellipsis não dispara, e minhas facetas não são rotuladas. Mas se eu configurá-la apenas com as ellipses function(df, x, y, facet, ...)
, não posso verificar sua presença usando is.null()
ou missing()
para disparar minhas instruções if . Existe alguma maneira de fazer com que as instruções if reconheçam a presença/ausência do argumento labeller?
Você pode usar
list(...)
para extrair e trabalhar com argumentos específicos passados para...
: