R/atck-cdf.R

Defines functions attck_cdf_tactic

Documented in attck_cdf_tactic

#' Product an ATT&CK Cumulative Distribution Function by Tactic
#'
#' @param xdf a data frame with `tactic`, `technique` and `value` columns.
#'        If no `value` column exists, then the function will assume you
#'        have passed in individual events and will perform a "count"
#'        summarization before generating the heatmap.
#' @param input,output,matrix if both are not `NULL` then they should be
#'        what [fct_tactic()] takes as parameters. Otherwise, the function
#'        will assume that the `tactic` column is already an ordered factor.
#' @param ... passed on to [ggplot2::geom_label()]
#' @export
attck_cdf_tactic <- function(xdf, input = NULL, output = NULL, matrix = NULL,  ...) {

  cn <- colnames(xdf)
  if (!all(c("tactic", "technique") %in% cn)) {
    stop("'xdf' needs both 'tactic' and 'technique' columns.", call.=FALSE)
  }

  if (!("value" %in% cn)) {
    xdf <- dplyr::count(xdf, tactic, technique, name = "value")
  }

  if (is.null(input) && is.null(output)) {
    if (!is.factor(xdf$tactic)) {
      stop(
        "No 'input'/'output' transformation specified but 'tactic' is not a factor.",
        call.=FALSE
      )
    }
  } else {
    if (sum(c(!is.null(input), !is.null(output), !is.null(matrix))) != 3) {
      stop("Must specify 'input', 'output', and 'matrix' if any one of them is not NULL", call.=FALSE)
    }
    xdf$tactic <- fct_tactic(xdf$tactic, input = input, output = output, matrix = matrix)
  }

  xdf <- dplyr::count(xdf, tactic, wt=value)
  xdf <- dplyr::arrange(xdf, tactic)
  xdf <- dplyr::mutate(xdf, pct = n/sum(n))
  xdf <- dplyr::mutate(xdf, cpct = cumsum(pct))

  gg <- ggplot(xdf, aes(tactic, cpct, group=1))
  gg <- gg + geom_path()
  gg <- gg + geom_label(
    aes(
      label = sprintf("%s\n%s\n%s", scales::comma(n), scales::percent(pct), scales::percent(cpct)),
    ), lineheight = 0.875, ...
  )
  gg <- gg + scale_x_discrete(
    expand = c(0, 0.5), position = "top",
    breaks = levels(xdf$tactic), limits = levels(xdf$tactic)
  )
  gg <- gg + scale_y_continuous(
    expand = c(0, 0.05), limits = c(-0.05, 1.05), label = scales::percent
  )
  gg <- gg + labs(x = NULL, y = NULL)

  gg

}
hrbrmstr/attckr documentation built on Aug. 13, 2020, 11:49 a.m.