Как изменить метки фасетов?


231

Я использовал следующую ggplotкоманду:

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

производить

альтернативный текст

Однако я хотел бы изменить метки фасетов на более короткие (например Hosp 1, Hosp 2...), потому что они слишком длинные и выглядят тесными (увеличение высоты графика не вариант, это заняло бы слишком много места в документ). Я посмотрел на страницу помощи facet_grid, но не могу понять, как.

Ответы:


126

Измените базовые имена уровней факторов следующим образом:

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

14
@wishihadabettername: Чтобы избежать изменения базовых данных, вы можете использовать: ggplot(transform(iris, Species = c("S", "Ve", "Vi")[as.numeric(Species)]), aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)
Арно А

1
related ... если вы хотите, чтобы метка панели была выражением bquote () (например, levels(x$measurements) <- c(bquote(Area ~~ (cm^2)), bquote(Length ~~ (cm)))), она не будет отображаться в математическом выражении. Как можно показать выражения в виде меток фасетов?
Брайан Д.

связанные с включением выражений в метку фасета, используйте labellerопцию для facet_grid: stackoverflow.com/questions/37089052/…
Брайан Д

286

Вот решение, которое избегает редактирования ваших данных:

Скажем, ваш график огранен groupчастью вашего фрейма данных, которая имеет уровни control, test1, test2, а затем создайте список, названный этими значениями:

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

Затем создайте функцию labeller и вставьте ее в ваш вызов 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)
 ...

При этом используются уровни фрейма данных для индексации списка hospital_names, возвращая значения списка (правильные имена).


Обратите внимание, что это работает, только если у вас есть только одна переменная фасетирования. Если у вас есть два аспекта, ваша функция-метка должна возвращать разные имена для каждого аспекта. Вы можете сделать это с чем-то вроде:

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

Где facet1_namesи facet2_names- это предварительно определенные списки имен, проиндексированных именами индекса фасета («Hostpital # 1» и т. Д.).


Редактирование: приведенный выше метод завершится неудачно, если вы передадите комбинацию переменная / значение, которую не знает метщик. Вы можете добавить отказоустойчивый для неизвестных переменных, как это:

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

Ответ адаптирован из того, как изменить метки strip.text в ggplot с помощью facet и margin = TRUE


edit: ПРЕДУПРЕЖДЕНИЕ : если вы используете этот метод для фасетирования столбца символов , возможно, вы получаете неправильные метки. Смотрите этот отчет об ошибке . исправлено в последних версиях ggplot2.


9
Хорошо, но не будет работать с facet_wrap, тогда как решение @Vince будет работать и с facet_wrap.
Арно А

@ArnaudAmzallag: Правильно, хотя, если кто-то захочет пожертвовать время, это может произойти в будущем .
naught101

Добавлен отказоустойчивый для неизвестных переменных фасетирования.
naught101

16
Примечание: это не работает в ggplot2 v.2 - функция labeller изменилась. @mbirons ответ работает stackoverflow.com/a/34811062/162832
Андреас

Интересно, но это не всегда работает, тогда как редактирование факторов всегда работает.
PatrickT

214

Вот еще одно решение, которое соответствует духу @naught101, но более простое и не выдает предупреждение о последней версии ggplot2.

По сути, вы сначала создаете именованный символьный вектор

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

И затем вы используете его в качестве метки, просто изменив последнюю строку кода, заданного @ naught101 для

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

Надеюсь это поможет.


В какой версии находится ggplot2 as_labeller? Я нашел некоторый исходный код для репозитория CRAN GitHub , но после обновления до последней версии (на CRAN!) У меня, похоже, нет этой функции.
n1k31t4

Это странно. Я тоже обновился через CRAN. Вот документация docs.ggplot2.org/dev/as_labeller.html
mbiron

4
Это здорово. Что происходит, когда у вас есть две переменные в вашей сетке фасетов? Нравится hospital ~ genderили что? Есть ли способ использовать метки на обеих осях? Я не вижу ничего очевидного в документах.
naught101

3
Обратите внимание, что если вы начали с нулевого ответа, этот работает только с c (), а не со списком () .
thomas88wp

1
Одна большая часть этого - то, что это работает с обеими осями фасетной сетки!
Calum You

30

Вот как я это сделал с facet_grid(yfacet~xfacet)помощью ggplot2, версия 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")
    )
)

Обратите внимание, что это не содержит призыв к as_labeller()- то, с чем я боролся некоторое время.

Этот подход вдохновлен последним примером на странице справки «Привести к функции labeller» .


это работает!!! Я не смог применить другие решения, потому что некоторые из предложенных решений устарели в текущих версиях ggplot2.
Ян

Вы можете построить эти именованные векторы с помощью setNames() stackoverflow.com/a/22428439/3362993
января

23

Если у вас есть два аспекта hospitalи , roomно нужно переименовать только один, вы можете использовать:

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

Для переименования двух аспектов с использованием векторного подхода (как в ответе naught101) вы можете сделать:

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

16

Самый простой способ изменить БЕЗ изменения основных данных:

1) Создайте объект с помощью as_labellerфункции, добавив обратную галочку для каждого значения по умолчанию :

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) Добавляем в GGplot:

ggplot(dataframe, aes(x=Temperature.C,y=fit))+geom_line()+ facet_wrap(~Humidity.RH., nrow=2,labeller=hum.names)

1
Это, я думаю, самый элегантный метод - он эффективен и работает с ggplot2 версии 3.0.0.9000
Landak

9

Обратите внимание, что это решение не будет работать хорошо в случае, если ggplot покажет меньше факторов, чем на самом деле содержит ваша переменная (что могло бы произойти, если бы вы, например, выполняли поднаборы):

 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)

Простое решение (помимо добавления всех неиспользованных факторов в names_li, что может быть утомительным) - удалить неиспользуемые факторы с помощью droplevels (), либо в исходном наборе данных, либо в функции labbeler, см.

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)

9

Это решение очень близко к тому, что имеет @domi, но оно предназначено для сокращения имени путем извлечения первых 4 букв и последнего числа.

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

введите описание изображения здесь


6

Оба facet_wrapи facet_gridтакже принимают входные данные ifelseв качестве аргумента. Поэтому, если переменная, используемая для огранки, логична, решение очень простое:

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

Если переменная имеет больше категорий, ifelseоператор должен быть вложенным .

Как побочный эффект, это также позволяет создавать группы в рамках ggplotвызова.


5

Добавление другого решения, похожего на @ domi's, с разбором математических символов, надстрочного индекса, нижнего индекса, скобок / скобок, .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}, "]"))))

Создано 2019-03-30 пакетом представлением (v0.2.1.9000)



3

Я думаю, что все другие решения действительно полезны для этого, но есть еще один способ.

Я предполагаю:

  • вы установили dplyrпакет, который имеет удобную mutateкоманду, и
  • Ваш набор данных назван survey.

    Опрос%>% мутации (Hosp1 = Больница1, Hosp2 = Больница2, ........)

Эта команда помогает вам переименовывать столбцы, но все остальные столбцы сохраняются.

Тогда сделай то же самое facet_wrap, теперь ты в порядке.


извините, он не работает, так как он также меняет содержимое столбца
Jens

3

Определение функции labeller в variable, valueкачестве аргументов не будет работать для меня. Также, если вы хотите использовать выражение, вам нужно использовать lapply, и вы не можете его просто использовать arr[val], поскольку аргументом функции является data.frame.

Этот код работал:

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)

3

Так как я еще не разрешено комментировать сообщения, я отправляю это отдельно в качестве дополнения к ответу Винса и ответ son520804 в . Кредит идет им.

Son520804:

используя данные Iris:

Я предполагаю:
вы установили пакет dplyr, который имеет удобную команду mutate, и ваш набор данных называется survey. survey %>% mutate(Hosp1 = Hospital1, Hosp2 = Hospital2,........) Эта команда помогает вам переименовывать столбцы, но все остальные столбцы сохраняются. Затем сделайте то же самое facet_wrap, теперь вы в порядке.

Используя пример ириса Винса и частичный код son520804, я сделал это с помощью функции mutate и нашел простое решение, не касаясь исходного набора данных. Хитрость заключается в том, чтобы создать вектор имен-заменителей и использовать mutate () внутри канала для временной коррекции имен фасетов:

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

В этом примере вы можете видеть, что уровни i $ Species временно изменяются на соответствующие общие имена, содержащиеся в векторе new_names. Строка, содержащая

mutate(Species=new_names) %>%

может быть легко удален, чтобы показать оригинальное наименование.

Предупреждение: это может легко привести к ошибкам в именах, если вектор new_name настроен неправильно. Вероятно, было бы намного понятнее использовать отдельную функцию для замены переменных строк. Имейте в виду, что вектор new_name может потребоваться повторять различными способами, чтобы соответствовать порядку вашего исходного набора данных. Пожалуйста, дважды и трижды проверьте, что это правильно достигнуто.


Это может быть немного приятнее для использования: new_names <- c('setosa' = 'Bristle-pointed iris', 'versicolor' = 'Poison flag iris', 'virginica' = 'Virginia iris')и затем в mutate вы можете создать новый столбец таким образом:mutate(Spec = new_names[Species])
filups21

3

Это работает для меня.

Определите фактор:

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

и использовать в ggplot():

facet_grid( hospitals.factor[hospital] ~ . )

2

Просто расширяя ответ naught101 - ему достается кредит

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

Что вам нужно сделать, это создать список с сопоставлением имени к имени

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

и переопределить plot_labeller()с новыми аргументами по умолчанию:

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

А потом:

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

В качестве альтернативы вы можете создать отдельную функцию для каждого изменения метки, которое вы хотите иметь.


2

У меня есть другой способ достижения той же цели без изменения базовых данных:

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

То, что я сделал выше, это изменение меток фактора в исходном фрейме данных, и это единственное отличие по сравнению с вашим исходным кодом.


1

Вы пытались изменить конкретные уровни вашего Hospitalвектора?

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"

1

Я чувствую, что должен добавить свой ответ к этому, потому что мне потребовалось довольно много времени, чтобы сделать эту работу:

Этот ответ для вас, если:

  • Вы не хотите редактировать свои исходные данные
  • если вам нужны выражения ( bquote) в ваших ярлыках и
  • если вы хотите гибкость отдельной маркировки имени-вектора

Я в основном поместил метки в именованный вектор, чтобы метки не путались и не переключались. labellerВыражение, вероятно , может быть проще, но это по крайней мере , работы (улучшения очень приветствуется). Обратите внимание на `(обратные кавычки), чтобы защитить фасет-фактор.

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

введите описание изображения здесь


1

Простое решение ( отсюда ):

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)

0

После борьбы за какое - то время, что я нашел то , что мы можем использовать fct_relevel()и fct_recode()от forcatsсовместно изменить порядок граней , а также исправить фасеты этикетку. Я не уверен, что это поддерживается дизайном, но это работает! Проверьте графики ниже:

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

Создано 2020-02-16 пакетом представлением (v0.3.0)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.