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