#r #ggplot2
#r #ggplot2
Вопрос:
Мой график имеет категориальную ось X и несколько типов элементов для рисования:
dt1 <- fread('
ID type value
a1 bar 40
a1 point 30
b1 bar 50
b1 point 20
c1 bar 30
c1 point 50
c1 point 20
d1 point 30
d1 point 50
e1 none 50
a2 bar 45
a2 point 30
')
# I want some custom order on the plot:
dt1[, ID:=factor(ID, levels=unique(ID[order(value)]))]
# here it will be b1 - c1 - a1 - d1 - a2
Если я построю график с geom_point()
последующим geom_bar()
, порядок X
осей будет правильным:
ggplot(dt1, aes(x=ID,y=value))
geom_point(data=dt1[type=='point',], size=5, col='red')
geom_bar( data=dt1[type=='bar',], stat='identity', alpha=0.5)
Но если у меня есть geom_bar()
в качестве первого слоя, за которым следует geom_point()
, он игнорирует уровни моей x
ID
переменной () и переупорядочивает ее в алфавитном порядке:
ggplot(dt1, aes(x=ID,y=value))
geom_bar( data=dt1[type=='bar',], stat='identity', alpha=0.5)
geom_point(data=dt1[type=='point',], size=5, col='red')
(Обратите внимание, что geom_bar()
, поскольку один слой имеет правильный порядок, проблема возникает только тогда, когда за ним следует другой уровень!) Почему это происходит и как это исправить? Я нашел один обходной путь с добавлением scale_x_discrete(drop=FALSE)
, но мне это не нравится, потому что он добавляет категории, которых там не должно быть:
ggplot(dt1, aes(x=ID,y=value))
geom_bar( data=dt1[type=='bar',], stat='identity', alpha=0.5)
geom_point(data=dt1[type=='point',], size=5, col='red')
scale_x_discrete(drop=F)
Ответ №1:
Это происходит потому, что более поздний слой содержит уровни, отсутствующие в более раннем слое (напомним, что неиспользуемые уровни по умолчанию удаляются, поэтому после построения слоя все неиспользуемые уровни удаляются). ggplot()
не знает, как объединить (что становится) два разных фактора, чтобы они были преобразованы в вектор символов (а затем обратно в фактор) перед нанесением на график. Вы можете использовать limits
аргумент in scale_x_discrete()
, чтобы указать желаемый порядок.
library(ggplot2)
library(data.table)
ggplot()
aes(x=ID,y=value)
geom_col(data=dt1[type=='bar',], alpha=0.5)
geom_point(data=dt1[type=='point',], size=5, col='red')
scale_x_discrete(limits = levels(droplevels(dt1$ID[dt1$type %in% c("bar", "point")])))
Вы можете сделать это немного более аккуратно, установив свои данные перед построением графика:
dt2 <- dt1[type != "none"]
dt2[, ID:=factor(ID, levels=unique(ID[order(value)]))]
ggplot()
aes(x=ID,y=value)
geom_col(data=dt1[type=='bar',], alpha=0.5)
geom_point(data=dt1[type=='point',], size=5, col='red')
scale_x_discrete(limits = levels(dt2$ID))
Комментарии:
1. Спасибо! Как вы думаете, может ли быть какой-либо способ достичь этого без явного перечисления
%in% c("bar", "point")
? В моем реальном случае у меня много критериев, поэтому я бы предпочел не перечислять их снова вручную.2. Я обновил — я бы подмножил данные перед построением графика.
3. понял, спасибо! (У меня есть своего рода продолжение этого вопроса, но я решил опубликовать его отдельно)