R:在ggplot2中使用free_x重新排序facet_wrapped x轴

时间:2014-10-07 14:41:37

标签: r plot ggplot2 facet

我尝试在ggplot2中使用reorder的小平面包裹的绘图中使用scales = free_x,但重新排序功能不能正确地重新排序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))

在从this tab-separated file读取的数据框上运行该代码会产生一个图,其中每个刻面图的x轴仅部分排序。 Someone else on SO提出了一个非常类似的问题,但唯一提出的解决方案是使用网格排列。因为我的数据集比那个问题中的数据集要大得多,但这不是一个非常迅速的操作,所以我想问:有没有办法重新排序每个刻面图的x轴以显示尺寸增加(或减少)顺序的条形?我非常感谢其他人可以在这个问题上提供任何帮助。

2 个答案:

答案 0 :(得分:10)

使用略有不同的方法,您可以将标签保留在图表下方的区域中。此版本通过以类似于jlhoward方法的方式连接V1和V2来创建唯一的x中断,但随后使用scale_x_discrete语句中下面代码中的函数角色将V2恢复为x标签。

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

答案 1 :(得分:6)

问题在于ggplotV2视为单因素;它没有为每个方面(V2的值)子集V1,然后将每个方面视为独立因素(不幸的是)。由于某些角色(&#34; Messenger 1&#34;等等)出现在多个游戏中,因此这些级别会根据它们在遇到它们的第一个游戏中的重要性进行排序。

有一种解决方法,但它有点像黑客攻击:你需要通过将播放的名称连接到每个角色来使角色唯一,然后将其用作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(...)参数。