如何以r中水平堆叠条形图的样式创建时间序列图

如何以r中水平堆叠条形图的样式创建时间序列图,r,plot,time-series,bar-chart,R,Plot,Time Series,Bar Chart,我想创建一个水平的“堆叠条形图”,其中日期沿x轴运行,我的样本在y轴上显示为条形图。在下面的简单示例中,我有三个样本(a、b、c),每个样本包含三个值(0、1、2)。我希望水平条根据x轴上每个时间步的值进行着色,这样我最终会得到三个水平条(每个样本一个),它们从我的第一个时间点到最后一个时间点,并包含一系列具有与不同值相关的颜色的块 例如,假设我希望值0为蓝色,值1为黄色,值2为红色:对于样本a,跟踪的前两天为蓝色,接下来的两天为黄色,然后是一个蓝色,依此类推 示例数据: df <- st

我想创建一个水平的“堆叠条形图”,其中日期沿x轴运行,我的样本在y轴上显示为条形图。在下面的简单示例中,我有三个样本(a、b、c),每个样本包含三个值(0、1、2)。我希望水平条根据x轴上每个时间步的值进行着色,这样我最终会得到三个水平条(每个样本一个),它们从我的第一个时间点到最后一个时间点,并包含一系列具有与不同值相关的颜色的块

例如,假设我希望值0为蓝色,值1为黄色,值2为红色:对于样本a,跟踪的前两天为蓝色,接下来的两天为黄色,然后是一个蓝色,依此类推

示例数据:

df <- structure(list(date = c("30/04/2011", "01/05/2011", "02/05/2011", "03/05/2011", "04/05/2011", "05/05/2011", "06/05/2011", "07/05/2011", "08/05/2011", "09/05/2011", "10/05/2011", "11/05/2011", "12/05/2011", "13/05/2011", "14/05/2011", "15/05/2011", "16/05/2011", "17/05/2011", "18/05/2011", "19/05/2011", "20/05/2011", "21/05/2011", "22/05/2011", "23/05/2011", "24/05/2011", "25/05/2011", "26/05/2011", "27/05/2011", "28/05/2011", "29/05/2011", "30/05/2011", "31/05/2011", "01/06/2011", "02/06/2011", "03/06/2011", "04/06/2011", "05/06/2011", "06/06/2011", "07/06/2011", "08/06/2011", "09/06/2011", "10/06/2011", "11/06/2011", "12/06/2011", "13/06/2011", "14/06/2011", "15/06/2011", "16/06/2011", "17/06/2011", "18/06/2011", "19/06/2011", "20/06/2011", "21/06/2011", "22/06/2011", "23/06/2011", "24/06/2011", "25/06/2011", "26/06/2011", "27/06/2011", "28/06/2011", "29/06/2011", "30/06/2011", "01/07/2011", "02/07/2011", "03/07/2011", "04/07/2011", "05/07/2011", "06/07/2011", "07/07/2011", "08/07/2011", "09/07/2011", "10/07/2011", "11/07/2011", "12/07/2011", "13/07/2011", "14/07/2011", "15/07/2011", "16/07/2011", "17/07/2011", "18/07/2011", "19/07/2011", "20/07/2011", "21/07/2011", "22/07/2011", "23/07/2011", "24/07/2011"), a = c(0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L), b = c(0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L), c = c(1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L)), .Names = c("date", "a", "b", "c"), class = "data.frame", row.names = c(NA, -86L))

head(df)
#         date a b c
# 1 30/04/2011 0 0 1
# 2 01/05/2011 0 1 1
# 3 02/05/2011 1 1 0
# 4 03/05/2011 1 0 0
# 5 04/05/2011 0 0 0

df这是一本非常实用的手册,但我认为它回答了您的问题。据我所知,没有一个函数能为你做到这一点,但我很可能是错的。我只是用多边形来为每组画框注意:您需要将日期字段更改为日期类。

dat$date <- as.Date(dat$date, "%d/%m/%Y")

plot(dat$a~dat$date, type = "n", yaxt = "n", ylab = "", 
     xlab = "", bty = "n", ylim = c(0, 4))
draw.box <- function(y, x1, x2, h, col) {
  polygon(x = c(x1, x1, x2, x2), 
          y = c(y - h/2, y + h/2, y + h/2, y - h/2),
          col = col, border = col)
}

for (j in c("a", "b", "c")) {
  for (i in 2:nrow(dat)) {
    bcol <- switch(as.character(dat[(i - 1), j]),
                   "0" = "red",
                   "1" = "blue",
                   "2" = "yellow")
    yloc <- switch(j,
                   "a" = 3,
                   "b" = 2,
                   "c" = 1)
    draw.box(y = yloc, 
             h = 0.75, 
             col = bcol, 
             x1 = dat[(i - 1), "date"], 
             x2 = dat[i, "date"])
  }
}

axis(side = 2, at = 3:1, labels = c("A", "B", "C"), 
     tick = FALSE, las = 2)

dat$date我可以让
barplot()
在这里工作,但是,伙计,我不得不跳过一些障碍

首先,
barplot()
需要一个条段长度矩阵,这意味着我们必须从输入数据中获取连续颜色拉伸的运行长度,以定义这些长度(注意:请参阅答案末尾,了解将每个数据点视为单独段的备选方案)。我们还需要捕获适用于每个运行长度的颜色,幸运的是,
rle()
非常适合于此,因为它捕获两个组件列表中的运行长度和值

其次,
barplot()
在堆叠条的着色方面有一个不幸的限制。也就是说,如果为
高度
参数提供一个具有两个或多个堆叠条(意味着两列或多列)的外观正常、结构直观的矩阵,并且希望使用与其他堆叠条不同的颜色序列对每个堆叠条进行着色,则将无法执行此操作。至少,不是那种矩阵结构

这是因为
col
参数只能接受颜色向量;它不能接受与传递给
height
参数的主矩阵输入相对应的矩阵或向量列表或任何其他内容。如果试图提供过长的颜色向量,
barplot()
会忽略多余的颜色向量

基于,解决方案是偏移矩阵中的每个条,将所有相邻列设置为零,从而允许您为每个条中的每个条段设置不同的颜色

要将数据转换成所需的形状并不容易,但借助@akrun对我刚才提出的一个问题的回答,我们可以按如下方式完成所有这些:

pd <- lapply(df[-1],function(v) do.call(cbind,rle(v)));
height <- as.matrix(setNames(reshape(cbind(id=1:sum(sapply(pd,nrow)),stack(lapply(pd,function(x) x[,'lengths']))),dir='w',timevar='ind')[-1],names(pd)));
height[is.na(height)] <- 0;
col <- c('blue','yellow','red')[do.call(c,sapply(pd,function(x) x[,'values']))+1];
barplot(t(apply(height,1,rev)),col=col,horiz=T,axes=F);
axis(1,0:(nrow(df)-1),labels=df$date);
title('Horizontal Stacked Bar Plot');
最后,我尝试在不使用行程步长的情况下构建绘图,而只是将每个数据点视为自己的段。这是可行的(尽管您仍然需要进行补偿),但可能不是您想要的。下面是它的屏幕截图:

下面是代码,如果您更喜欢:

pd <- lapply(df[-1],function(v) rep(1,length(v)));
height <- as.matrix(setNames(reshape(cbind(id=1:sum(sapply(pd,length)),stack(lapply(pd,function(x) x))),dir='w',timevar='ind')[-1],names(pd)));
height[is.na(height)] <- 0;
col <- c('blue','yellow','red')[do.call(c,df[-1]+1)];
barplot(t(apply(height,1,rev)),col=col,horiz=T,axes=F);
axis(1,0:(nrow(df)-1),labels=df$date);
title('Horizontal Stacked Bar Plot');

pd对于ggplot2绘图,首先将df转换为长格式(使用重塑2包中的melt),将日期列转换为
“日期”
类,将
列转换为系数,然后使用
几何图

library(ggplot2)
library(reshape2)

long <- melt(df, measure.var = 2:4)
long <- transform(long, date = as.Date(long$date, "%d/%m/%Y"), value = factor(value))

ggplot(long, aes(date, variable)) + 
   geom_tile(aes(fill = value)) + 
   scale_fill_manual(values = c("blue", "yellow", "red"))
库(ggplot2)
图书馆(E2)

long我不知道如何解释数据,因为如果在两个日期之间定义一个值,那么第一个或最后一个值应该是NA。@dayne:太好了,谢谢!我希望数据具体与df中分配给它们的日期相关,而不是介于两个日期之间,但我认为,通过将轴标签移到条形图的中心而不是勾号,可以很容易地实现这一点。谢谢你的帮助!这也很好。非常感谢。我将尝试转换它,以便x轴标签与条形对齐,而不是与记号对齐。谢谢你的好例子。这很好。如果你不能从我的回答中看出我对ggplot2软件包有抵触情绪,但这是一个非常令人信服的用例。它会单独对待每个日期吗?(而不是我迄今为止填写的答案。)
geom_tile
用彩色块平铺区域,如图所示。@G.Grothendieck。谢谢你。很好,它在每一个日期都以街区为中心。不是ggplot用户,是否有一种简单的方法更改默认值,使绘图类似于在基础图形中绘制的绘图(即,使单个条之间有空格,没有灰度背景和黑色轴?)。非常感谢!我通过在ggplot行中添加
height
来增加条间距
ggplot(long,aes(date,variable,height=0.7))
并使用
theme_bw()
用于删除灰色背景/网格等的命令。我接受了这个答案,因为它将每个块的中心放在日期上,而不是日期之间,但我希望我能全部接受!感谢大家提供了非常有用的回答。您可能希望这样写,在
aes
之外使用
height
geom_tile(aes(fill=value),height=0.7)
library(ggplot2)
library(reshape2)

long <- melt(df, measure.var = 2:4)
long <- transform(long, date = as.Date(long$date, "%d/%m/%Y"), value = factor(value))

ggplot(long, aes(date, variable)) + 
   geom_tile(aes(fill = value)) + 
   scale_fill_manual(values = c("blue", "yellow", "red"))