甘特图时间线绘图(在基础R中)

12

我有一个数据框看起来像这样:

       person n start end
1         sam 6     0   6
2        greg 5     6  11
3     teacher 4    11  15
4         sam 4    15  19
5        greg 5    19  24
6       sally 5    24  29
7        greg 4    29  33
8         sam 3    33  36
9       sally 5    36  41
10 researcher 6    41  47
11       greg 6    47  53

这里的start和end是时间或持续时间(例如,Sam从0点到6点说话,Greg从6点到11点说话等),n表示该人说话的长度(在本例中为单词数)。我想在基础R中将其绘制成一个时间轴图(最终可能会使用ggplot2问类似的问题,但此答案适用于基础R [当我说基础时,我的意思是随着标准安装的软件包]

y轴将是按人员分组,x轴将是时间。希望最终产品看起来像上面的数据:

Timeline_Graph

我想使用基础R来实现这一点。但我不确定如何处理。我的想法是使用散点图并绘制一个散点图,但不包括散点。然后用方形段结束它。但是我不确定这样做的效果,因为段需要数值型的x和y点才能生成线段,而y轴是分类变量。另一个想法是将因子转换为数字(为每个因子分配一个数字),并绘制一个空散点图,然后用方形段结束它。这可能是我领域中观察语音模式的有力工具。

提前感谢您的帮助。

PS:使用方形结束线段的参数是 segments(... , lend=2),为了节省时间,对于那些不熟悉所有线段参数的人来说,请注意这一点。

3个回答

31

你说你想要一个基于R的解决方案,但你没有说原因。既然这只是ggplot中的一行代码,我还是会展示它。

library(ggplot2)
ggplot(dat, aes(colour=person)) + 
    geom_segment(aes(x=start, xend=end, y=person, yend=person), size=3) +
    xlab("Duration")

输入图片说明


他似乎已经避免了他正在开发的软件包的所有其他外部依赖,并试图保持这种状态:https://dev59.com/ymHVa4cB1Zd3GeqPru0V。 - Chase
他可能还想更好地控制外观,更好地理解基础图形,将其与其他基础图形绘图集成,或者只是出于个人喜好。哦,这不是真正的一行。你至少有两行,很容易被解释为三行,并且你忘记了安装包'ggplot2'。 - John
1
@Andrie,非常好。 我不想使用ggplot的原因是如Chase所指出的,我除了wordcloud之外避免了所有依赖项(因为该软件包在C中执行一些编码,我无法进行)。 话虽如此,该函数将绘制但也将返回一个处理过的数据框,该数据框可以馈送到ggplot中(我计划在我的软件包中显示这个示例,但可能必须使用“#”获取代码来通过软件包创建测试。 我对ggplot感兴趣的原因是我会使用相同的想法进行重复测量,并且在这里分面将很好。 太棒了Andrie。 +1 - Tyler Rinker
2
@TylerRinker 不错。你有两个选项可以在不引入依赖项的情况下将其包含在软件包中。1)使用 dontrun 块 http://cran.r-project.org/doc/manuals/R-exts.html#index-g_t_005cdontrun-76 2)在软件包的 DESCRIPTION 中使用 suggests(ggplot2),然后在示例中使用 require(ggplot2)。这样,只有当用户真正想要使用它时,才会加载 ggplot2 软件包。 - Andrie
@Andrie 谢谢,这是我为普通消费者创建的第一个软件包(之前我已经为自己创建了两个软件包,但对于第一次尽可能纪律严明)。我希望提供尽可能高质量的产品。感谢您提供依赖关系与建议信息。+1 - Tyler Rinker
你好,有什么方法可以在条形图上添加文本标签吗? - M.Qasim

17

和@John的方法非常相似,但是由于我做了这个,所以我会发布它 :)

这里有一个通用函数来绘制甘特图(不需要依赖):

plotGantt <- function(data, res.col='resources', 
                      start.col='start', end.col='end', res.colors=rainbow(30))
{
  #slightly enlarge Y axis margin to make space for labels
  op <- par('mar')
  par(mar = op + c(0,1.2,0,0)) 

  minval <- min(data[,start.col],na.rm=T)
  maxval <- max(data[,end.col],na.rm=T)

  res.colors <- rev(res.colors)
  resources <- sort(unique(data[,res.col]),decreasing=T)

  plot(c(minval,maxval),
       c(0.5,length(resources)+0.5),
       type='n', xlab='Duration',ylab=NA,yaxt='n' )
  axis(side=2,at=1:length(resources),labels=resources,las=1)
  for(i in 1:length(resources))
  {
    yTop <- i+0.1
    yBottom <- i-0.1
    subset <- data[data[,res.col] == resources[i],]
    for(r in 1:nrow(subset))
    {
      color <- res.colors[((i-1)%%length(res.colors))+1]
      start <- subset[r,start.col]
      end <- subset[r,end.col]
      rect(start,yBottom,end,yTop,col=color)
    }
  }
  par(mar=op) # reset the plotting margins
}

使用示例:

data <- read.table(text=
'"person","n","start","end"
"sam",6,0,6
"greg",5,6,11
"teacher",4,11,15
"sam",4,15,19
"greg",5,19,24
"sally",5,24,29
"greg",4,29,33
"sam",3,33,36
"sally",5,36,41
"researcher",6,41,47
"greg",6,47,53',sep=',',header=T)

plotGantt(data, res.col='person',start.col='start',end.col='end',
          res.colors=c('green','blue','brown','red','yellow'))

Result:

enter image description here


这个回答也满足了我列出的参数。它看起来也很棒。谢谢你分享一个稍微不同的方法。+1 - Tyler Rinker
还有,谢谢你告诉我甘特图这个词,我之前不知道它的名称。 - Tyler Rinker
1
@TylerRinker:不用谢 : )。但是我稍微修改了代码以腾出标签的空间。 - digEmAll
我想将这些工作中的一部分包含在一个软件包中。我想要正确引用你。请通过tyler.rinker@gmail.com与我联系。 - Tyler Rinker
2
@TylerRinker:谢谢,但是这段小代码不需要引用我的名字。请随意使用 ;) - digEmAll
@digEmAll - 你好,我有一个后续问题,关于如何在y轴上绘制类别,当它们存在于整个数据框中,但不在你正在绘制的子集中,并且还能够始终使用特定y轴类别的颜色。我在这里发布了一个问题- http://stackoverflow.com/questions/26374327/gantt-plot-in-base-r-modifying-plot-properties - 希望你能帮忙。谢谢。 - jalapic

8

当y轴是分类变量时,你只需要给这些类别分配数字(1:5),并进行跟踪。使用因子的默认as.numeric()通常会按字母顺序给它们编号,但你仍然应该检查一下。使用xaxt='n'参数制作图表,然后使用axis()命令放置y轴。

axis(2, 1:5, myLabels)

请记住,无论何时绘制图表,唯一放置事物的方式都是使用数字。分类的 x 或 y 值始终只是 1:nCategories 的数字,轴上用类别名称标签代替数字。
以下代码可以让你接近目标(假设你的数据框对象叫做 datf)...
datf$pNum <- as.numeric(datf$person)
plot(datf$pNum, xlim = c(0, 53), type = 'n', yaxt = 'n', xlab ='Duration (words)', ylab = 'person', main = 'Speech Duration')
axis(2, 1:5, sort(unique(datf$person)), las = 2, cex.axis = 0.75)
with(datf, segments(start, pNum, end, pNum, lwd = 3, lend=2))

非常好。这几乎做到了我要求的(在基本参数内),我可以接着做下去了。非常好的工作。 - Tyler Rinker
希望你不介意,我在你的“segments”使用中加入了一段代码“,lend=2”。 - Tyler Rinker
能否添加结果的图像? - Roman Luštrik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接