Como alterar os rótulos das facetas?

231

Eu usei o seguinte ggplotcomando:

ggplot(survey, aes(x = age)) + stat_bin(aes(n = nrow(h3), y = ..count.. / n), binwidth = 10)
  + scale_y_continuous(formatter = "percent", breaks = c(0, 0.1, 0.2))
  + facet_grid(hospital ~ .)
  + theme(panel.background = theme_blank())

para produzir

texto alternativo

Eu gostaria de alterar as facetas rótulos, no entanto, para algo mais curto (como Hosp 1, Hosp 2...), porque eles são muito longos agora e olhar apertado (aumentando a altura do gráfico não é uma opção, que seria necessário muito espaço em o documento). Eu olhei para a página de ajuda facet_grid , mas não consigo descobrir como.

wishihadabettername
fonte

Respostas:

124

Altere os nomes dos níveis de fatores subjacentes com algo como:

# Using the Iris data
> i <- iris
> levels(i$Species)
[1] "setosa"     "versicolor" "virginica" 
> levels(i$Species) <- c("S", "Ve", "Vi")
> ggplot(i, aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)
Vince
fonte
12
@wishihadabettername: Para evitar a alteração de dados subjacentes, você pode usar: ggplot(transform(iris, Species = c("S", "Ve", "Vi")[as.numeric(Species)]), aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)
Arnaud A
1
relacionado ... se você deseja que o rótulo do painel seja uma expressão entre aspas () (por exemplo, levels(x$measurements) <- c(bquote(Area ~~ (cm^2)), bquote(Length ~~ (cm)))) , ele não aparecerá na expressão matemática. Como mostrar expressões como rótulos de faceta?
Brian D
relacionado à inclusão de expressões no rótulo da faceta, use a labelleropção para facet_grid: stackoverflow.com/questions/37089052/…
Brian D
285

Aqui está uma solução que evita editar seus dados:

Digamos que seu plot seja facetado pela groupparte do quadro de dados, que possui níveis control, test1, test2, e crie uma lista nomeada por esses valores:

hospital_names <- list(
  'Hospital#1'="Some Hospital",
  'Hospital#2'="Another Hospital",
  'Hospital#3'="Hospital Number 3",
  'Hospital#4'="The Other Hospital"
)

Em seguida, crie uma função 'rotuladora' e envie-a para sua chamada facet_grid:

hospital_labeller <- function(variable,value){
  return(hospital_names[value])
}

ggplot(survey,aes(x=age)) + stat_bin(aes(n=nrow(h3),y=..count../n), binwidth=10)
 + facet_grid(hospital ~ ., labeller=hospital_labeller)
 ...

Isso usa os níveis do quadro de dados para indexar a lista hospital_names, retornando os valores da lista (os nomes corretos).


Observe que isso só funciona se você tiver apenas uma variável de faceta. Se você tiver duas facetas, sua função de rotuladora precisará retornar um vetor de nome diferente para cada faceta. Você pode fazer isso com algo como:

plot_labeller <- function(variable,value){
  if (variable=='facet1') {
    return(facet1_names[value])
  } else {
    return(facet2_names[value])
  }
}

Onde facet1_namese facet2_namessão listas predefinidas de nomes indexados pelos nomes de índice de faceta ('Hostpital # 1' etc.).


Edit: O método acima falhará se você passar uma combinação de variável / valor que a etiquetadora não conhece. Você pode adicionar um fail-safe para variáveis ​​desconhecidas como esta:

plot_labeller <- function(variable,value){
  if (variable=='facet1') {
    return(facet1_names[value])
  } else if (variable=='facet2') {
    return(facet2_names[value])
  } else {
    return(as.character(value))
  }
}

Resposta adaptada de como alterar as etiquetas strip.text no ggplot com faceta e margem = TRUE


edit: AVISO : se você estiver usando esse método para facetar uma coluna de caracteres , poderá estar recebendo rótulos incorretos. Veja este relatório de bug . corrigido nas versões recentes do ggplot2.

naught101
fonte
9
Bom, mas não funcionará com facet_wrap, enquanto a solução @Vince também funcionará com facet_wrap.
Arnaud A
@ArnaudAmzallag: Correto, mas se alguém quiser doar algum tempo, poderá fazê-lo no futuro .
naught101
Adicionado um fail-safe para variáveis ​​de faceta desconhecidas.
naught101
16
Aviso: Isso não funciona no ggplot2 v.2 - a função rotuladora mudou. @brirons answer works stackoverflow.com/a/34811062/162832
Andreas
Interessante, mas isso nem sempre funciona, enquanto a edição dos fatores sempre funciona.
PatrickT
214

Aqui está outra solução que está no espírito da dada por @ naught101, mas mais simples e também não lança um aviso sobre a versão mais recente do ggplot2.

Basicamente, você primeiro cria um vetor de caractere nomeado

hospital_names <- c(
                    `Hospital#1` = "Some Hospital",
                    `Hospital#2` = "Another Hospital",
                    `Hospital#3` = "Hospital Number 3",
                    `Hospital#4` = "The Other Hospital"
                    )

E então você o usa como rotulador, apenas modificando a última linha do código fornecido por @ naught101 para

... + facet_grid(hospital ~ ., labeller = as_labeller(hospital_names))

Espero que isto ajude.

mbiron
fonte
Qual versão do ggplot2 está as_labeller? Encontrei algum código-fonte no repositório CRAN GitHub , mas após a atualização para a versão mais recente (no CRAN!), Parece que não tenho a função.
N1k31t4
Isso é estranho. Também atualizei através do CRAN. Aqui está a documentação docs.ggplot2.org/dev/as_labeller.html
mbiron
4
Isso é legal. O que acontece quando você tem duas variáveis ​​em sua grade de facetas? Gosta hospital ~ genderou algo assim? Existe uma maneira de usar rotuladoras nos dois eixos? Não vejo nada óbvio nos documentos.
precisa saber é o seguinte
3
Observe que se você começou com a resposta de nada, esta funciona apenas com c () e não com uma lista () .
precisa saber é o seguinte
1
Uma grande parte disso é que isso funciona com os dois eixos da grade de facetas!
Calum You
30

Aqui está como eu fiz isso facet_grid(yfacet~xfacet)usando o ggplot2, versão 2.2.1:

facet_grid(
    yfacet~xfacet,
    labeller = labeller(
        yfacet = c(`0` = "an y label", `1` = "another y label"),
        xfacet = c(`10` = "an x label", `20` = "another x label")
    )
)

Observe que isso não contém uma chamada para as_labeller()- algo com o qual lutei por um tempo.

Essa abordagem é inspirada no último exemplo da página de ajuda Coerce to labeller function .

bovender
fonte
isso funciona!!! Não pude aplicar as outras soluções porque algumas das soluções sugeridas foram preteridas nas versões atuais do ggplot2.
yanes
Você pode construir esses vetores nomeados com setNames() stackoverflow.com/a/22428439/3362993
jsta
23

Se você tem duas facetas hospitale roomdeseja renomear apenas uma, pode usar:

facet_grid( hospital ~ room, labeller = labeller(hospital = as_labeller(hospital_names)))

Para renomear duas facetas usando a abordagem baseada em vetores (como na resposta de naught101), você pode:

facet_grid( hospital ~ room, labeller = labeller(hospital = as_labeller(hospital_names),
                                                 room = as_labeller(room_names)))
domi
fonte
16

A maneira MAIS FÁCIL de alterar SEM modificar os dados subjacentes é:

1) Crie um objeto usando a as_labellerfunção adicionando a marca de retorno para cada um dos valores padrão :

hum.names <- as_labeller(c(`50` = "RH% 50", `60` = "RH% 60",`70` = "RH% 70", `80` = "RH% 80",`90` = "RH% 90", `100` = "RH% 100")) #Necesarry to put RH% into the facet labels

2) Adicionamos ao GGplot:

ggplot(dataframe, aes(x=Temperature.C,y=fit))+geom_line()+ facet_wrap(~Humidity.RH., nrow=2,labeller=hum.names)
Leinfloyd
fonte
1
Isso eu acho que é o método mais elegante - é eficaz e funciona com ggplot2 versão 3.0.0.9000
Landak
9

Observe que esta solução não funcionará bem, caso o ggplot mostre menos fatores do que a sua variável realmente contém (o que poderia acontecer se você estivesse, por exemplo, com um subconjunto):

 library(ggplot2)
 labeli <- function(variable, value){
  names_li <- list("versicolor"="versi", "virginica"="virg")
  return(names_li[value])
 }

 dat <- subset(iris,Species!="setosa")
 ggplot(dat, aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ ., labeller=labeli)

Uma solução simples (além de adicionar todos os fatores não utilizados em names_li, o que pode ser entediante) é eliminar os fatores não utilizados com droplevels (), no conjunto de dados original ou na função labbeler, consulte:

labeli2 <- function(variable, value){
  value <- droplevels(value)
  names_li <- list("versicolor"="versi", "virginica"="virg")
  return(names_li[value])
}

dat <- subset(iris,Species!="setosa")
ggplot(dat, aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ ., labeller=labeli2)
Matifou
fonte
9

Essa solução está muito próxima do que o @domi possui, mas foi projetada para encurtar o nome, buscando as primeiras 4 letras e o último número.

library(ggplot2)

# simulate some data
xy <- data.frame(hospital = rep(paste("Hospital #", 1:3, sep = ""), each = 30),
                 value = rnorm(90))

shortener <- function(string) {
  abb <- substr(string, start = 1, stop = 4) # fetch only first 4 strings
  num <- gsub("^.*(\\d{1})$", "\\1", string) # using regular expression, fetch last number
  out <- paste(abb, num) # put everything together
  out
}

ggplot(xy, aes(x = value)) +
  theme_bw() +
  geom_histogram() +
  facet_grid(hospital ~ ., labeller = labeller(hospital = shortener))

insira a descrição da imagem aqui

Roman Luštrik
fonte
6

Ambos facet_wrape facet_gridtambém aceitam entrada de ifelsecomo argumento. Portanto, se a variável usada para lapidação for lógica, a solução será muito simples:

facet_wrap(~ifelse(variable, "Label if true", "Label if false"))

Se a variável tiver mais categorias, a ifelseinstrução precisará ser aninhada .

Como efeito colateral, isso também permite que a criação dos grupos seja facetada na ggplotchamada.

lillemets
fonte
5

Adicionando outra solução semelhante à @ domi's com a análise de símbolos matemáticos, sobrescrito, subscrito, parênteses / colchete, .etc.

library(tidyverse)
theme_set(theme_bw(base_size = 18))

### create separate name vectors
# run `demo(plotmath)` for more examples of mathematical annotation in R
am_names <- c(
  `0` = "delta^{15}*N-NO[3]^-{}",
  `1` = "sqrt(x,y)"
)

# use `scriptstyle` to reduce the size of the parentheses &
# `bgroup` to make adding `)` possible 
cyl_names <- c(
  `4` = 'scriptstyle(bgroup("", a, ")"))~T~-~5*"%"',
  `6` = 'scriptstyle(bgroup("", b, ")"))~T~+~10~degree*C',
  `8` = 'scriptstyle(bgroup("", c, ")"))~T~+~30*"%"'
)

ggplot(mtcars, aes(wt, mpg)) + 
  geom_jitter() +
  facet_grid(am ~ cyl,
             labeller = labeller(am  = as_labeller(am_names,  label_parsed),
                                 cyl = as_labeller(cyl_names, label_parsed))
             ) +
  geom_text(x = 4, y = 25, size = 4, nudge_y = 1,
            parse = TRUE, check_overlap = TRUE,
            label = as.character(expression(paste("Log"["10"], bgroup("(", frac("x", "y"), ")")))))

### OR create new variables then assign labels directly
# reverse facet orders just for fun
mtcars <- mtcars %>% 
  mutate(am2  = factor(am,  labels = am_names),
         cyl2 = factor(cyl, labels = rev(cyl_names), levels = rev(attr(cyl_names, "names")))
  )

ggplot(mtcars, aes(wt, mpg)) + 
  geom_jitter() +
  facet_grid(am2 ~ cyl2,
             labeller = label_parsed) +
  annotate("text", x = 4, y = 30, size = 5,
           parse = TRUE, 
           label = as.character(expression(paste("speed [", m * s^{-1}, "]"))))

Criado em 30/03/2019 pelo pacote reprex (v0.2.1.9000)

Tung
fonte
3

Eu acho que todas as outras soluções são realmente úteis para fazer isso, mas há outra maneira.

Eu assumo:

  • você instalou o dplyrpacote, que possui o mutatecomando conveniente , e
  • seu conjunto de dados é nomeado survey.

    %>% de pesquisa mutada (Hosp1 = Hospital1, Hosp2 = Hospital2, ........)

Este comando ajuda a renomear colunas, mas todas as outras colunas são mantidas.

Então faça o mesmo facet_wrap, você está bem agora.

son520804
fonte
Desculpe, isso não funciona, uma vez que também altera o conteúdo da coluna
Jens
3

A definição da função rotuladora com os variable, valueargumentos não funcionaria para mim. Além disso, se você quiser usar a expressão, precisará usar lapply e não pode simplesmente usar arr[val], pois o argumento para a função é um data.frame.

Este código funcionou:

libary(latex2exp)
library(ggplot2)
arr <- list('virginica'=TeX("x_1"), "versicolor"=TeX("x_2"), "setosa"=TeX("x_3"))
mylabel <- function(val) { return(lapply(val, function(x) arr[x])) }
ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width)) + geom_line() + facet_wrap(~Species, labeller=mylabel)
reox
fonte
3

Desde que eu ainda não estou autorizado a comentar sobre as mensagens, eu estou postando isso separadamente como uma adenda à resposta de Vince e resposta de son520804 . Crédito vai para eles.

Son520804:

usando dados Iris:

Presumo:
Você instalou o pacote dplyr, que possui o conveniente comando mutate, e seu conjunto de dados é chamado de survey. survey %>% mutate(Hosp1 = Hospital1, Hosp2 = Hospital2,........) Este comando ajuda você a renomear colunas, mas todas as outras colunas são mantidas. Então faça o mesmo facet_wrap, você está bem agora.

Usando o exemplo de íris de Vince e o código parcial de son520804, fiz isso com a função mutate e consegui uma solução fácil sem tocar no conjunto de dados original. O truque é criar um vetor de nome substituto e usar mutate () dentro do canal para corrigir temporariamente os nomes das facetas:

i <- iris

levels(i$Species)
[1] "setosa"     "versicolor" "virginica"

new_names <- c(
  rep("Bristle-pointed iris", 50), 
  rep("Poison flag iris",50), 
  rep("Virginia iris", 50))

i %>% mutate(Species=new_names) %>% 
ggplot(aes(Petal.Length))+
    stat_bin()+
    facet_grid(Species ~ .)

Neste exemplo, você pode ver que os níveis de i $ Species são temporariamente alterados para nomes comuns correspondentes contidos no vetor new_names. A linha que contém

mutate(Species=new_names) %>%

pode ser facilmente removido para revelar a nomeação original.

Palavra de cautela: Isso pode facilmente introduzir erros nos nomes se o vetor new_name não estiver configurado corretamente. Provavelmente seria muito mais limpo usar uma função separada para substituir as seqüências de caracteres variáveis. Lembre-se de que o vetor new_name pode precisar ser repetido de diferentes maneiras para corresponder à ordem do seu conjunto de dados original. Por favor, verifique duas vezes e triplamente se isso foi alcançado corretamente.

Alexander Kielland
fonte
Pode ser um pouco mais agradável de usar: new_names <- c('setosa' = 'Bristle-pointed iris', 'versicolor' = 'Poison flag iris', 'virginica' = 'Virginia iris')e, em seguida, na mutação você pode criar uma nova coluna assim:mutate(Spec = new_names[Species])
filups21
3

Isso está funcionando para mim.

Defina um fator:

hospitals.factor<- factor( c("H0","H1","H2") )

e use, em ggplot():

facet_grid( hospitals.factor[hospital] ~ . )
Hernán Castelo
fonte
2

Apenas estendendo a resposta de naught101 - o crédito vai para ele

plot_labeller <- function(variable,value, facetVar1='<name-of-1st-facetting-var>', var1NamesMapping=<pass-list-of-name-mappings-here>, facetVar2='', var2NamesMapping=list() )
{
  #print (variable)
  #print (value)
  if (variable==facetVar1) 
    {
      value <- as.character(value)
      return(var1NamesMapping[value])
    } 
  else if (variable==facetVar2) 
    {
      value <- as.character(value)
      return(var2NamesMapping[value])
    } 
  else 
    {
      return(as.character(value))
    }
}

O que você precisa fazer é criar uma lista com mapeamento de nome para nome

clusteringDistance_names <- list(
  '100'="100",
  '200'="200",
  '300'="300",
  '400'="400",
  '600'="500"
)

e redefina plot_labeller()com novos argumentos padrão:

plot_labeller <- function(variable,value, facetVar1='clusteringDistance', var1NamesMapping=clusteringDistance_names, facetVar2='', var1NamesMapping=list() )

E depois:

ggplot() + 
  facet_grid(clusteringDistance ~ . , labeller=plot_labeller) 

Como alternativa, você pode criar uma função dedicada para cada uma das alterações de etiqueta que deseja ter.

user4786271
fonte
2

Eu tenho outra maneira de alcançar o mesmo objetivo sem alterar os dados subjacentes:

ggplot(transform(survey, survey = factor(survey,
        labels = c("Hosp 1", "Hosp 2", "Hosp 3", "Hosp 4"))), aes(x = age)) +
  stat_bin(aes(n = nrow(h3),y=..count../n), binwidth = 10) +
  scale_y_continuous(formatter = "percent", breaks = c(0, 0.1, 0.2)) +
  facet_grid(hospital ~ .) +
  opts(panel.background = theme_blank())

O que fiz acima foi alterar os rótulos do fator no quadro de dados original, e essa é a única diferença em comparação com o código original.

e você
fonte
1

Você já tentou alterar os níveis específicos do seu Hospitalvetor?

levels(survey$hospital)[levels(survey$hospital) == "Hospital #1"] <- "Hosp 1"
levels(survey$hospital)[levels(survey$hospital) == "Hospital #2"] <- "Hosp 2"
levels(survey$hospital)[levels(survey$hospital) == "Hospital #3"] <- "Hosp 3"
philiporlando
fonte
1

Sinto que devo adicionar minha resposta a isso, porque demorei bastante para fazer isso funcionar:

Esta resposta é para você se:

  • você não deseja editar seus dados originais
  • se você precisar de expressões ( bquote) nos seus marcadores e
  • se você quiser a flexibilidade de um nome-vetor de rotulagem separado

Basicamente, coloquei os rótulos em um vetor nomeado para que os rótulos não ficassem confusos ou alternados. A labellerexpressão provavelmente poderia ser mais simples, mas isso pelo menos funciona (as melhorias são muito bem-vindas). Observe o `(aspas) para proteger o fator de faceta.

n <- 10
x <- seq(0, 300, length.out = n)

# I have my data in a "long" format
my_data <- data.frame(
  Type = as.factor(c(rep('dl/l', n), rep('alpha', n))),
  T = c(x, x),
  Value = c(x*0.1, sqrt(x))
)

# the label names as a named vector
type_names <- c(
  `nonsense` = "this is just here because it looks good",
  `dl/l` = Linear~Expansion~~Delta*L/L[Ref]~"="~"[%]", # bquote expression
  `alpha` = Linear~Expansion~Coefficient~~alpha~"="~"[1/K]"
  )


ggplot() + 
  geom_point(data = my_data, mapping = aes(T, Value)) + 
  facet_wrap(. ~ Type, scales="free_y", 
             labeller = label_bquote(.(as.expression(
               eval(parse(text = paste0('type_names', '$`', Type, '`')))
               )))) +
  labs(x="Temperature [K]", y="", colour = "") +
  theme(legend.position = 'none')

insira a descrição da imagem aqui

dani
fonte
1

Solução simples ( daqui ):

p <- ggplot(mtcars, aes(disp, drat)) + geom_point()
# Example (old labels)
p + facet_wrap(~am)


to_string <- as_labeller(c(`0` = "Zero", `1` = "One"))
# Example (New labels)
p + facet_wrap(~am, labeller = to_string)
usuario
fonte
0

Depois de lutar por um tempo, o que eu encontrei é que podemos usar fct_relevel()e fct_recode()de forcatsem conjunto para alterar a ordem das facetas assim corrigir os rótulos faceta. Não tenho certeza se é suportado pelo design, mas funciona! Confira os gráficos abaixo:

library(tidyverse)

before <- mpg %>%
  ggplot(aes(displ, hwy)) + 
  geom_point() +
  facet_wrap(~class)
before

after <- mpg %>%
  ggplot(aes(displ, hwy)) + 
  geom_point() + 
  facet_wrap(
    vars(
      # Change factor level name
      fct_recode(class, "motorbike" = "2seater") %>% 
        # Change factor level order
        fct_relevel("compact")
    )
  )
after

Criado em 2020-02-16 pelo pacote reprex (v0.3.0)

Ashirwad
fonte