Jak zmienić etykiety aspektów?

230

Użyłem następującego ggplotpolecenia:

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())

produkować

alternatywny tekst

Chciałbym zmienić fazowane etykiet jednak coś krótszego (jak Hosp 1, Hosp 2...), ponieważ są one zbyt długo i teraz wygląd ciasno (zwiększając wysokość wykresu nie jest opcją, zajęłoby zbyt dużo miejsca w dokument). Spojrzałem na stronę pomocy facet_grid, ale nie wiem, jak to zrobić.

wishihadabettername
źródło

Odpowiedzi:

123

Zmień nazwy podstawowych poziomów czynników za pomocą czegoś takiego:

# 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
źródło
12
@wishihadabettername: Aby uniknąć zmiany podstawowych danych, możesz użyć: ggplot(transform(iris, Species = c("S", "Ve", "Vi")[as.numeric(Species)]), aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)
Arnaud A
1
powiązane ... jeśli chcesz, aby etykieta panelu była wyrażeniem bquote () (np. levels(x$measurements) <- c(bquote(Area ~~ (cm^2)), bquote(Length ~~ (cm)))), nie pojawi się w wyrażeniu matematycznym. Jak pokazywać wyrażenia jako etykiety aspektów?
Brian D
powiązane z włączaniem wyrażeń w etykiecie aspektu, użyj labelleropcji facet_grid: stackoverflow.com/questions/37089052/...
Brian D
285

Oto rozwiązanie, które pozwala uniknąć edycji danych:

Załóżmy, że twoja fabuła jest oparta na groupczęści ramki danych, która ma poziomy control, test1, test2, a następnie utwórz listę nazwaną według tych wartości:

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

Następnie utwórz funkcję „labeller” i wepchnij ją do wywołania 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)
 ...

Wykorzystuje poziomy ramek danych do indeksowania listy nazw szpitali, zwracając wartości listy (poprawne nazwy).


Pamiętaj, że działa to tylko wtedy, gdy masz tylko jedną zmienną aspektową. Jeśli masz dwa aspekty, funkcja etykietująca musi zwrócić inny wektor nazwy dla każdego aspektu. Możesz to zrobić za pomocą:

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

Gdzie facet1_namesi facet2_namessą wstępnie zdefiniowanymi listami nazw indeksowanych według nazw indeksów aspektów („Hostpital # 1” itp.).


Edycja: Powyższa metoda kończy się niepowodzeniem, jeśli przekażesz kombinację zmiennych / wartości, której etykietujący nie zna. Możesz dodać bezpieczny dla nieznanych zmiennych, takich jak to:

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))
  }
}

Odpowiedź zaadaptowana ze sposobu zmiany etykiet strip.text w ggplot z facet i margin = TRUE


edycja: OSTRZEŻENIE : jeśli używasz tej metody do fasetowania według kolumny znaków , być może otrzymujesz nieprawidłowe etykiety. Zobacz ten raport o błędach . naprawione w ostatnich wersjach ggplot2.

naught101
źródło
9
Fajnie, ale nie będzie działać z facet_wrap, podczas gdy rozwiązanie @Vince będzie również działać z facet_wrap.
Arnaud A
@ArnaudAmzallag: Prawidłowo, choć jeśli ktoś ma ochotę poświęcić trochę czasu, może to w przyszłości .
naught101
Dodano bezpieczny dla nieznanych zmiennych fasetowania.
naught101
16
Uwaga: Nie działa to w ggplot2 v.2 - zmieniła się funkcja labeller. @mbirons odpowiedź działa stackoverflow.com/a/34811062/162832
Andreas
Ciekawe, ale to nie zawsze działa, podczas gdy edycja czynników zawsze działa.
PatrickT
214

Oto inne rozwiązanie zgodne z duchem @ naught101, ale prostsze i nie rzucające ostrzeżenia na najnowszą wersję ggplot2.

Zasadniczo najpierw tworzysz nazwany wektor znaków

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

A potem używasz go jako etykietującego, po prostu modyfikując ostatni wiersz kodu podanego przez @ naught101 na

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

Mam nadzieję że to pomoże.

Mbiron
źródło
W której wersji jest ggplot2 as_labeller? Znalazłem trochę kodu źródłowego w repozytorium CRAN GitHub , ale po aktualizacji do najnowszej wersji (w CRAN!) Nie mam tej funkcji.
n1k31t4
To jest dziwne. Zaktualizowałem również przez CRAN. Oto dokumentacja docs.ggplot2.org/dev/as_labeller.html
mbiron
4
To jest fajne. Co się dzieje, gdy masz dwie zmienne w siatce aspektów? Lubisz hospital ~ genderczy coś? Czy istnieje sposób na użycie znaczników na obu osiach? Nie widzę nic oczywistego w dokumentacji.
naught101
3
Zauważ, że jeśli zacząłeś od odpowiedzi na nic, ta działa tylko z c (), a nie z listą () .
thomas88wp
1
Jedną wielką częścią tego jest to, że działa to z obiema osiami siatki ścianek!
Calum You
30

Oto jak to zrobiłem za facet_grid(yfacet~xfacet)pomocą ggplot2, wersja 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")
    )
)

Zauważ, że to nie zawiera wezwania do as_labeller()- czegoś, z czym zmagałem się przez chwilę.

Podejście to zostało zainspirowane ostatnim przykładem na stronie pomocy Coerce to labeller function .

Bovender
źródło
to działa!!! Nie mogłem zastosować innych rozwiązań, ponieważ niektóre z sugerowanych rozwiązań były przestarzałe w bieżących wersjach ggplot2.
yanes
Nazwane wektory można konstruować za pomocą setNames() stackoverflow.com/a/22428439/3362993
jsta
23

Jeśli masz dwa aspekty hospitali roomchcesz zmienić nazwę tylko jednego, możesz użyć:

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

Aby zmienić nazwę dwóch aspektów przy użyciu podejścia wektorowego (jak w odpowiedzi naught101), możesz:

facet_grid( hospital ~ room, labeller = labeller(hospital = as_labeller(hospital_names),
                                                 room = as_labeller(room_names)))
domi
źródło
16

Najłatwiejszym sposobem zmiany BEZ modyfikowania podstawowych danych jest:

1) Utwórz obiekt za pomocą as_labellerfunkcji, dodając znak zaznaczenia wstecz dla każdej wartości domyślnej :

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) Dodajemy do GGplot:

ggplot(dataframe, aes(x=Temperature.C,y=fit))+geom_line()+ facet_wrap(~Humidity.RH., nrow=2,labeller=hum.names)
Leinfloyd
źródło
1
Myślę, że to najbardziej elegancka metoda - jest skuteczna i działa z wersją ggplot2 3.0.0.9000
Landak
9

Zauważ, że to rozwiązanie nie będzie działało dobrze, jeśli ggplot pokaże mniej czynników niż faktycznie zawiera twoja zmienna (co mogłoby się zdarzyć, gdybyś miał na przykład podzbiór):

 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)

Prostym rozwiązaniem (oprócz dodania wszystkich nieużywanych czynników w names_li, co może być żmudne) jest upuszczenie nieużywanych czynników za pomocą droplevels (), w oryginalnym zbiorze danych lub w funkcji labbeler, patrz:

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
źródło
9

To rozwiązanie jest bardzo zbliżone do tego, co ma @domi, ale ma na celu skrócenie nazwy poprzez pobranie pierwszych 4 liter i ostatniej cyfry.

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))

wprowadź opis zdjęcia tutaj

Roman Luštrik
źródło
6

Zarówno facet_wrapa facet_gridtakże zaakceptować wejście od ifelsejako argument. Jeśli więc zmienna zastosowana do facetingu jest logiczna, rozwiązanie jest bardzo proste:

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

Jeśli zmienna ma więcej kategorii, ifelseinstrukcja musi być zagnieżdżona .

Jako efekt uboczny pozwala to również na tworzenie grup, które będą fasetowane w ramach ggplotpołączenia.

lillemets
źródło
5

Dodanie innego rozwiązania podobnego do @ domi z parsowaniem symboli matematycznych, indeksu górnego, indeksu dolnego, nawiasu / nawiasu, .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}, "]"))))

Utworzono 30.03.2019 przez pakiet reprezentx (v0.2.1.9000)

Tung
źródło
3

Myślę, że wszystkie inne rozwiązania są naprawdę pomocne, ale istnieje jeszcze inny sposób.

Zakładam:

  • zainstalowałeś dplyrpakiet, który ma wygodne mutatepolecenie, oraz
  • Twój zestaw danych ma nazwę survey.

    ankieta%>% mutate (Hosp1 = Szpital1, Hosp2 = Szpital2, ........)

To polecenie pomaga zmienić nazwę kolumn, ale wszystkie inne kolumny są zachowane.

Więc zrób to samo facet_wrap, wszystko w porządku.

son520804
źródło
przepraszam, to nie działa, ponieważ zmienia również zawartość kolumny
Jens
3

Definicja funkcji przyrządu variable, valuejako argumenty nie działałaby dla mnie. Również jeśli chcesz użyć wyrażenia, musisz użyć laply i nie możesz po prostu użyć arr[val], ponieważ argumentem funkcji jest data.frame.

Ten kod działał:

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
źródło
3

Ponieważ nie mam jeszcze prawo do komentowania postów, jestem delegowania to oddzielnie jako dodatek do odpowiedzi Vince'a i odpowiedzi son520804 użytkownika . Kredyt trafia do nich.

Son520804:

przy użyciu danych Iris:

Zakładam:
Zainstalowałeś pakiet dplyr, który ma wygodne polecenie mutate, a Twój zestaw danych nosi nazwę ankieta. survey %>% mutate(Hosp1 = Hospital1, Hosp2 = Hospital2,........) To polecenie pomaga zmienić nazwę kolumn, ale wszystkie inne kolumny są zachowane. Następnie zrób to samo facet_wrap, wszystko w porządku.

Korzystając z przykładu tęczówki Vince'a i częściowego kodu son520804, zrobiłem to z funkcją mutacji i uzyskałem łatwe rozwiązanie bez dotykania oryginalnego zestawu danych. Sztuką jest utworzenie stojącego wektora nazw i użycie mutate () wewnątrz potoku, aby tymczasowo poprawić nazwy aspektów:

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 ~ .)

W tym przykładzie widać, że poziomy gatunku i $ zostały tymczasowo zmienione na odpowiadające im nazwy pospolite zawarte w wektorze nowe_nazwy. Linia zawierająca

mutate(Species=new_names) %>%

można łatwo usunąć, aby odsłonić oryginalne nazewnictwo.

Uwaga: może łatwo wprowadzić błędy w nazwach, jeśli wektor nowa_nazwa nie jest poprawnie skonfigurowany. Prawdopodobnie znacznie czystsze byłoby użycie oddzielnej funkcji do zamiany ciągów zmiennych. Pamiętaj, że wektor new_name może wymagać powtórzenia na różne sposoby, aby dopasować kolejność oryginalnego zestawu danych. Podwójnie i potrójnie sprawdź, czy zostało to poprawnie osiągnięte.

Alexander Kielland
źródło
Może być nieco przyjemniejszy w użyciu: new_names <- c('setosa' = 'Bristle-pointed iris', 'versicolor' = 'Poison flag iris', 'virginica' = 'Virginia iris')a następnie w mutacji możesz w ten sposób utworzyć nową kolumnę:mutate(Spec = new_names[Species])
filups21
3

To działa dla mnie.

Zdefiniuj czynnik:

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

i użyj w ggplot():

facet_grid( hospitals.factor[hospital] ~ . )
Hernán Castelo
źródło
2

Po prostu poszerzając odpowiedź naught101 - należy mu się uznanie

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))
    }
}

Musisz tylko utworzyć listę z mapowaniem nazwy na nazwę

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

i przedefiniuj za plot_labeller()pomocą nowych domyślnych argumentów:

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

I wtedy:

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

Alternatywnie możesz utworzyć dedykowaną funkcję dla każdej zmiany etykiety, którą chcesz wprowadzić.

użytkownik4786271
źródło
2

Mam inny sposób na osiągnięcie tego samego celu bez zmiany podstawowych danych:

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())

To, co zrobiłem powyżej, to zmiana etykiet współczynnika w oryginalnej ramce danych, i to jedyna różnica w porównaniu z oryginalnym kodem.

ytu
źródło
1

Czy próbowałeś zmienić określone poziomy swojego Hospitalwektora?

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
źródło
1

Czuję, że powinienem dodać do tego moją odpowiedź, ponieważ zajęło mi to dość długo:

Ta odpowiedź jest dla Ciebie, jeśli:

  • robisz nie chcą zmieniać swoje pierwotne dane
  • jeśli potrzebujesz wyrażeń ( bquote) w etykietach i
  • jeśli chcesz elastyczności oddzielnego etykietowania wektor-nazwa

Zasadniczo umieszczam etykiety w nazwanym wektorze, aby nie pomylić ani nie zamienić etykiet. labellerEkspresja prawdopodobnie mógłby być prostszy, ale ten przynajmniej robót (ulepszenia są bardzo mile widziane). Zwróć uwagę na `(poprzednie cudzysłowy), aby chronić współczynnik kształtu.

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')

wprowadź opis zdjęcia tutaj

Dani
źródło
1

Proste rozwiązanie ( stąd ):

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)
Nacięcie
źródło
0

Po zmaga się przez chwilę, co znalazłem jest to, że możemy korzystać fct_relevel()i fct_recode()ze forcatsw połączeniu zmienić kolejność aspektach, jak również naprawić etykiety fazowane. Nie jestem pewien, czy jest obsługiwany przez projekt, ale działa! Sprawdź wykresy poniżej:

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

Utworzono 2020-02-16 przez pakiet reprezentx (v0.3.0)

Ashirwad
źródło