R: Заменить facet_wrapped ось x с помощью free_x в ggplot2
Я пытаюсь использовать reorder
в факсимильном графике, который также использует scales = free_x
в ggplot2, но функция переупорядочения не переупорядочивает ось x правильно. Вот что я запускаю:
library(ggplot2)
df <- read.table("speaking_distribution_by_play.txt",
header = F,
sep = "\t")
ggplot(df, aes(x=reorder(V2, V3), y=V3)) +
geom_bar(stat = "identity") +
facet_wrap(~V1, ncol = 4, scales = "free_x") +
opts(title = "Distribution of Speakers in Shakespearean Drama") +
xlab("Speaking Role") +
ylab("Words Spoken") +
opts(axis.text.x=theme_text(angle=90, hjust=1))
Запуск этого кода в кадре данных, считанного с этот файл с разделителями разделов дает график, в котором ось x каждого граненного участка только частично упорядочен. Кто-то еще на SO задал очень похожий вопрос, но единственным предлагаемым решением было использование сетки. Поскольку мой набор данных немного больше, чем набор данных в этом вопросе, это не будет очень быстрой операцией, поэтому я хотел спросить: есть ли способ изменить порядок оси x каждого грантового графика, так что показать полосы в увеличении (или уменьшении) порядка размера? Я был бы очень благодарен за любую помощь, которую другие могут предложить по этому вопросу.
Ответы
Ответ 1
Проблема заключается в том, что ggplot
рассматривает V2
как один фактор; он не подмножает V2
для каждой грани (значение V1
), а затем относится к каждому из них как к независимым факторам (к сожалению). Поскольку некоторые роли ( "Messenger 1" и т.д.) Появляются в более чем одной игре, эти уровни упорядочиваются в зависимости от их важности в первой игре, в которой они встречаются.
Существует обходной путь, но это немного взломанный: вам нужно сделать роли уникальными, объединив имя игры для каждого, а затем используйте это как значение x. Чтобы вернуть исходные роли, отключите текст оси и вместо этого используйте geom_text(...)
для ярлыков. Вот пример:
gg <- df[order(df$V1,-df$V3),] # reorder by play and lines
gg$lvl <- with(df,paste(V2,V1,sep="."))
ggplot(gg[gg$V1 %in% unique(df$V1)[1:4],],
aes(x=factor(lvl,levels=unique(lvl)), y=V3)) +
geom_text(aes(y=5,label=V2),angle=90,size=3,hjust=-0)+
geom_bar(stat = "identity", fill="blue",alpha=0.2) +
facet_wrap(~V1, ncol = 2, scales="free_x") +
labs(title="Distribution of Speakers in Shakespearean Drama",
x="Speaking Role", y="Words Spoken") +
theme(axis.text.x=element_blank(),axis.ticks.x=element_blank())
![]()
Это выглядит ужасно в таком маленьком масштабе (не так плохо, как ваш оригинальный сюжет, хотя...). Но если вы сделаете его более крупным (как вам нужно делать с 38 играми, нет?), Вы можете увидеть ярлыки и бары. Если вы действительно хотите, чтобы метки были ниже баров, используйте что-то вроде этого:
ggplot(gg[gg$V1 %in% unique(df$V1)[1:4],],
aes(x=factor(lvl,levels=unique(lvl)), y=V3)) +
geom_text(aes(y=-5,label=V2),angle=90,size=3,hjust=1)+
ylim(-500,NA)+
geom_bar(stat = "identity", fill="lightblue") +
facet_wrap(~V1, ncol = 2, scales="free_x") +
labs(title="Distribution of Speakers in Shakespearean Drama",
x="Speaking Role", y="Words Spoken") +
theme(axis.text.x=element_blank(),axis.ticks.x=element_blank())
![]()
Опять же, выглядит ужасно в этом небольшом масштабе, но лучше увеличено. В любом случае вам, вероятно, потребуется настроить параметр size=...
в geom_text(...)
.
Ответ 2
При немного другом подходе вы можете сохранить метки в области под диаграммами. Эта версия создает уникальные перерывы x, объединяя V1 и V2 способом, подобным методу jlhoward, но затем восстанавливает V2 как метки x, используя роды функций в приведенном ниже коде в выражении scale_x_discrete.
library(ggplot2)
df <- read.table("speaking_distribution_by_play.txt",
header = F,
sep = "\t")
# Creates a small test subset; remove for complete set
df <- df[df$V1 %in% c("Mac.xml","MM.xml","MND.xml","MV.xml"),]
# used to create x-axis label restoring original name of role
roles <- function(x) sub("[^_]*_","",x )
ggplot(cbind(df, V4=paste(df$V1,df$V2,sep="_")), aes(x=reorder(V4,V3), y=V3) ) +
geom_bar(stat = "identity") +
facet_wrap(~ V1, ncol=4, scales = "free_x") +
labs(title = "Distribution of Speakers in Shakespearean Drama") +
xlab("Speaking Role") +
ylab("Words Spoken") +
scale_x_discrete(labels=roles) +
theme(axis.text.x=element_text(angle=90, hjust=1))
![enter image description here]()