ggplot: как изменить метки фасетов?
Я использовал следующую команду 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 ~ .)
+ opts(panel.background = theme_blank())
производить
Однако я хотел бы изменить метки фасетов на более короткие (например, Hosp 1, Hosp 2...), потому что они слишком длинные и выглядят тесными (увеличение высоты графика не вариант, это потребовало бы слишком много места в документе). Я посмотрел на страницу помощи facet_grid, но не могу понять, как.
23 ответа
Измените имена базовых уровней факторов примерно так:
# 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 ~ .)
Вот решение, которое позволяет избежать редактирования ваших данных:
Скажите, что ваш сюжет огранен 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.
Вот еще одно решение, которое соответствует духу @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))
Надеюсь это поможет.
Самый простой способ изменить БЕЗ изменения основных данных:
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)
Вот как я это сделал с 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".
Если у вас есть два аспекта 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)))
Добавление другого решения, похожего на @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)
Простое решение ( отсюда):
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)
Это решение очень близко к тому, что есть у @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))
И то и другое facet_wrap
а также facet_grid
также принять вход от ifelse
в качестве аргумента. Поэтому, если переменная, используемая для огранки, логична, решение очень простое:
facet_wrap(~ifelse(variable, "Label if true", "Label if false"))
Если переменная имеет больше категорий, ifelse
утверждение должно быть вложенным.
Как побочный эффект, это также позволяет создавать группы в рамках ggplot
вызов.
Обратите внимание, что это решение не будет работать хорошо в случае, если 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)
Это работает для меня.
Определите фактор:
hospitals.factor<- factor( c("H0","H1","H2") )
и использовать, в ggplot()
:
facet_grid( hospitals.factor[hospital] ~ . )
Поскольку мне еще не разрешено комментировать сообщения, я публикую это отдельно как дополнение к ответу Винса и ответу 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 может потребоваться повторить различными способами, чтобы соответствовать порядку вашего исходного набора данных. Пожалуйста, дважды и трижды проверьте, что это правильно достигнуто.
Определение функции 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)
Я думаю, что все другие решения действительно полезны для этого, но есть еще один способ.
Я предполагаю:
- вы установили
dplyr
пакет, который имеет удобныйmutate
команда и Ваш набор данных назван
survey
,Опрос%>% мутация (Hosp1 = Больница1, Hosp2 = Больница2,........)
Эта команда помогает вам переименовывать столбцы, но все остальные столбцы сохраняются.
Затем сделайте то же самое facet_wrap
, ты в порядке сейчас.
У меня есть другой способ достичь той же цели без изменения базовых данных:
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())
То, что я сделал выше, это изменение меток фактора в исходном фрейме данных, и это единственное отличие по сравнению с вашим исходным кодом.
Я чувствую, что должен добавить свой ответ на это, потому что мне потребовалось довольно много времени, чтобы сделать эту работу:
Этот ответ для вас, если:
- вы не хотите редактировать исходные данные
- если вам нужны выражения (
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')
Один лайнер от мишабалясина :
facet_grid(.~vs, labeller = purrr::partial(label_both, sep = " #"))
Посмотреть в действии
library(reprex)
library(tidyverse)
mtcars %>%
ggplot(aes(x="", y=gear,fill=factor(gear), group=am)) +
geom_bar(stat="identity", width=1) +
coord_polar("y", start=0) +
facet_grid(.~vs, labeller = purrr::partial(label_both, sep = " #"))
Создано 2021-07-09 пакетом REPEX (v2.0.0)
Просто расширяя ответ 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)
В качестве альтернативы вы можете создать отдельную функцию для каждого изменения метки, которое вы хотите иметь.
После некоторой борьбы я обнаружил, что мы можем использовать 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
Создано 16.02.2020 пакетом REPEX (v0.3.0)
Мой подход к этой проблеме в эти дни заключается в использовании
dplyr::case_when
для производства этикетировщика в пределах или
facet_wrap
функция. Это расширение решения, предложенного @lillemets.
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(case_when(hospital == "Hospital #1" ~ "Hosp1",
hospital == "Hospital #2" ~ "Hosp2") ~ .)
+ theme(panel.background = theme_blank())
Что хорошо, так это то, что если у вас есть вторая метка фасета, которую нужно изменить, вы просто используете тот же подход на другой стороне
~
в пределах
facet_grid
Вы пытались изменить конкретные уровни вашего 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"
Найден простой способ присвоить значения существующему вектору без необходимостиc=(`1`="first name",`2`="second name")
и т. д.
Сначала создайте функцию маркировки
title_labeller_function <- function(nuisance_parameter) {
return(vector_of_labels)
}
,гдеvector_of_labels
ваши ярлыки, например.c("first label", "second label")
Затем просто назначьте это в своемfacet_grid/facet_wrap
facet_grid(.~ hospital,labeller=as_labeller(title_labeller_function))
Для получения дополнительной информации см. as_labeller-documentation .