【问题标题】:how to use black-and-white fill patterns instead of color coding on Calendar Heatmap如何在日历热图上使用黑白填充图案而不是颜色编码
【发布时间】:2013-02-22 00:05:38
【问题描述】:

我正在使用Paul BleicherCalendar Heatmap 来可视化一段时间内的一些事件,我有兴趣添加black-and-white fill patterns 而不是(或在其之上)颜色编码以增加日历热图的可读性黑白打印时。

这是日历热图的彩色示例,

这是它在黑白中的样子,

很难区分黑白的各个级别。

有没有一种简单的方法可以让 R 为 6 个级别添加某种模式而不是颜色?

重现彩色日历热图的代码。

source("http://blog.revolution-computing.com/downloads/calendarHeat.R")

stock <- "MSFT"
start.date <- "2012-01-12"
end.date <- Sys.Date()

quote <- paste("http://ichart.finance.yahoo.com/table.csv?s=", stock, "&a=", substr(start.date,6,7), "&b=", substr(start.date, 9, 10), "&c=", substr(start.date, 1,4), "&d=", substr(end.date,6,7), "&e=", substr(end.date, 9, 10), "&f=", substr(end.date, 1,4), "&g=d&ignore=.csv", sep="")
stock.data <- read.csv(quote, as.is=TRUE)

# convert the continuous var to a categorical var 
stock.data$by <- cut(stock.data$Adj.Close, b = 6, labels = F)

calendarHeat(stock.data$Date, stock.data$by, varname="MSFT Adjusted Close")

更新 02-13-2013 03:52:11Z,添加模式是什么意思

我设想将模式添加到日历热图中的各个日期框,因为模式被添加到此图中右侧 (B) 饼图中的各个切片中,

发现here 类似于this plot 中的状态。

【问题讨论】:

  • 添加一个pettern是什么意思?您想更改单元格的大小吗?是否要在某些单元格中添加文本?​​
  • 理论上您可以覆盖格子面板函数以使用gridExtra::grid.pattern 而不是grid.rect。但它不太可能很好地工作,因为这个功能是错误的
  • @agstudy,谢谢你的提问。我添加了一个更新来澄清,但我喜欢你在个人日盒中添加一封信或类似的东西的想法。无论如何,我最初设想的某种模式就像我在更新中描述的那样。
  • @baptiste,我查看了calendarHeat 函数,但看不到使用了grid.rect。请您解释一下如何将grid.rect 替换为gridExtra::grid.pattern。谢谢。
  • 添加字母或点符号可能是一个更好的主意;为此,您也应该编写一个自定义面板功能。顺便说一句,为什么是 ggplot2 标签?

标签: r plot ggplot2 heatmap visualize


【解决方案1】:

我在他成为赏金之前回答了这个问题。看起来 OP 发现我以前的答案有点复杂。我将代码组织在一个要点here 中。您只需要下载文件并获取它。

我创建了新函数extra.calendarHeat,这是第一个绘制双时间序列hetmap的扩展。(dat,value1,value2)。我添加了这个新参数:

   pch.symbol : vector of symbols , defualt 15:20
   cex.symbol : cex of the symbols , default = 2
   col.symbol : color of symbols , default #00000044
   pvalues    : value of symbols

这里有一些例子:

## I am using same data 
stock <- "MSFT"
start.date <- "2012-01-12"
end.date <- Sys.Date()
quote <- paste("http://ichart.finance.yahoo.com/table.csv?s=",
               stock,
               "&a=", substr(start.date,6,7),
               "&b=", substr(start.date, 9, 10),
               "&c=", substr(start.date, 1,4), 
               "&d=", substr(end.date,6,7),
               "&e=", substr(end.date, 9, 10),
               "&f=", substr(end.date, 1,4),
               "&g=d&ignore=.csv", sep="")             
stock.data <- read.csv(quote, as.is=TRUE)

p1 <- extra.calendarHeat(dates= stock.data$Date, values = stock.data$Adj.Close,
                         pvalues = stock.data$Volume,
                         varname="W&B MSFT Adjusted Close 
                                  \n Volume as no border symbol ")

## multiply symbols
p2 <- extra.calendarHeat(dates= stock.data$Date, values = stock.data$Adj.Close,
                         pvalues = stock.data$Volume,
                         varname="W&B MSFT Adjusted Close \n 
                                    black Volume as multiply symbol ",
                         pch.symbol = c(3,4,8,9),
                         col.symbol='black')

## circles symbols
p3 <- extra.calendarHeat(dates= stock.data$Date, values = stock.data$Adj.Close,
                         pvalues = stock.data$Volume,
                         varname="W&B  MSFT Adjusted Close \n blue Volume as circles",
                         pch.symbol = c(1,10,13,16,18),
                         col.symbol='blue')

## triangles  symbols
p4 <- extra.calendarHeat(dates= stock.data$Date, values = stock.data$Adj.Close,
                         pvalues = stock.data$Volume,
                         varname="W&B MSFT Adjusted Close \n red Volume as triangles",
                         pch.symbol = c(2,6,17,24,25),
                         col.symbol='red')

p5 <- extra.calendarHeat(dates= stock.data$Date, values = stock.data$Adj.Close,
                         varname="MSFT Adjusted Close",
                         pch.symbol = LETTERS,
                         col.symbol='black')

# symbols are LETTERS
p6 <- extra.calendarHeat(dates= stock.data$Date, values = stock.data$Adj.Close,
                         pvalues = stock.data$Volume,
                         varname="MSFT Adjusted Close  \n Volume as LETTERS symbols",
                         pch.symbol = letters,
                         color='r2b')

【讨论】:

  • 这真是令人印象深刻。我会让赏金持续一段时间,然后奖励它。我非常感谢您将所有代码放在一个地方。谢谢!
  • @EricFail 感谢您选择此答案。只是我很好奇你会在什么情况下使用它?
  • 我正在跟踪诊所的客户联系人。我们有一系列不同的接触类型和测试需要密切关注,我们只能使用黑白激光打印机或黑色和灰色调打印机。再次感谢您的帮助。
  • @EricFail 客户端?你的意思是耐心,不是吗?无论如何,您是否在真实数据上对其进行了测试?
  • @EricFail 感谢客户/患者的解释。我很困惑,因为这两个术语以法语存在。不管怎样,很高兴我能帮上忙。
【解决方案2】:

您可以从latticeExtrapanel.level.plot 添加模式。我认为提出的问题有点具体。所以我试图概括它。这个想法是给出将时间序列转换为日历热图的步骤:使用 2 种模式(填充颜色和形状)。我们可以想象多个时间序列(关闭/打开)。例如,你可以得到这样的东西

或者像这样,使用 ggplot2 主题:

函数 calendarHeat 给出一个单一的时间序列 (dat,value) ,像这样转换数据:

   date.seq value dotw woty   yr month seq
1 2012-01-01    NA    0    2 2012     1   1
2 2012-01-02    NA    1    2 2012     1   2
3 2012-01-03    NA    2    2 2012     1   3
4 2012-01-04    NA    3    2 2012     1   4
5 2012-01-05    NA    4    2 2012     1   5
6 2012-01-06    NA    5    2 2012     1   6

所以我假设我的数据格式是这样的,否则,我从 calendarHeat 中提取了函数中数据转换的部分(参见gist

 dat <- transformdata(stock.data$Date, stock.data$by)

那么日历本质上是一个levelplot,带有自定义sacles、自定义theme和自定义panel' function

library(latticeExtra)
levelplot(value~woty*dotw | yr, data=dat, border = "black",
          layout = c(1, nyr%%7),
          col.regions = (calendar.pal(ncolors)),
          aspect='iso',
          between = list(x=0, y=c(1,1)),
          strip=TRUE,
          panel = function(...) {
            panel.levelplot(...)
            calendar.division(...)  
            panel.levelplot.points(...,na.rm=T,
                                   col='blue',alpha=0.5,
                                   ## you can play with cex and pch here to get the pattern you      
                                   ## like
                                   cex =dat$value/max(dat$value,na.rm=T)*3
                                   pch=ifelse(is.na(dat$value),NA,20),
                                   type = c("p"))

          },
          scales= scales,
          xlim =extendrange(dat$woty,f=0.01),
          ylim=extendrange(dat$dotw,f=0.1),
          cuts= ncolors - 1,
          colorkey= list(col = calendar.pal(ncolors), width = 0.6, height = 0.5),
          subscripts=TRUE,
          par.settings = calendar.theme)

天平在哪里:

 scales = list(
   x = list( at= c(seq(2.9, 52, by=4.42)),
             labels = month.abb,
             alternating = c(1, rep(0, (nyr-1))),
             tck=0,
             cex =1),
   y=list(
     at = c(0, 1, 2, 3, 4, 5, 6),
     labels = c("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
                "Friday", "Saturday"),
     alternating = 1,
     cex =1,
     tck=0))

主题设置为:

 calendar.theme <- list(
   xlab=NULL,ylab=NULL,
   strip.background = list(col = "transparent"),
   strip.border = list(col = "transparent"),
   axis.line = list(col="transparent"),
   par.strip.text=list(cex=2))

面板函数使用函数caelendar.division。事实上,网格(月黑计数)的划分很长,并且是使用grid 包以硬方式完成的(面板焦点......)。我稍微改了一下,现在在格子面板函数中调用:caelendar.division

【讨论】:

    【解决方案3】:

    我们可以使用 ggplot2 的 scale_shape_manual 来获得接近阴影的形状,我们可以在灰色热图上绘制这些形状。
    注意:这是改编自 @Jay 在 the original blog 发帖中的 cmets对于日历热图

    # PACKAGES
    library(ggplot2)
    library(data.table)
    
    # Transofrm data
    stock.data <- transform(stock.data,
      week = as.POSIXlt(Date)$yday %/% 7 + 1,
      month = as.POSIXlt(Date)$mon + 1,
      wday = factor(as.POSIXlt(Date)$wday, levels=0:6, labels=levels(weekdays(1, abb=FALSE)), ordered=TRUE),
      year = as.POSIXlt(Date)$year + 1900)
    
    # find when the months change
    #   Not used, but could be 
    stock.data$mchng <- as.logical(c(0, diff(stock.data$month)))
    
    # we need dummy data for Sunday / Saturday to be included.
    #  These added rows will not be plotted due to their NA values
    dummy <- as.data.frame(stock.data[1:2, ])
    dummy[, -which(names(dummy) %in% c("wday", "year"))] <- NA
    dummy[, "wday"] <- weekdays(2:3, FALSE)
    dummy[, "mchng"] <- TRUE
    rbind(dummy, stock.data) -> stock.data
    
    # convert the continuous var to a categorical var 
    stock.data$Adj.Disc <- cut(stock.data$Adj.Close, b = 6, labels = F)
    
    # vals is the greyscale tones used for the outer monthly borders
    vals <- gray(c(.2, .5))
    
    # PLOT
      # Expected warning due to dummy variable with NA's: 
      # Warning message:
      # Removed 2 rows containing missing values (geom_point). 
    ggplot(stock.data) + 
      aes(week, wday, fill=as.factor(Adj.Disc), 
          shape=as.factor(Adj.Disc), color=as.factor(month %% 2)) + 
      geom_tile(linetype=1, size=1.8) + 
      geom_tile(linetype=6, size=0.4, color="white") + 
      scale_color_manual(values=vals) +
      geom_point(aes(alpha=0.2), color="black") + 
      scale_fill_grey(start=0, end=0.9) +  scale_shape_manual(values=c(2, 3, 4, 12, 14, 8)) + 
      theme(legend.position="none")  +  labs(y="Day of the Week") +  facet_wrap(~ year, ncol = 1)
    

    【讨论】:

    • 谢谢!非常有趣,我喜欢 ggplot2 解决方案。我无法重现您的代码,但似乎缺少一些名为 vals 的元素。
    • 感谢@EricFail。 vals 只是要使用的灰度值。重新编辑。
    猜你喜欢
    • 2013-07-01
    • 1970-01-01
    • 2017-05-20
    • 2015-03-02
    • 2011-09-08
    • 2023-03-23
    • 1970-01-01
    • 2020-05-22
    • 1970-01-01
    相关资源
    最近更新 更多