a b/R/runKappa.R
1
#' @name runKappa
2
#' @title Run consistency evaluation using Kappa statistic
3
#' @description Calculate Kappa statistic to measure the consistency between two appraisements
4
#' @param subt1 A numeric vector to indicate the first appraisement. Order should be exactly the same with subt2 for each sample.
5
#' @param subt2 A numeric vector to indicate the second appraisement. Order should be exactly the same with subt1 for each sample.
6
#' @param subt1.lab A string value to indicate the label of the first subtype.
7
#' @param subt2.lab A string value to indicate the label of the second subtype.
8
#' @param fig.path A string value to indicate the output path for storing the consistency heatmap.
9
#' @param fig.name A string value to indicate the name of the consistency heatmap.
10
#' @param width A numeric value to indicate the width of output figure.
11
#' @param height A numeric value to indicate the height of output figure.
12
#' @details This function evaluates the consistency between two appraisements that targets to the same cohort.
13
#' For example, the NTP-predicted subtype amd PAM-predicted subtype of external cohort, or the current subtype and predicted subtype of discovery cohort.
14
#' Therefore, the arguments `subt1` and `subt2` can be the `clust` column of `clust.res` derived from `getMOIC()` with one specified algorithm
15
#' or `get\%algorithm_name\%` or `getConsensusMOIC()` with a list of multiple algorithms or `runNTP()` or `runPAM()`.
16
#' However, subtypes identified from different algorithm (i.e., `get\%algorithm_name1\%` and `get\%algorithm_name2\%`) can not be evaluated
17
#' because the subtype 1 identified from the first algorithm may not be the same subtype 1 from the second algorithm.
18
#' @return A figure of consistency heatmap (.pdf).
19
#' @export
20
#' @importFrom grDevices dev.copy2pdf
21
#' @examples # There is no example and please refer to vignette.
22
runKappa <- function(subt1     = NULL,
23
                     subt2     = NULL,
24
                     subt1.lab = NULL,
25
                     subt2.lab = NULL,
26
                     fig.path  = getwd(),
27
                     fig.name  = "constheatmap",
28
                     width     = 5,
29
                     height    = 5) {
30
31
  subt1 <- as.vector(as.character(subt1))
32
  subt2 <- as.vector(as.character(subt2))
33
34
  # check sample
35
  if(length(subt1) != length(subt2)) {
36
    stop("subtypes identified from different cohorts.")
37
  }
38
39
  # check subtype
40
  if(!identical(sort(unique(subt1)),sort(unique(subt2)))) {
41
    stop("subtypes fail to matched from two appraisements.")
42
  }
43
44
  # check argument
45
  if(is.null(subt1.lab) | is.null(subt2.lab)) {
46
    stop("label for subtype1 and subtype2 must be both indicated.")
47
  }
48
49
  # calculate consistency
50
  comb.subt <- data.frame(subt1 = paste0("CS", subt1),
51
                          subt2 = paste0("CS", subt2),
52
                          stringsAsFactors = F)
53
54
  tab_classify <- as.data.frame.array(table(comb.subt$subt1,comb.subt$subt2))
55
56
  # n.moic <- length(unique(moic.res$clust.res$clust))
57
  # if(n.moic < 5) {
58
  #   p.fisher <- fisher.test(tab_classify, workspace = 1e9)$p.value
59
  # } else {
60
  #   message("--using simulated p value in fisher's exact test.")
61
  #   p.fisher <- fisher.test(tab_classify, simulate.p.value = T)$p.value
62
  # }
63
64
  # calculate kappa statistic
65
  x <- table(comb.subt$subt1,comb.subt$subt2)
66
  nr <- nrow(x); nc <- ncol(x); N <- sum(x)
67
  Po <- sum(diag(x))/N; Pe <- sum(rowSums(x) * colSums(x)/N)/N
68
  kappa <- (Po - Pe)/(1 - Pe)
69
  seK0 <- sqrt(Pe/(N * (1 - Pe)))
70
  p.v <- 1 - pnorm(kappa/seK0)
71
  p.lab <- ifelse(p.v < 0.001, "P < 0.001", paste0("P = ", format(round(p.v,3), nsmall = 3)))
72
73
  # generate consistency table
74
  blue   <- "#204F8D"
75
  lblue  <- "#498EB9"
76
  dwhite <- "#B6D1E8"
77
  white  <- "#E6EAF7"
78
79
  par(bty="n", mgp = c(2,0.5,0), mar = c(4.1,4.1,4.1,2.1),tcl=-.25, font.main=3)
80
  par(xpd=NA)
81
  plot(c(0,ncol(tab_classify)),c(0,nrow(tab_classify)),
82
       col = "white",
83
       xlab = "",xaxt = "n",
84
       ylab = "",yaxt = "n")
85
  title(paste0("Consistency between ",subt1.lab," and ",subt2.lab,"\nKappa = ", format(round(kappa,3), nsmall = 3),
86
               "\n", p.lab),
87
        adj = 0, line = 0)
88
89
  # add y-axis
90
  axis(2, at = 0.5:(nrow(tab_classify)-0.5), labels = FALSE)
91
  text(y = 0.5:(nrow(tab_classify)-0.5),
92
       par("usr")[1],
93
       labels = rownames(tab_classify)[nrow(tab_classify):1],
94
       srt = 0, pos = 2, xpd = TRUE)
95
  mtext(paste0("Subtypes derived from ", subt1.lab), side = 2, line = 3)
96
97
  # add x-axis
98
  axis(1, at = 0.5:(ncol(tab_classify)-0.5), labels = FALSE)
99
  text(x = 0.5:(ncol(tab_classify)-0.5),
100
       par("usr")[1] - 0.2,
101
       labels = colnames(tab_classify),
102
       srt = 45, pos = 1, xpd = TRUE)
103
  mtext(paste0("Subtypes derived from ", subt2.lab), side = 1, line = 3)
104
105
  # generate colors
106
  input_matrix <- as.matrix(tab_classify)
107
  mat.max = max(input_matrix)
108
  unq.value <- unique(sort(as.vector(input_matrix)))
109
  rbPal <- colorRampPalette(c(white,dwhite,lblue,blue))
110
  col.vec <- rbPal(max(unq.value) + 1)
111
  col.mat <- matrix(NA,byrow = T,ncol = ncol(input_matrix),nrow = nrow(input_matrix))
112
113
  # fill matrix
114
  for (i in 1:nrow(col.mat)) {
115
    for (j in 1:ncol(col.mat)) {
116
      col.mat[i,j] <- col.vec[input_matrix[i,j] + 1]
117
    }
118
  }
119
120
  # generate heatmap
121
  x_size <- ncol(input_matrix)
122
  y_size <- nrow(input_matrix)
123
124
  my_xleft = rep(c(0:(x_size-1)),each = x_size)
125
  my_xright = my_xleft + 1
126
  my_ybottom = rep(c((y_size-1):0),y_size)
127
  my_ytop = my_ybottom + 1
128
  rect(xleft = my_xleft,
129
       ybottom = my_ybottom,
130
       xright = my_xright,
131
       ytop = my_ytop,
132
       col=col.mat,
133
       border = F)
134
135
  # fill count
136
  text(my_xleft + 0.5,my_ybottom + 0.5,input_matrix, cex = 1.3)
137
138
  # output to pdf
139
  outFig <- paste0(fig.name,".pdf")
140
  invisible(dev.copy2pdf(file = file.path(fig.path, outFig), width = width, height = height))
141
}