R/plot_fnet.R

Defines functions read_by plot_fnet

Documented in plot_fnet

## plot_fnet.R | riskyr
## 2022 08 09
## Plot frequency net from Binder et al. (2020):
## See doi: 10.3389/fpsyg.2020.00750
## -----------------------------------------------

# This function is based on plot_prism.R.

## plot_fnet: Documentation ----------

#' Plot frequency net diagram of frequencies and probabilities.
#'
#' \code{plot_fnet} plots a frequency net of
#' from a sufficient and valid set of 3 essential probabilities
#' (\code{\link{prev}}, and
#' \code{\link{sens}} or its complement \code{\link{mirt}}, and
#' \code{\link{spec}} or its complement \code{\link{fart}})
#' or existing frequency information \code{\link{freq}}
#' and a population size of \code{\link{N}} individuals.
#'
#' \code{plot_fnet} shows frequencies as nodes and probabilities as links
#' (like trees and double trees generated by \code{\link{plot_prism}}),
#' but combines elements from 2x2 tables (see \code{\link{plot_tab}})
#' and tree diagrams.
#'
#' Similar to other 2D-visualizations (e.g., ,
#' \code{\link{plot_area}}, \code{\link{plot_prism}} and
#' \code{\link{plot_tab}}), the
#' frequency net selects and combines two perspectives
#' (e.g., \code{by = "cddc"}).
#' However, the frequency net is similar to a 2x2 table insofar as
#' its perspectives (shown by arranging marginal frequencies in a
#' vertical vs. horizontal fashion) do not suggest an order
#' or dependency (in contrast to trees or mosaic plots).
#' Additionally, the frequency net allows showing
#' 3 kinds of (marginal, conditional, and joint) probabilities.
#'
#' See the article by Binder K, Krauss S and Wiesner P (2020).
#' A new visualization for probabilistic situations containing two binary events:
#' The frequency net. Frontiers in Psychology, 11, 750. doi: 10.3389/fpsyg.2020.00750
#' for analysis and details.
#'
#' @param prev  The condition's prevalence \code{\link{prev}}
#' (i.e., the probability of condition being \code{TRUE}).
#'
#' @param sens  The decision's sensitivity \code{\link{sens}}
#' (i.e., the conditional probability of a positive decision
#' provided that the condition is \code{TRUE}).
#' \code{sens} is optional when its complement \code{mirt} is provided.
#'
#' @param mirt  The decision's miss rate \code{\link{mirt}}
#' (i.e., the conditional probability of a negative decision
#' provided that the condition is \code{TRUE}).
#' \code{mirt} is optional when its complement \code{sens} is provided.
#'
#' @param spec  The decision's specificity value \code{\link{spec}}
#' (i.e., the conditional probability
#' of a negative decision provided that the condition is \code{FALSE}).
#' \code{spec} is optional when its complement \code{fart} is provided.
#'
#' @param fart  The decision's false alarm rate \code{\link{fart}}
#' (i.e., the conditional probability
#' of a positive decision provided that the condition is \code{FALSE}).
#' \code{fart} is optional when its complement \code{spec} is provided.
#'
#' @param N  The number of individuals in the population.
#' A suitable value of \code{\link{N}} is computed, if not provided.
#' Note that a population size \code{\link{N}} is not needed
#' for computing current probability information \code{\link{prob}},
#' but is needed for computing frequency information
#' \code{\link{freq}} from current probabilities \code{\link{prob}}.
#'
#' @param by  A character code specifying 1 or 2 perspective(s)
#' that split(s) the population into 2 subsets.
#' Specifying 1 perspective plots a frequency tree (single tree)
#' with 3 options:
#'   \enumerate{
#'   \item \code{"cd"}: by condition only;
#'   \item \code{"dc"}: by decision only;
#'   \item \code{"ac"}: by accuracy only.
#'   }
#' Specifying 2 perspectives plots a frequency prism (double tree)
#' with 6 options:
#'   \enumerate{
#'   \item \code{"cddc"}: by condition (cd) and by decision (dc) (default);
#'   \item \code{"cdac"}: by condition (cd) and by accuracy (ac);
#'   \item \code{"dccd"}: by decision (dc) and by condition (cd);
#'   \item \code{"dcac"}: by decision (dc) and by accuracy (ac);
#'   \item \code{"accd"}: by accuracy (ac) and by condition (cd);
#'   \item \code{"acdc"}: by accuracy (ac) and by decision (dc).
#'   }
#'
#' @param area  A character code specifying the shapes of the frequency boxes,
#' with 2 options:
#'   \enumerate{
#'   \item \code{"no"}: rectangular frequency boxes, not scaled (default);
#'   \item \code{"sq"}: frequency boxes are squares (scaled relative to N).
#'   }
#'
#' @param scale  Scale probabilities and corresponding area dimensions either by
#' exact probability or by (rounded or non-rounded) frequency, with 2 options:
#'   \enumerate{
#'   \item \code{"p"}: scale main area dimensions by exact probability (default);
#'   \item \code{"f"}: re-compute probabilities from (rounded or non-rounded) frequencies
#'   and scale main area dimensions by their frequency.
#'   }
#'  Note: \code{scale} setting matters for the display of probability values and for
#'  area plots with small population sizes \code{\link{N}} when \code{round = TRUE}.
#'
#' @param round  Boolean option specifying whether computed frequencies
#' are rounded to integers. Default: \code{round = TRUE}.
#'
#' @param sample  Boolean value that determines whether frequency values
#' are sampled from \code{N}, given the probability values of
#' \code{prev}, \code{sens}, and \code{spec}.
#' Default: \code{sample = FALSE}.
#'
#' @param f_lbl  Type of label for showing frequency values in 4 main areas,
#' with 6 options:
#'   \enumerate{
#'   \item \code{"def"}: abbreviated names and frequency values;
#'   \item \code{"abb"}: abbreviated frequency names only (as specified in code);
#'   \item \code{"nam"}: names only (as specified in \code{lbl_txt = txt});
#'   \item \code{"num"}: numeric frequency values only (default);
#'   \item \code{"namnum"}: names (as specified in \code{lbl_txt = txt}) and numeric values;
#'   \item \code{"no"}: no frequency labels (same for \code{f_lbl = NA} or \code{NULL}).
#'   }
#'
#' @param f_lbl_sep  Label separator for main frequencies
#' (used for \code{f_lbl = "def" OR "namnum"}).
#' Use \code{f_lbl_sep = ":\n"} to add a line break between name and numeric value.
#' Default: \code{f_lbl_sep = NA} (set to \code{" = "} or \code{":\n"} based on \code{f_lbl}).
#'
#' @param f_lwd  Line width of areas.
#' Default: \code{f_lwd = 0}.
#'
#' @param p_lwd  Line width of probability links.
#' Default: \code{p_lwd = 1}, but consider increasing when setting \code{p_scale = TRUE}.
#'
#' @param p_scale  Boolean option for scaling current widths of probability links
#' (as set by \code{p_lwd}) by the current probability values.
#' Default: \code{p_scale = FALSE}.
#'
#' @param p_lbl  Type of label for showing probability links and values,
#' with many options:
#'   \enumerate{
#'   \item \code{"abb"}: show links and abbreviated probability names;
#'   \item \code{"def"}: show links and abbreviated probability names and values;
#'   \item \code{"min"}: show links and minimum (prominent) probability names;
#'   \item \code{"mix"}: show links and prominent probability names and all values (default);
#'   \item \code{"nam"}: show links and probability names (as specified in code);
#'   \item \code{"num"}: show links and numeric probability values;
#'   \item \code{"namnum"}: show links with names and numeric probability values;
#'   \item \code{"no"}: show links with no labels (same for \code{p_lbl = NA} or \code{NULL}).
#'   }
#'
#' @param arr_c  Arrow code for symbols at ends of probability links
#' (as a numeric value \code{-3 <= arr_c <= +6}),
#' with the following options:
#'   \itemize{
#'   \item \code{-1} to \code{-3}: points at one/other/both end/s;
#'   \item \code{0}: no symbols;
#'   \item \code{+1} to \code{+3}: V-arrow at one/other/both end/s;
#'   \item \code{+4} to \code{+6}: T-arrow at one/other/both end/s.
#' }
#' Default: \code{arr_c = NA}, but adjusted by \code{area}.
#'
#' @param joint_p  Boolean options for showing links to joint probabilities
#' (i.e., diagonals from N in center to joint frequencies in 4 corners).
#' Default: \code{joint_p = TRUE}.
#'
#' @param lbl_txt  Default label set for text elements.
#' Default: \code{lbl_txt = \link{txt}}.
#'
#' @param main Text label for main plot title.
#' Default: \code{main = txt$scen_lbl}.
#'
#' @param sub Text label for plot subtitle (on 2nd line).
#' Default: \code{sub = "type"} shows information on current plot type.
#'
#' @param title_lbl \strong{Deprecated} text label for current plot title.
#' Replaced by \code{main}.
#'
#' @param cex_lbl  Scaling factor for text labels (frequencies and headers).
#' Default: \code{cex_lbl = .90}.
#'
#' @param cex_p_lbl  Scaling factor for text labels (probabilities).
#' Default: \code{cex_p_lbl = cex_lbl - .05}.
#'
#' @param col_pal  Color palette.
#' Default: \code{col_pal = \link{pal}}.
#'
#' @param mar_notes  Boolean option for showing margin notes.
#' Default: \code{mar_notes = FALSE}.
#'
#' @param ...  Other (graphical) parameters.
#'
#' @return Nothing (NULL).
#'
#' @examples
#' # (1) Basics: ----
#' # A. Using global prob and freq values:
#' plot_fnet()  # default frequency net, same as:
#' # plot_fnet(by = "cddc", area = "no", scale = "p",
#' #            f_lbl = "num", f_lwd = 0, cex_lbl = .90,
#' #            p_lbl = "mix", arr_c = -2, cex_p_lbl = NA)
#'
#' # B. Providing values:
#' plot_fnet(N = 10000, prev = .02, sens = .8, spec = .9)  # Binder et al. (2020, Fig. 3)
#'
#' # C. Rounding and sampling:
#' plot_fnet(N = 100, prev = 1/3, sens = 2/3, spec = 6/7, area = "sq", round = FALSE)
#' plot_fnet(N = 100, prev = 1/3, sens = 2/3, spec = 6/7, area = "sq", sample = TRUE, scale = "freq")
#'
#' # Variants:
#' plot_fnet(N = 10000, prev = .02, sens = .8, spec = .9, by = "cdac")
#' plot_fnet(N = 10000, prev = .02, sens = .8, spec = .9, by = "dccd")
#' # plot_fnet(N = 10000, prev = .02, sens = .8, spec = .9, by = "dcac")
#' # plot_fnet(N = 10000, prev = .02, sens = .8, spec = .9, by = "accd")
#' # plot_fnet(N = 10000, prev = .02, sens = .8, spec = .9, by = "acdc")
#'
#' # Trees (only 1 dimension):
#' plot_fnet(N = 10000, prev = .02, sens = .8, spec = .9, by = "cd")
#' # plot_fnet(N = 10000, prev = .02, sens = .8, spec = .9, by = "dc")
#' # plot_fnet(N = 10000, prev = .02, sens = .8, spec = .9, by = "ac")
#'
#' # Area and margin notes:
#' plot_fnet(N = 10, prev = 1/4, sens = 3/5, spec = 2/5, area = "sq", mar_notes = TRUE)
#'
#'
#' # (2) Use case (highlight horizontal vs. vertical perspectives: ----
#' # Define scenario:
#' mammo <- riskyr(N = 10000, prev = .01, sens = .80, fart = .096,
#'                 scen_lbl = "Mammography screening", N_lbl = "Women",
#'                 cond_lbl = "Breast cancer", dec_lbl = "Test result",
#'                 cond_true_lbl = "Cancer (C+)", cond_false_lbl = "no Cancer (C-)",
#'                 dec_pos_lbl = "positive (T+)", dec_neg_lbl = "negative (T-)",
#'                 hi_lbl = "C+ and T+", mi_lbl = "C+ and T-",
#'                 fa_lbl = "C- and T+", cr_lbl = "C- and T-")
#' # Colors:
#' my_non <- "grey95"
#' my_red <- "orange1"
#' my_blu <- "skyblue1"
#'
#' # A. Emphasize condition perspective (rows):
#' my_col_1 <- init_pal(N_col = my_non,
#'                      cond_true_col = my_blu, cond_false_col = my_red,
#'                      dec_pos_col = my_non, dec_neg_col = my_non,
#'                      hi_col = my_blu, mi_col = my_blu,
#'                      fa_col = my_red, cr_col = my_red)
#' plot(mammo, type = "fnet", col_pal = my_col_1,
#'      f_lbl = "namnum", f_lwd = 2, p_lbl = "no", arr_c = 0)
#'
#' # B. Emphasize decision perspective (columns):
#' my_col_2 <- init_pal(N_col = my_non,
#'                      cond_true_col = my_non, cond_false_col = my_non,
#'                      dec_pos_col = my_red, dec_neg_col = my_blu,
#'                      hi_col = my_red, mi_col = my_blu,
#'                      fa_col = my_red, cr_col = my_blu)
#' plot(mammo, type = "fnet", col_pal = my_col_2,
#'      f_lbl = "namnum", f_lwd = 2, p_lbl = "no", arr_c = 0)
#'
#'
#' # (3) Custom color and text settings: ----
#' plot_fnet(col_pal = pal_bw, f_lwd = .5, p_lwd = .5, lty = 2, # custom fbox color, prob links,
#'           font = 3, cex_p_lbl = .75)                         # and text labels
#'
#' plot_fnet(N = 7, prev = 1/2, sens = 3/5, spec = 4/5, round = FALSE,
#'           by = "cdac", lbl_txt = txt_org, f_lbl = "namnum", f_lbl_sep = ":\n",
#'           f_lwd = 1, col_pal = pal_rgb)  # custom colors
#'
#' # plot_fnet(N = 5, prev = 1/2, sens = .8, spec = .5, scale = "p",   # Note scale!
#' #           by = "cddc", area = "hr", col_pal = pal_bw, f_lwd = 1)  # custom colors
#'
#' plot_fnet(N = 3, prev = .50, sens = .50, spec = .50, scale = "p",              # Note scale!
#'           area = "sq", lbl_txt = txt_org, f_lbl = "namnum", f_lbl_sep = ":\n", # custom text
#'           col_pal = pal_kn, f_lwd = .5)                                        # custom colors
#'
#' # (4) Other options: ----
#' plot_fnet(N = 4, prev = .2, sens = .7, spec = .8,
#'           area = "sq", scale = "p")  # areas scaled by prob (matters for small N)
#' # plot_fnet(N = 4, prev = .2, sens = .7, spec = .8,
#' #           area = "sq", scale = "f")  # areas scaled by (rounded or non-rounded) freq
#'
#' ## Frequency boxes (f_lbl):
#' # plot_fnet(f_lbl = NA)       # no freq labels
#' # plot_fnet(f_lbl = "abb")    # abbreviated freq names (variable names)
#' plot_fnet(f_lbl = "nam")      # only freq names
#' plot_fnet(f_lbl = "num")      # only numeric freq values (default)
#' # plot_fnet(f_lbl = "namnum") # names and numeric freq values
#' plot_fnet(f_lbl = "namnum", cex_lbl = .75)  # smaller freq labels
#' # plot_fnet(f_lbl = "def")    # informative default: short name and numeric value (abb = num)
#'
#' # f_lwd:
#' # plot_fnet(f_lwd =  1)  # basic lines
#' # plot_fnet(f_lwd =  0)  # no lines (default), set to tiny_lwd = .001, lty = 0 (same if NA/NULL)
#' # plot_fnet(f_lwd = .5)  # thinner lines
#' plot_fnet(f_lwd =  3)    # thicker lines
#'
#' ## Probability links (p_lbl, p_lwd, p_scale):
#' # plot_fnet(p_lbl = NA)       # no prob labels (NA/NULL/"none")
#' plot_fnet(p_lbl = "mix")      # abbreviated names with numeric values (abb = num)
#' # plot_fnet(p_lbl = "min")    # minimal names (of key probabilities)
#' # plot_fnet(p_lbl = "nam")    # only prob names
#' plot_fnet(p_lbl = "num")      # only numeric prob values
#' # plot_fnet(p_lbl = "namnum") # names and numeric prob values
#'
#' plot_fnet(p_lwd = 6, p_scale = TRUE)
#' plot_fnet(area = "sq", f_lbl = "num", p_lbl = NA, col_pal = pal_bw, p_lwd = 6, p_scale = TRUE)
#'
#' # arr_c:
#' # plot_fnet(arr_c =  0)  # acc_c = 0: no arrows
#' # plot_fnet(arr_c = -3)  # arr_c = -1 to -3: points at both ends
#' # plot_fnet(arr_c = -2)  # point at far end
#' plot_fnet(arr_c = +2)    # crr_c = 1-3: V-shape arrows at far end
#'
#' plot_fnet(by = "cd", joint_p = FALSE)      # tree without joint probability links
#' # plot_fnet(by = "cddc", joint_p = FALSE)  # fnet ...
#'
#' ## Plain plot versions:
#' plot_fnet(area = "no", f_lbl = "def", p_lbl = "num", col_pal = pal_mod, f_lwd = 1,
#'           main = "", mar_notes = FALSE)  # remove titles and margin notes
#' plot_fnet(area = "no", f_lbl = "nam", p_lbl = "min", col_pal = pal_rgb)
#'
#' plot_fnet(area = "sq", f_lbl = "nam", p_lbl = "num", col_pal = pal_rgb)
#' # plot_fnet(area = "sq", f_lbl = "def", f_lbl_sep = ":\n", p_lbl = NA, f_lwd = 1, col_pal = pal_kn)
#'
#' ## Suggested combinations:
#' # plot_fnet(f_lbl = "nam", p_lbl = "mix")  # basic plot
#' plot_fnet(f_lbl = "namnum", p_lbl = "num", cex_lbl = .80, cex_p_lbl = .75)
#' # plot_fnet(area = "no", f_lbl = "def", p_lbl = "abb",           # def/abb labels
#' #           f_lwd = .8, p_lwd = .8, lty = 2, col_pal = pal_bwp)  # black-&-white
#'
#' # plot_fnet(area = "sq", f_lbl = "nam", p_lbl = "abb", lbl_txt = txt_TF, col_pal = pal_bw)
#' plot_fnet(area = "sq", f_lbl = "num", p_lbl = "num", f_lwd = 1, col_pal = pal_rgb)
#' plot_fnet(area = "sq", f_lbl = "nam", p_lbl = "num", f_lwd = .5, col_pal = pal_rgb)
#'
#' @source
#' Binder, K., Krauss, S., and Wiesner, P. (2020).
#' A new visualization for probabilistic situations containing two binary events: The frequency net.
#' Frontiers in Psychology, 11, 750. doi: 10.3389/fpsyg.2020.00750
#'
#' @importFrom graphics par
#' @importFrom graphics plot
#' @importFrom graphics box
#' @importFrom graphics axis
#' @importFrom graphics grid
#' @importFrom graphics abline
#' @importFrom graphics rect
#' @importFrom graphics arrows
#' @importFrom graphics points
#' @importFrom graphics text
#' @importFrom graphics title
#' @importFrom graphics mtext
#' @importFrom graphics legend
#' @importFrom graphics lines
#' @importFrom grDevices dev.size
#'
#' @family visualization functions
#'
#' @seealso
#' \code{\link{plot_prism}} for plotting prism plot (double tree);
#' \code{\link{plot_area}} for plotting mosaic plot (scaling area dimensions);
#' \code{\link{plot_bar}} for plotting frequencies as vertical bars;
#' \code{\link{plot_tab}} for plotting table (without scaling area dimensions);
#' \code{\link{pal}} contains current color settings;
#' \code{\link{txt}} contains current text settings.
#'
#' @export

## plot_fnet: Definition ----------

plot_fnet <- function(prev = num$prev,    # probabilities
                      sens = num$sens, mirt = NA,
                      spec = num$spec, fart = NA,
                      N = num$N,          # population size N

                      # Plot options:
                      by = "cddc",        # 2 perspectives (rows 2 and 4): each by = "cd"/"dc"/"ac"  (default: "cddc")
                      area = "no",        # "no" (default = NA, NULL, "fix") vs: "sq"
                      scale = "p",        # "f" vs. "p" (default)
                      round = TRUE,       # round freq values to integers? When not rounded: n_digits = 2 (currently fixed).
                      sample = FALSE,     # sample freq values from probabilities?

                      # Freq boxes:
                      f_lbl = "num",      # freq labels: "def", "nam"/"num"/"namnum", "abb", or NA/NULL/"no" to hide freq labels.
                      f_lbl_sep = NA,     # freq label separator (default: " = ", use ":\n" to add an extra line break)
                      f_lwd = 0,          # lwd of freq boxes: 0 (set to tiny_lwd, lty = 0) vs. 1 (numeric), or NULL/NA (set to 0).
                      # f_lty = 0,        # lty of freq boxes: 1 ("solid") vs. 0 ("blank"), etc. (currently not used)

                      # Prob links:
                      p_lwd = 1,          # lwd of prob links: Default p_lwd = 1 (and used as p_lwd_max when p_scale = TRUE).
                      p_scale = FALSE,    # scale widths of probability links (set by p_lwd) by current p_val?
                      p_lbl = "mix",      # prob labels: "def", "nam"/"num"/"namnum", "abb"/"mix"/"min", or NA/NULL/"no" to hide prob labels.
                      # p_lty,            # lty of prob links: set to default = 1 (currently not used)
                      arr_c = NA,         # arrow code (-3 to +6). Set to defaults of -2 or 0 (by area, below).
                      joint_p = TRUE,     # show diagonal links from N (center) to joint probabilities (in 4 corners)?

                      # Text and color:
                      lbl_txt = txt,      # labels and text elements
                      main = txt$scen_lbl,  # main title
                      sub = "type",         # subtitle ("type" shows generic plot type info)
                      title_lbl = NULL,     # DEPRECATED plot title, replaced by main
                      cex_lbl = .90,      # size of freq & text labels.
                      cex_p_lbl = NA,     # size of prob labels (set to cex_lbl - .05 by default).
                      col_pal = pal,      # color palette

                      # Generic options:
                      mar_notes = FALSE,  # show margin notes?
                      ...                 # other (graphical) parameters (passed to plot_link and plot_ftype_label)
) {

  ## (0) Compute new freq and prob objects (based on probability inputs): ----------

  ## (A) If a valid set of probabilities was provided:
  if (is_valid_prob_set(prev = prev, sens = sens, mirt = mirt, spec = spec, fart = fart, tol = .01)) {

    # (a) Compute the complete quintet of probabilities:
    prob_quintet <- comp_complete_prob_set(prev = prev, sens = sens, mirt = mirt, spec = spec, fart = fart)
    sens <- prob_quintet[2]  # gets sens (if not provided)
    mirt <- prob_quintet[3]  # gets mirt (if not provided)
    spec <- prob_quintet[4]  # gets spec (if not provided)
    fart <- prob_quintet[5]  # gets fart (if not provided)

    # (b) Compute LOCAL freq and prob based on current parameters (N and probabilities):
    freq <- comp_freq(prev = prev, sens = sens, spec = spec, N = N,
                      round = round, sample = sample)              # key freq
    prob <- comp_prob_prob(prev = prev, sens = sens, spec = spec)  # key prob

    # message("Computed local freq and prob to plot prism.")

    # (c) Compute cur.popu from computed frequencies (not needed):
    # cur.popu <- comp_popu(hi = freq$hi, mi = freq$mi, fa = freq$fa, cr = freq$cr)  # compute cur.popu (from 4 essential frequencies)
    # message("Generated new population (cur.popu) to plot.")

  } else {  # (B) NO valid set of probabilities was provided:

    message("No valid set of probabilities provided: Using global freq & prob to plot prism.")

  } # if (is_valid_prob_set)


  ## (1) Prepare parameters: ----------

  opar <- par(no.readonly = TRUE)  # all par settings that can be changed.
  on.exit(par(opar))  # par(opar)  # restore original settings

  ## (2) Key options and parameters: ----------

  ## 1. by Perspective: ----

  # by:
  by_vec <- read_by(by = by) # helper function returns vector with 3 elements:
  by_top <- by_vec[1]
  by_bot <- by_vec[2]
  by     <- by_vec[3]  # updates original by to (possibly changed) by_now


  ## 2. Freq boxes: ----

  # area:
  if (is.null(area) || is.na(area) || tolower(area) == "none" || tolower(area) == "fix") { area <- "no" }
  if ( !is.null(area) && !is.na(area) ) { area <- tolower(area) }  # area in lowercase
  if ( area == "hr" || area == "vr" || area == "horizontal" || area == "hrect" || area == "hbar" || area == "h" || area == "bar" || area == "bars" ) { area <- "no" }
  if ( area == "square" || area == "squares" ) { area <- "sq" }

  # scale:
  if ( is.null(scale) || is.na(scale)  ) { scale <- "f" }  # default
  if ( !is.null(scale) && !is.na(scale) ) { scale <- tolower(scale) }  # scale in lowercase
  if (scale == "freq" || scale == "f") { scale <- "f" }
  if (scale == "prob" || scale == "p") { scale <- "p" }

  # use scale input:
  if (scale == "f") {

    ## (A) Use scale for area dimensions:
    ## Recompute specific probabilities from current (4 essential) freq
    ## which may be rounded or not rounded:
    prob_from_freq <- comp_prob_freq(hi = freq$hi, mi = freq$mi, fa = freq$fa, cr = freq$cr)

    ## Adjusting width of boxes in comp_lx_fbox (by scale argument) below!

    ## (B) Use scale for area dimensions AND prob values:
    ## A more radical type of scale (i.e., re-defining prob based on current freq)
    ## also changes the prob values displayed in links and margins:
    prob <- prob_from_freq  # use re-computed values for all prob values!

  }

  # f_lwd & lty:
  tiny_lwd <- .001   # initialize tiny, invisible width

  if ( is.null(f_lwd) || is.na(f_lwd) || f_lwd <= 0 ) {

    f_lwd <- tiny_lwd  # to avoid error (for lwd = 0)
    lty <- 0           # "blank" (no lines) [only when f_lty and p_lty are NOT used]

  }

  # f_lbl_sep: Set smart default:
  if ( !is.null(f_lbl) && !is.na(f_lbl) ) {
    if (is.na(f_lbl_sep)) {
      if (f_lbl == "def" || f_lbl == "namnum" || f_lbl == "namval" || f_lbl == "abbnum" || f_lbl == "abbval") {
        f_lbl_sep <- ":\n"  # add an extra line break
      } else {
        f_lbl_sep <- " = "  # use default
      }
    }
  }


  ## 3. Prob links: ----

  # No probability labels: Detect special strings:
  if (!is.null(p_lbl)) {
    if (is.na(p_lbl) ||
        p_lbl == "" || tolower(p_lbl) == "null" | tolower(p_lbl) == "na") {
      p_lbl <- NA  # set to NA or NULL
    }
  }

  # arr_c:
  # Note that arr_c <- NA by default:

  if ( is.null(arr_c) ) { arr_c <- 0 }  # sensible zero

  # sensible default (based on p_scale):
  if (p_scale && is.na(arr_c)) { arr_c <- 0 }  # default for p_scale (unless arr_c was set)

  # sensible defaults (based on area):
  if ( is.na(arr_c) ) {
    if (area == "no") { arr_c <- -2 }  # point at far end
    if (area == "hr") { arr_c <- -2 }  # point at far end
    if (area == "sq") { arr_c <-  0 }  # no arrows
  }


  ## 4. Text labels: ----

  # Default main and subtitle labels:
  if (is.null(main)) { main <- txt$scen_lbl }
  if (is.na(main))   { main <- "" }
  if (is.null(sub) || is.na(sub)) { sub <- "" }

  # Label sizes:
  if ( is.null(cex_lbl) ) { cex_lbl <- .001 }  # sensible zero
  if ( is.na(cex_lbl) ) { cex_lbl <- .90 }  # default size of cex
  if ( cex_lbl == 0 )  { cex_lbl <- .001 }  # other sensible zero

  if ( is.null(cex_p_lbl) ) { cex_p_lbl <- .001 }  # sensible zero
  if ( is.na(cex_p_lbl) ) { cex_p_lbl <- (cex_lbl - .05) }  # default size of cex
  if ( cex_p_lbl == 0 )  { cex_p_lbl <- .001 } # other sensible zero


  ## 5. Colors / color palettes: ----

  # (a) Set plot background color:
  par(bg = col_pal[["bg"]])  # col_pal[["bg"]] / "white" / NA (for transparent background)

  # (b) Detect and handle special cases of color equality (e.g., pal_bwp):
  if ( (par("bg") %in% col_pal[1:11]) && # if bg is equal to ANY fbox color AND
       (f_lwd <= tiny_lwd) ) {           # f_lwd is tiny_lwd (default):
    f_lwd <- 1
    # lty <- 1
  }


  ## 6. Additional parameters (currently fixed): ----

  lty <- 1
  ftype_x <- -5.5  # x-value of ftype labels
  ftype_pos <- 4   # pos of ftype labels (NULL: centered, 2: right justified, or 4: left justified)


  ## (3) Define plot and margin areas: ----------

  ## (A) Define margin areas:

  if (nchar(main) > 0 | nchar(sub) > 0) { n_lines_top <- 2 } else { n_lines_top <- 0 }
  if (mar_notes) { n_lines_bot <- 3 } else { n_lines_bot <- 0 }

  par(mar = c(n_lines_bot, 1, n_lines_top, 1) + 0.1)  # margins; default: par("mar") = 5.1 4.1 4.1 2.1.
  par(oma = c(0, 0, 0, 0) + 0.1)                      # outer margins; default: par("oma") = 0 0 0 0.

  ## Axis label locations:
  par(mgp = c(3, 1, 0)) # default: c(3, 1, 0)

  ## Orientation of the tick mark labels (and corresponding mtext captions below):
  par(las = 0)  # Options: parallel to the axis (0 = default), horizontal (1), perpendicular to the axis (2), vertical (3).


  ## (B) Plot setup:

  # Levels to plot with objects:
  y_levels <- 5
  x_levels <- 9

  x_ctr <- 0  # vertical middle / center
  y_ctr <- 0  # horizontal middle / center

  # Dimensions:
  x_min <- -5
  x_max <- +5

  if ( !is.na(by_bot) ) {
    y_min <- -5
  } else { # is.na(by_bot):
    y_min <- -5  # WAS: -1 (in plot_prism)
  } # if ( !is.na(by_bot) ) etc.
  y_max <- +5

  # Plot empty canvas:
  plot(0:1, 0:1, type = "n",
       xlab = "", ylab = "",
       xlim = c(x_min, x_max), ylim = c(y_min, y_max),
       axes = FALSE)

  ## Plot empty canvas:
  # plot(0, 0, type = "n", bty = "n", xaxt = "n", yaxt = "n",
  #     xlab = "", ylab = "", xlim = c(0, x_max), ylim = c(0, y_max))

  ## Plot with points:
  # plot(rep(0:x_max, y_max + 1), rep(0:y_max, each = x_max + 1),
  #     xlab = "x-axis", ylab = "y-axis")


  ## (C) Mark plot areas:

  ## (a) Mark plot area:
  # col.plot <- "firebrick3"
  # box("plot", col = col.plot)
  # text(x_max/2, y_max/2, "Plot area", col = col.plot, cex = 1, font = 2)  ## plot text

  ## (b) Mark margin area:
  # mar.col <- "forestgreen"
  # box("figure", col = mar.col)
  # mtext("Margin area", side = 3, line = 2, cex = 1, font = 2, col = mar.col)
  # mtext("side 1, line 3, adj 0", side = 1, line = 3, adj = 0.0, cex = cex_lbl, col = mar.col)
  # mtext("side 1, line 3, adj 1", side = 1, line = 3, adj = 1.0, cex = cex_lbl, col = mar.col)
  # mtext("side 3, line 0, adj 0", side = 3, line = 0, adj = 0.0, cex = cex_lbl, col = mar.col)
  # mtext("side 3, line 0, adj 1", side = 3, line = 0, adj = 1.0, cex = cex_lbl, col = mar.col)

  ## (c) Mark outer margin area (oma):
  # oma.col <- "steelblue4"
  # box("outer", col = oma.col)
  # mtext("Outer margin area", side = 1, line = 1, cex = 1, font = 2, col = oma.col, outer = TRUE)
  # mtext("side 1, line 0, adj 0", side = 1, line = 0, adj = 0.0, cex = cex_lbl, col = oma.col, outer = TRUE)
  # mtext("side 1, line 0, adj 1", side = 1, line = 0, adj = 1.0, cex = cex_lbl, col = oma.col, outer = TRUE)

  ## (d) Draw a grid of plot points:
  # points(0, 0, pch = 1, col = grey(.66, .50), cex = 1)  # mark origin

  ## Plot grid of points:
  # grid_x <- rep(seq(x_min, x_max, by = 1), times = length(seq(y_min, y_max, by = 1))) # x/horizontal
  # grid_y <- rep(seq(y_min, y_max, by = 1), each =  length(seq(x_min, x_max, by = 1))) # y/vertical
  # points(grid_x, grid_y, pch = 3, col = grey(.66, .50), cex = 3/4)                    # plot grid points


  ## (4) Define graphical parameters: --------

  ## (A) Aspect ratio of current plot:
  plot_xy <- par("pin")  # use par("pin") OR dev.size("in")
  plot_ratio <- plot_xy[1]/plot_xy[2]  # current aspect ratio
  scale_x <- 1/plot_ratio              # multiplicative correction factor (for x-widths)


  ## (B) Box parameters:

  ##     Box dimensions: ------

  ## Box areas with fixed size:

  ## (a) rectangular box (area == "no", i.e., default):
  # if ( !is.na(by_bot) ) {

  b_h_scale <- 1.15       # optional scaling factor (for larger box heights)
  b_h <- (1 * b_h_scale)  # basic box height

  # gold_ratio  <- 1.618  # a. golden ratio (= approx. 1.6180339887)
  wide_screen <- 16/9     # b. 1.778
  # compromise  <- 1.70   # c. 1.70
  # wider       <- 1.88   # d. 1.88 (wider than wide_screen)

  # b_w <- comp_lx(b_h, mf = gold_ratio, corf = scale_x)  # a. gold_ratio + corrected for aspect ratio
  b_w <- comp_lx(b_h, mf = wide_screen, corf = scale_x)   # b. wide_screen + corrected
  # b_w <- comp_lx(b_h, mf = compromise, corf = scale_x)  # c. compromise + corrected
  # b_w <- comp_lx(b_h, mf = wider, corf = scale_x)       # d. wider + corrected

  # b_w <- comp_lx(b_h, mf = 2, corf = scale_x)   # x. customized width


  # } # else {

  # b_h <- 1
  # two_to_one <- 2.0

  # b_w <- comp_lx(b_h, mf = two_to_one, corf = scale_x)  # a. two_to_one + corrected for aspect ratio
  # b_w <- comp_lx(b_h, mf = 3.0, corf = scale_x)         # x. customized width

  # } # if ( !is.na(by_bot) ) etc.


  ## (b) Square box:
  if (area == "sq") {

    corr_3 <- 1.00

    ## Scale correction factor for showing 3 (single tree) instead of 5 levels (prism, double tree):
    # if ( !is.na(by_bot) ) { corr_3 <- 1.00 } else { corr_3 <- 1.60 } # if ( !is.na(by_bot) ) etc.

    b_w <- comp_lx(b_h, mf = corr_3, corf = scale_x)  # same as b_h + corrected for aspect ratio
  }

  ## (B) Other graphical parameters:

  ## Dimensions:
  # x_range <- x_max - 2  # range in x direction
  # t_w <- x_range + b_w  # total width = range + width of center box


  ## (5) Main fnet diagram: --------

  ## (A) Define and plot objects: ------

  # Row-by-row strategy:
  # For each row (y):
  # - Determine desired perspective (by "xx") of current row.
  # - For each perspective:
  #   - define all boxes of current row (dimensions => x-pos)
  #   - plot all boxes of current row (from largest to smallest)


  ## Population size N: Center (formerly 1st and 5th rows, top/bot: y = +4/-4): ------

  # box 1 dimensions:

  if (area == "sq") {

    # N area as square:
    N_scale <- 3/2  # optional scaling factor (for larger N squares)
    N_l     <- b_h * N_scale
    N_area  <- N_l^2

    box_1_h <- N_l
    box_1_w <- comp_lx(box_1_h, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio

  } else { # default: area == "no" and all others:

    # N area fixed:
    box_1_w <- b_w
    box_1_h <- b_h

  }

  # box 1:
  box_1_x <-  0  # center
  box_1_y <-  0  # center
  box_1 <- make_box("N", box_1_x, box_1_y, box_1_w, box_1_h)

  # plot(box_1, lbl_type = "namnum", cex = cex_lbl, lwd = f_lwd, lbl_sep = ":\nN = ")  # N (top)
  row_1_boxes <- list(box_1)  # list of boxes (lists)

  ## plot label:
  # plot_ftype_label("N", ftype_x, box_1_y, lbl_txt = lbl_txt, suffix = ":", pos = ftype_pos, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!

  # plot list of fboxes:
  # plot_fbox_list(row_1_boxes, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd)  # plot list of boxes


  ## CELLS in 4 corners (formerly 3rd row, y = 0, center): SDT cases/cells as 4 boxes: ------

  # Cell positions (in 4 corners):
  x_left  <- -3
  x_right <- +3
  y_bot   <- -4
  y_top   <- +4

  # dimensions lx:

  if (area == "sq") { # Scale SDT case/cell areas as squares:

    # Compute ly for current scale:
    hi_ly <- comp_ly_fsqr("hi", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)
    mi_ly <- comp_ly_fsqr("mi", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)
    fa_ly <- comp_ly_fsqr("fa", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)
    cr_ly <- comp_ly_fsqr("cr", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)

    # Compute lx corresponding to ly:
    hi_lx <- comp_lx(hi_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
    mi_lx <- comp_lx(mi_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
    fa_lx <- comp_lx(fa_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
    cr_lx <- comp_lx(cr_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio

  } else { # default: area == "no" and all others:

    # Set lx: fixed & all equal:
    hi_lx <- b_w
    mi_lx <- b_w
    fa_lx <- b_w
    cr_lx <- b_w

    # Set ly: fixed & all equal:
    hi_ly <- b_h
    mi_ly <- b_h
    fa_ly <- b_h
    cr_ly <- b_h

  } # if (area == etc.)

  ## coordinates:

  # fixed x-coordinates:
  if (by_top == "cd") {  # vertical marginal:

    # by cd(dc):
    hi_x <- x_right
    hi_y <- y_top

    mi_x <- x_left
    mi_y <- y_top

    fa_x <- x_right
    fa_y <- y_bot

    cr_x <- x_left
    cr_y <- y_bot

    # Handle alternative fnet cases: cdac
    if ( !is.na(by_bot) ) {  # Horizontal marginal dimension exists:

      if (by_bot == "ac"){ # Swap X-coord. of fa and cr boxes:
        fa_x <- x_left
        cr_x <- x_right
      }

    }

  } else if (by_top == "dc") {

    # by dc(cd):
    hi_x <- x_right
    hi_y <- y_top

    mi_x <- x_right
    mi_y <- y_bot

    fa_x <- x_left
    fa_y <- y_top

    cr_x <- x_left
    cr_y <- y_bot

    # Handle alternative fnet cases: dcac
    if ( !is.na(by_bot) ) {  # Horizontal marginal dimension exists:

      if (by_bot == "ac"){ # Swap X-coord. of mi and cr boxes:
        mi_x <- x_left
        cr_x <- x_right
      }

    }

  } else if (by_top == "ac") {

    # by ac(cd):
    hi_x <- x_right
    hi_y <- y_top

    mi_x <- x_right
    mi_y <- y_bot

    fa_x <- x_left
    fa_y <- y_bot

    cr_x <- x_left
    cr_y <- y_top

    # Handle alternative fnet cases: acdc
    if ( !is.na(by_bot) ) {  # Horizontal marginal dimension exists:

      if (by_bot == "dc"){ # Swap X-coord. of fa and mi boxes:
        fa_x <- x_right
        mi_x <- x_left
      }

    }

  } else {

    message(paste0("Unknown primary/vertical perspective: by_top = ", by_top))

  } # if (by_top == etc.)


  # } # if (area == etc.)

  # define boxes:
  box_hi <- make_box("hi", hi_x, hi_y, hi_lx, hi_ly)  # hi
  box_mi <- make_box("mi", mi_x, mi_y, mi_lx, mi_ly)  # mi
  box_fa <- make_box("fa", fa_x, fa_y, fa_lx, fa_ly)  # fa
  box_cr <- make_box("cr", cr_x, cr_y, cr_lx, cr_ly)  # cr

  ## plot boxes: 4 SDT cases/cells

  ## OLD: Plot boxes:
  # plot(box_hi, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd)
  # plot(box_mi, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd)
  # plot(box_fa, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd)
  # plot(box_cr, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd)

  ## NEW: Plot boxes by decreasing freq/prob (to prevent occlusion of box labels).
  ##      See comp_freq_fbox + plot_fbox_list in plot_util.R.
  row_3_boxes <- list(box_hi, box_mi, box_fa, box_cr)  # list of boxes (lists)
  # plot_fbox_list(row_3_boxes, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd)  # plot list of boxes

  ## plot label:
  # plot_ftype_label("hi", ftype_x, box_3_y_top, lbl_txt = lbl_txt, suffix = ":", pos = ftype_pos, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!


  ##   2nd row (y = +2): by_top perspective ------

  # Note: Express all widths of compound frequencies
  #       as sums of hi_lx mi_lx fa_lx cr_lx!

  # box dimensions (w and h):
  box_2_1_lx <- b_w  # default box width
  box_2_2_lx <- b_w

  box_2_1_ly <- b_h  # default box height
  box_2_2_ly <- b_h

  # default box coordindates (x and y):

  # X horizontal:
  box_2_1_x <- x_right
  box_2_2_x <- x_left
  box_2_1_y <- 0  # center
  box_2_2_y <- 0  # center

  # X vertical:
  box_2_1_x <- 0  # center
  box_2_2_x <- 0  # center
  box_2_1_y <- y_top
  box_2_2_y <- y_bot


  # Define boxes and labels by perspective:
  if (by_top == "cd") {

    ## (a) by condition:

    if (area == "sq") { # Scale area as square:

      # Compute ly for current scale:
      box_2_1_ly <- comp_ly_fsqr("cond_true",  area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # cond_true
      box_2_2_ly <- comp_ly_fsqr("cond_false", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # cond_false

      # Compute lx corresponding to ly:
      box_2_1_lx <- comp_lx(box_2_1_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
      box_2_2_lx <- comp_lx(box_2_2_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio

    } # if (area == etc.)

    # define boxes:
    box_2_1 <- make_box("cond_true",  box_2_1_x,  box_2_1_y, box_2_1_lx, box_2_1_ly)
    box_2_2 <- make_box("cond_false", box_2_2_x,  box_2_2_y, box_2_2_lx, box_2_2_ly)

    # plot label (vertical/top):
    plot_ftype_label("cond_true", box_2_1_x, (box_2_1_y + 1), lbl_txt = lbl_txt, suffix = ":", pos = 3, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!

  } else if (by_top == "dc") {

    ## (b) by decision:

    if (area == "sq") { # Scale area as square:

      # Compute ly for current scale:
      box_2_1_ly <- comp_ly_fsqr("dec_pos", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # dec_pos
      box_2_2_ly <- comp_ly_fsqr("dec_neg", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # dec_neg

      # Compute lx corresponding to ly:
      box_2_1_lx <- comp_lx(box_2_1_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
      box_2_2_lx <- comp_lx(box_2_2_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio

    }  # if (area == etc.)

    # define boxes:
    box_2_1 <- make_box("dec_pos", box_2_1_x,  box_2_1_y, box_2_1_lx, box_2_1_ly)
    box_2_2 <- make_box("dec_neg", box_2_2_x,  box_2_2_y, box_2_2_lx, box_2_2_ly)

    # plot label:
    plot_ftype_label("dec_pos", box_2_1_x, (box_2_1_y + 1), lbl_txt = lbl_txt, suffix = ":", pos = 3, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!

  } else if (by_top == "ac") {

    ## (c) by accuracy:

    if (area == "sq") { # Scale area as square:

      # Compute ly for current scale:
      box_2_1_ly <- comp_ly_fsqr("dec_cor", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # dec_cor
      box_2_2_ly <- comp_ly_fsqr("dec_err", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # dec_err

      # Compute lx corresponding to ly:
      box_2_1_lx <- comp_lx(box_2_1_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
      box_2_2_lx <- comp_lx(box_2_2_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio

    }  # if (area == etc.)

    # define boxes:
    box_2_1 <- make_box("dec_cor", box_2_1_x,  box_2_1_y, box_2_1_lx, box_2_1_ly)
    box_2_2 <- make_box("dec_err", box_2_2_x,  box_2_2_y, box_2_2_lx, box_2_2_ly)

    # plot label:
    plot_ftype_label("dec_cor", box_2_1_x, (box_2_1_y + 1), lbl_txt = lbl_txt, suffix = ":", pos = 3, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!

  } else {  # default on top: same as (by_top == "cd")

    ## (+) by condition:

    if (area == "sq") { # Scale area as square:

      # Compute ly for current scale:
      box_2_1_ly <- comp_ly_fsqr("cond_true",  area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # cond_true
      box_2_2_ly <- comp_ly_fsqr("cond_false", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # cond_false

      # Compute lx corresponding to ly:
      box_2_1_lx <- comp_lx(box_2_1_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
      box_2_2_lx <- comp_lx(box_2_2_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio

    } # if (area == etc.)

    # define boxes:
    box_2_1 <- make_box("cond_true",  box_2_1_x,  box_2_1_y, box_2_1_lx, box_2_1_ly)
    box_2_2 <- make_box("cond_false", box_2_2_x,  box_2_2_y, box_2_2_lx, box_2_2_ly)

    # plot label:
    plot_ftype_label("cond_true", box_2_1_x, (box_2_1_y + 1), lbl_txt = lbl_txt, suffix = ":", pos = 3, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!

  }

  ## OLD: plot boxes:
  # plot(box_2_1, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd, lbl_sep = ":\n")
  # plot(box_2_2, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd, lbl_sep = ":\n")

  # NEW:
  row_2_boxes <- list(box_2_1, box_2_2)  # list of boxes (lists)
  # plot_fbox_list(row_2_boxes, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd)  # plot list of boxes


  ##   4th row (y = -2): by perspective ------

  if ( !is.na(by_bot) ) {

    ## Note: Repeat code of 2nd row above (with 4 changes:
    ##       mirrored y-values, "by_bot" for "by_top", "box_4_" for "box_2_", default on top/bot):

    # box dimensions (w and h):
    box_4_1_lx <- b_w  # default box width
    box_4_2_lx <- b_w

    box_4_1_ly <- b_h  # default box height
    box_4_2_ly <- b_h

    # fixed box coordindates (x and y):

    # Y vertical:
    box_4_1_x <- 0  # center
    box_4_2_x <- 0  # center
    box_4_1_y <- y_top
    box_4_2_y <- y_bot

    # Y horizontal:
    box_4_1_x <- x_right
    box_4_2_x <- x_left
    box_4_1_y <- 0  # center
    box_4_2_y <- 0  # center

    # Define boxes and labels by perspective:
    if (by_bot == "cd") {

      ## (a) by condition:

      if (area == "sq") { # Scale area as square:

        # Compute ly for current scale:
        box_4_1_ly <- comp_ly_fsqr("cond_true",  area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # cond_true
        box_4_2_ly <- comp_ly_fsqr("cond_false", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # cond_false

        # Compute lx corresponding to ly:
        box_4_1_lx <- comp_lx(box_4_1_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
        box_4_2_lx <- comp_lx(box_4_2_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio

      } # if (area == etc.)

      # define boxes:
      box_4_1 <- make_box("cond_true",  box_4_1_x,  box_4_1_y, box_4_1_lx, box_4_1_ly)
      box_4_2 <- make_box("cond_false", box_4_2_x,  box_4_2_y, box_4_2_lx, box_4_2_ly)

      # plot label:
      plot_ftype_label("cond_true", ftype_x, box_4_1_y, lbl_txt = lbl_txt, suffix = ":", pos = ftype_pos, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!

    } else if (by_bot == "dc") {

      ## (b) by decision:

      if (area == "sq") { # Scale area as square:

        # Compute ly for current scale:
        box_4_1_ly <- comp_ly_fsqr("dec_pos", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # dec_pos
        box_4_2_ly <- comp_ly_fsqr("dec_neg", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # dec_neg

        # Compute lx corresponding to ly:
        box_4_1_lx <- comp_lx(box_4_1_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
        box_4_2_lx <- comp_lx(box_4_2_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio

      } # if (area == etc.)

      # define boxes:
      box_4_1 <- make_box("dec_pos", box_4_1_x,  box_4_1_y, box_4_1_lx, box_4_1_ly)
      box_4_2 <- make_box("dec_neg", box_4_2_x,  box_4_2_y, box_4_2_lx, box_4_2_ly)

      # plot label (horizontal/left):
      plot_ftype_label("dec_pos", (box_4_2_x - 1), box_4_2_y, lbl_txt = lbl_txt, suffix = ":", pos = 2, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!

    } else if (by_bot == "ac") {

      ## (c) by accuracy:

      if (area == "sq") { # Scale area as square:

        # Compute ly for current scale:
        box_4_1_ly <- comp_ly_fsqr("dec_cor", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # dec_cor
        box_4_2_ly <- comp_ly_fsqr("dec_err", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # dec_err

        # Compute lx corresponding to ly:
        box_4_1_lx <- comp_lx(box_4_1_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
        box_4_2_lx <- comp_lx(box_4_2_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio

      } # if (area == etc.)

      # define boxes:
      box_4_1 <- make_box("dec_cor", box_4_1_x,  box_4_1_y, box_4_1_lx, box_4_1_ly)
      box_4_2 <- make_box("dec_err", box_4_2_x,  box_4_2_y, box_4_2_lx, box_4_2_ly)

      # plot label:
      plot_ftype_label("dec_cor", ftype_x, box_4_1_y, lbl_txt = lbl_txt, suffix = ":", pos = ftype_pos, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!

    } else {  # default on bot: same as (by_bot == "dc")

      ## (+) by decision:

      if (area == "sq") { # Scale area as square:

        # Compute ly for current scale:
        box_4_1_ly <- comp_ly_fsqr("dec_pos", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # dec_pos
        box_4_2_ly <- comp_ly_fsqr("dec_neg", area_N = N_area, cur_freq = freq, cur_prob = prob, scale = scale)  # dec_neg

        # Compute lx corresponding to ly:
        box_4_1_lx <- comp_lx(box_4_1_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio
        box_4_2_lx <- comp_lx(box_4_2_ly, mf = corr_3, corf = scale_x)  # same, but corrected for aspect ratio

      }  # if (area == etc.)

      # define boxes:
      box_4_1 <- make_box("dec_pos", box_4_1_x,  box_4_1_y, box_4_1_lx, box_4_1_ly)
      box_4_2 <- make_box("dec_neg", box_4_2_x,  box_4_2_y, box_4_2_lx, box_4_2_ly)

      # plot label:
      plot_ftype_label("dec_pos", ftype_x, box_4_1_y, lbl_txt = lbl_txt, suffix = ":", pos = ftype_pos, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!

    }

    ## OLD: plot boxes:
    # plot(box_4_1, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd, lbl_sep = ":\n")
    # plot(box_4_2, lbl_type = f_lbl, cex = cex_lbl, lwd = f_lwd, lbl_sep = ":\n")

    # NEW:
    row_4_boxes <- list(box_4_1, box_4_2)  # list of boxes (lists)

  } # if ( !is.na(by_bot) ) etc.

  ## Combine ALL boxes:
  if ( !is.na(by_bot) ) {
    all_boxes <- c(row_1_boxes, row_2_boxes, row_3_boxes, row_4_boxes)
  } else {
    all_boxes <- c(row_1_boxes, row_2_boxes, row_3_boxes)
  } # if ( !is.na(by_bot) ) etc.

  ## Plot ALL boxes at once:
  # plot_fbox_list(all_boxes, lbl_type = f_lbl, lbl_sep = ":\n", cex = cex_lbl, lwd = f_lwd, density = NA)  # plot list of boxes
  plot_fbox_list(all_boxes,  # plot list of boxes
                 cur_freq = freq, lbl_txt = lbl_txt, col_pal = col_pal,  # PASS current freq/txt/pal arguments!
                 lbl_type = f_lbl, lbl_sep = f_lbl_sep,
                 cex = cex_lbl, lwd = f_lwd, lty = lty)  # no ...!


  ## (B) Plot probabilities as links: ------

  ## parameters:

  ## from top:

  ##   row 1 (center) to 2 (marginals): ----

  plot_link(box_1, box_2_1, 3, 1, cur_prob = prob, arr_code = arr_c,
            lbl_type = p_lbl, lbl_pos = NULL, cex = cex_p_lbl,
            col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale,
            ...)  # Allow ...!
  plot_link(box_1, box_2_2, 1, 3, cur_prob = prob, arr_code = arr_c,
            lbl_type = p_lbl, lbl_pos = NULL, lbl_off = 1, cex = cex_p_lbl,
            lbl_sep = "\n    = ",  # special case: cprev label !!!
            col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale,
            ...)  # Allow ...!  # link label in 2 lines

  ##   row 2 (vertical marginals) to 3 (cells): ----

  # Links depend on perspectives/box types:

  if (by_top == "cd") {  # row 2: by condition (cond_true vs. cond_false)

    ## (a) by condition:
    plot_link(box_2_1, box_hi, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 3, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_true  - hi
    plot_link(box_2_1, box_mi, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 3, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_true  - mi

    # Handle fnet cases:
    if ( !is.na(by_bot) ) {  # Horizontal marginal dimension exists:

      if (by_bot == "dc"){ # base case:

        plot_link(box_2_2, box_fa, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - fa
        plot_link(box_2_2, box_cr, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - cr

      } else if (by_bot == "ac"){ # swapped bottom boxes:

        plot_link(box_2_2, box_fa, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - fa
        plot_link(box_2_2, box_cr, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - cr

      }

    } else { # default for is.na(by_bot):

      plot_link(box_2_2, box_fa, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - fa
      plot_link(box_2_2, box_cr, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - cr

    }

  } else if (by_top == "dc") {  # row 2: by decision (dec_pos vs. dec_neg)

    ## (b) by decision:
    plot_link(box_2_1, box_hi, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 3, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_pos - hi
    plot_link(box_2_1, box_fa, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 3, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_pos - fa !

    # Handle fnet cases:
    if ( !is.na(by_bot) ) {  # Horizontal marginal dimension exists:

      if (by_bot == "cd"){ # base case:

        plot_link(box_2_2, box_mi, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - mi !
        plot_link(box_2_2, box_cr, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - cr

      } else if (by_bot == "ac"){ # swapped bottom boxes:

        plot_link(box_2_2, box_mi, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - mi !
        plot_link(box_2_2, box_cr, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - cr

      }

    } else { # default for is.na(by_bot):

      plot_link(box_2_2, box_mi, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - mi !
      plot_link(box_2_2, box_cr, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - cr

    }

  } else if (by_top == "ac") {  # row 2: by accuracy (dec_cor vs. dec_err)

    ## (c) by accuracy:
    plot_link(box_2_1, box_hi, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 3, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_cor - hi: acc_hi
    plot_link(box_2_1, box_cr, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 3, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_cor - cr: acc_cr

    # Handle fnet cases:
    if ( !is.na(by_bot) ) {  # Horizontal marginal dimension exists:

      if (by_bot == "cd"){ # base case:

        plot_link(box_2_2, box_mi, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_err - mi: err_mi
        plot_link(box_2_2, box_fa, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_err - fa: err_fa

      } else if (by_bot == "dc"){ # swapped bottom boxes:

        plot_link(box_2_2, box_mi, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_err - mi: err_mi
        plot_link(box_2_2, box_fa, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_err - fa: err_fa

      }

    } else { # default for is.na(by_bot):

      plot_link(box_2_2, box_mi, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_err - mi: err_mi
      plot_link(box_2_2, box_fa, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 1, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_err - fa: err_fa

    }

  } else {  # default on top: same as (by_top == "cd")

    ## (+) by condition:
    plot_link(box_2_1, box_hi, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_true  - hi
    plot_link(box_2_1, box_mi, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 4, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_true  - mi
    plot_link(box_2_2, box_fa, 4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - fa
    plot_link(box_2_2, box_cr, 2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 4, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - cr

  }

  ## from bottom:

  if ( !is.na(by_bot) ) {

    ##   row 4 (horizontal marginals) to 3 (cells): ----

    # Links depend on perspectives/box types:

    if (by_bot == "cd") {  # row 4: by condition (cond_true vs. cond_false)

      ## (a) by condition:
      plot_link(box_4_1, box_hi, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 4, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_true  - hi
      plot_link(box_4_1, box_mi, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 4, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_true  - mi

      if (by_top == "dc"){

        plot_link(box_4_2, box_fa, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - fa
        plot_link(box_4_2, box_cr, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - cr

      } else if (by_top == "ac"){

        plot_link(box_4_2, box_fa, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - fa
        plot_link(box_4_2, box_cr, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # cond_false - cr

      }

    } else if (by_bot == "dc") {  # row 4: by decision (dec_pos vs. dec_neg)

      ## (b) by decision:
      plot_link(box_4_1, box_hi, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 4, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_pos - hi
      plot_link(box_4_1, box_fa, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 4, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_pos - fa !

      if (by_top == "cd"){

        plot_link(box_4_2, box_mi, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - mi !
        plot_link(box_4_2, box_cr, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - cr

      } else if (by_top == "ac"){

        plot_link(box_4_2, box_mi, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - mi !
        plot_link(box_4_2, box_cr, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - cr

      }

    } else if (by_bot == "ac") {  # row 4: by accuracy (dec_cor vs. dec_err)

      ## (c) by accuracy:

      plot_link(box_4_1, box_hi, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 4, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_cor - hi: acc_hi
      plot_link(box_4_1, box_cr, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 4, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_cor - cr: acc_cr

      if (by_top == "cd"){

        plot_link(box_4_2, box_mi, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_err - mi: err_mi
        plot_link(box_4_2, box_fa, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_err - fa: err_fa

      } else if (by_top == "dc"){

        plot_link(box_4_2, box_mi, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_err - mi: err_mi
        plot_link(box_4_2, box_fa, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_err - fa: err_fa

      }

    } else {  # default on bot: same as (by_bot == "dc")

      ## (+) by decision:
      plot_link(box_4_1, box_hi, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 4, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_pos - hi
      plot_link(box_4_1, box_fa, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 4, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_pos - fa !
      plot_link(box_4_2, box_mi, 3, 1, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - mi !
      plot_link(box_4_2, box_cr, 1, 3, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 2, cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!  # dec_neg - cr

    }

    ## Center to horizontal (left/right) (formerly row 5 to 4): ----

    if (by_bot == "cd" || by_bot == "dc" || (by_bot == "ac")) {

      # link to 2 default boxes:
      plot_link(box_1, box_4_1,  4, 2, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 3,
                cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
      plot_link(box_1, box_4_2,  2, 4, cur_prob = prob, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = 3, # lbl_off = 4/4,
                cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

    }

  } # if ( !is.na(by_bot) ) etc.


  ## Plot diagonal links of joint probabilities (from N to joint frequencies): -----
  # +++ here now +++

  if (joint_p){

    # compute joint probabilities:
    n_digits <- 3
    p_hi <- as_pc(round(freq$hi/freq$N, n_digits), 1)
    p_mi <- as_pc(round(freq$mi/freq$N, n_digits), 1)
    p_fa <- as_pc(round(freq$fa/freq$N, n_digits), 1)
    p_cr <- as_pc(round(freq$cr/freq$N, n_digits), 1)

    # create labels:
    p_hi_lbl <- ""  # initialize
    p_mi_lbl <- ""
    p_fa_lbl <- ""
    p_cr_lbl <- ""

    if (!is.na(p_lbl)){

      if (p_lbl == "abb"){

        p_hi_lbl <- paste0("p(hi)")
        p_mi_lbl <- paste0("p(mi)")
        p_fa_lbl <- paste0("p(fa)")
        p_cr_lbl <- paste0("p(cr)")

      } else if (p_lbl == "def"){

        p_hi_lbl <- paste0("p(hi) =", p_hi, "%")
        p_mi_lbl <- paste0("p(mi) =", p_mi, "%")
        p_fa_lbl <- paste0("p(fa) =", p_fa, "%")
        p_cr_lbl <- paste0("p(cr) =", p_cr, "%")

      } else if (p_lbl == "nam"){

        p_hi_lbl <- paste0("p(", txt$hi_lbl, ")")
        p_mi_lbl <- paste0("p(", txt$mi_lbl, ")")
        p_fa_lbl <- paste0("p(", txt$fa_lbl, ")")
        p_cr_lbl <- paste0("p(", txt$cr_lbl, ")")

      } else if (p_lbl == "namnum"){

        p_hi_lbl <- paste0("p(", txt$hi_lbl, ")\n = ", p_hi, "%")
        p_mi_lbl <- paste0("p(", txt$mi_lbl, ")\n = ", p_mi, "%")
        p_fa_lbl <- paste0("p(", txt$fa_lbl, ")\n = ", p_fa, "%")
        p_cr_lbl <- paste0("p(", txt$cr_lbl, ")\n = ", p_cr, "%")

      } else if (p_lbl == "num" | p_lbl == "min" | p_lbl == "mix"){ # percentages only:

        p_hi_lbl <- paste0(p_hi, "%")
        p_mi_lbl <- paste0(p_mi, "%")
        p_fa_lbl <- paste0(p_fa, "%")
        p_cr_lbl <- paste0(p_cr, "%")

      }

    }

    # plot diagonal links:
    if (by_top == "cd"){

      plot_link(box_1, box_hi, 7, 5, lbl = p_hi_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
      plot_link(box_1, box_mi, 6, 8, lbl = p_mi_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

      if ( !is.na(by_bot) ) {  # Horizontal marginal dimension exists:

        if (by_bot == "dc"){

          plot_link(box_1, box_fa, 8, 6, lbl = p_fa_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
          plot_link(box_1, box_cr, 5, 7, lbl = p_cr_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

        } else if (by_bot == "ac"){

          plot_link(box_1, box_fa, 5, 7, lbl = p_fa_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
          plot_link(box_1, box_cr, 8, 6, lbl = p_cr_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

        } # if (by_bot ==...) end.

      } else { # if is.na(by_bot) ) (i.e., by = "cd" only):

        plot_link(box_1, box_fa, 8, 6, lbl = p_fa_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                  cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
        plot_link(box_1, box_cr, 5, 7, lbl = p_cr_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                  cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

      } # if ( !is.na(by_bot) ) end.

    } else if (by_top == "dc"){

      plot_link(box_1, box_hi, 7, 5, lbl = p_hi_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
      plot_link(box_1, box_fa, 6, 8, lbl = p_fa_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

      if ( !is.na(by_bot) ) {  # Horizontal marginal dimension exists:

        if (by_bot == "cd"){

          plot_link(box_1, box_mi, 8, 6, lbl = p_mi_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
          plot_link(box_1, box_cr, 5, 7, lbl = p_cr_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

        } else if (by_bot == "ac"){

          plot_link(box_1, box_mi, 5, 7, lbl = p_mi_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
          plot_link(box_1, box_cr, 8, 6, lbl = p_cr_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

        } # if (by_bot ==...) end.

      } else { # if is.na(by_bot) ) (i.e., by = "dc" only):

        plot_link(box_1, box_mi, 8, 6, lbl = p_mi_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                  cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
        plot_link(box_1, box_cr, 5, 7, lbl = p_cr_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                  cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

      } # if ( !is.na(by_bot) ) end.

    } else if (by_top == "ac"){

      plot_link(box_1, box_hi, 7, 5, lbl = p_hi_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
      plot_link(box_1, box_cr, 6, 8, lbl = p_cr_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

      if ( !is.na(by_bot) ) {  # Horizontal marginal dimension exists:

        if (by_bot == "cd"){

          plot_link(box_1, box_fa, 5, 7, lbl = p_fa_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
          plot_link(box_1, box_mi, 8, 6, lbl = p_mi_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

        } else if (by_bot == "dc"){

          plot_link(box_1, box_fa, 8, 6, lbl = p_fa_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
          plot_link(box_1, box_mi, 5, 7, lbl = p_mi_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                    cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

        } # if (by_bot ==...) end.

      } else { # if is.na(by_bot) ) (i.e., by = "ac" only):

        plot_link(box_1, box_fa, 5, 7, lbl = p_fa_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                  cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!
        plot_link(box_1, box_mi, 8, 6, lbl = p_mi_lbl, arr_code = arr_c, lbl_type = p_lbl, lbl_pos = NULL,
                  cex = cex_p_lbl, col_pal = col_pal, p_lwd = p_lwd, p_scale = p_scale, ...)  # Allow ...!

      } # if ( !is.na(by_bot) ) end.

    } # if (by_top == ...) end.

  } # if (joint_p) end.


  ## (C) Plot other stuff: ------

  # box_else <- make_box("else_box", 9, -2, b_w, b_h)  # define some arbitrary box
  # plot(box_else, col = "firebrick1", cex = 1/2, font = 2)     # plot box

  ## ftype labels:
  # plot_ftype_label("N", ftype_x, 4, lbl_txt = lbl_txt, suffix = ":", pos = ftype_pos, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!
  # plot_ftype_label("cond_true", ftype_x, 2, lbl_txt = lbl_txt, suffix = ":", pos = ftype_pos, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!
  # plot_ftype_label("hi", ftype_x, 0, lbl_txt = lbl_txt, suffix = ":", pos = ftype_pos, col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!
  # plot_ftype_label("N", ftype_x, -4, pos = ftype_pos, lbl_txt = lbl_txt, suffix = ":", col = pal["txt"], cex = cex_lbl, ...)  # Allow ...!


  ## (6) Title: ------

  # Main title: Handle deprecated "title_lbl" argument: ----

  if (is.null(title_lbl) == FALSE){
    message("Argument 'title_lbl' is deprecated. Please use 'main' instead.")
    main <- title_lbl
  }


  # Subtitle (2nd line): ----

  if (sub == "type"){ # show default plot type info:

    if ( !is.na(by_bot) ) {
      sub <- paste0(lbl["plot_fnet_lbl"], " (by ", as.character(by), ")")  # plot name: frequency net..
    } else {
      sub <- paste0(lbl["plot_tree_lbl"], " (by ", as.character(by), ")")  # plot name: tree/frequency tree.
    } # if ( !is.na(by_bot) )

  }


  # Combine title + subtitle: ----

  if ( (main != "") & (sub == "") ){ # only main title:
    cur_title_lbl <- main
  } else if ( (main == "") & (sub != "") ){ # only subtitle:
    cur_title_lbl <- sub
  } else { # combine both:
    cur_title_lbl <- paste0(main, ":\n", sub)  # add ":" and line break
  }


  # Plot title: ----

  title(cur_title_lbl, adj = 0, line = 0, font.main = 1, cex.main = 1.2)  # (left, NOT raised (by +1), normal font)



  ## (7) Margins: ------

  if (mar_notes) {

    # Note:
    note_lbl <- ""  # initialize
    if ( (area != "no") && (scale == "f") ) { # Note area type and scaling by f:
      note_lbl <- label_note(area = area, scale = scale)
    }

    plot_mar(show_freq = TRUE, show_cond = TRUE, show_dec = TRUE,
             show_accu = TRUE, accu_from_freq = FALSE,
             note = note_lbl,
             cur_freq = freq, cur_prob = prob, lbl_txt = lbl_txt)

  } # if (mar_notes)


  ##   Finish: ---------

  # on.exit(par(opar))  # par(opar)  # restore original settings
  invisible() # restores par(opar)

} # plot_fnet().


## Check: ------

# ## Basics:
#
# ## Global freq and prob objects:
# plot_fnet()  # default, same as:
# plot_fnet(by = "cddc", area = "no", scale = "f",
#            f_lbl = "default", f_lwd = 0, cex_lbl = .90,
#            p_lbl = "mix", arr_c = -2, cex_p_lbl = NA)
#
# ## Locally computed values:
# plot_fnet(N = 10, prev = 1/2, sens = 4/5, spec = 3/5)
# plot_fnet(N = 10, prev = 1/3, sens = 3/5, spec = 4/5, area = "hr")
# plot_fnet(N = 10, prev = 1/4, sens = 3/5, spec = 2/5, area = "sq", mar_notes = TRUE)
#
# ## Custom text and color settings:
# my_txt <- init_txt(cond_lbl = "The Truth", cond_true_lbl = "so true", cond_false_lbl = "so false",
#                    hi_lbl = "TP", mi_lbl = "FN", fa_lbl = "FP", cr_lbl = "TN")
# my_col <- init_pal(N_col = rgb(0, 169, 224, max = 255),  # seeblau
#                    hi_col = "gold", mi_col = "firebrick1", fa_col = "firebrick2", cr_col = "orange")
# plot_fnet(f_lbl = "nam", lbl_txt = my_txt, col_pal = my_col)
#
# ## Local values and custom color and text settings:
# plot_fnet(N = 7, prev = 1/2, sens = 3/5, spec = 4/5, round = FALSE,
#            by = "cdac", lbl_txt = txt_org, f_lbl = "namnum", f_lbl_sep = ":\n",
#            col_pal = pal_rgb)  # custom colors
#
# plot_fnet(N = 5, prev = 1/2, sens = .8, spec = .5, scale = "p",  # note scale!
#            by = "cddc", area = "hr", col_pal = pal_bw, f_lwd = 1) # custom colors
#
# plot_fnet(N = 3, prev = .50, sens = .50, spec = .50, scale = "p",              # note scale!
#            area = "sq", lbl_txt = txt_org, f_lbl = "namnum", f_lbl_sep = ":\n", # custom text
#            col_pal = pal_kn, f_lwd = .5)                                        # custom colors
#
# ## Plot versions:
# # (a) single tree (nchar(by) == 2):
# plot_fnet(by = "cd", f_lbl = "def")  # by condition (freq boxes: hi mi fa cr)
# plot_fnet(by = "dc", f_lbl = "def")  # by decision  (freq boxes: hi fa mi cr)
# plot_fnet(by = "ac", f_lbl = "def")  # by decision  (freq boxes: hi cr mi fa)
#
# # (b) double tree (nchar(by) == 4):
# #     (3 x 2) = 6 versions (+ 3 redundant ones):
# plot_fnet(by = "cddc")  # v01 (default)
# plot_fnet(by = "cdac")  # v02
# plot_fnet(by = "cdcd")  # (+) Message
#
# plot_fnet(by = "dccd")  # v03
# plot_fnet(by = "dcac")  # v04
# plot_fnet(by = "dcdc")  # (+) Message
#
# plot_fnet(by = "accd")  # v05
# plot_fnet(by = "acdc")  # v06
# plot_fnet(by = "acac")  # (+) Message
#
# ## Plot options:
#
# # area:
# plot_fnet(area = "no")  # rectangular boxes (default): (same if area = NA/NULL)
# plot_fnet(area = "sq")  # squares (areas on each level sum to N)
#
# # scale (matters for scaled areas and small N):
# plot_fnet(area = "sq", scale = "f")  # areas scaled by (rounded or non-rounded) freq
# plot_fnet(area = "sq", scale = "p")  # areas scaled by prob
#
# ## Freq (as boxes):
#
# # f_lbl:
# plot_fnet(f_lbl = "default") # default: short name and numeric value (abb = num)
# plot_fnet(f_lbl = "abb")     # abbreviated freq names (variable names)
# plot_fnet(f_lbl = "nam")     # only freq names
# plot_fnet(f_lbl = "num")     # only numeric freq values
# plot_fnet(f_lbl = "namnum")  # names and numeric freq values
# plot_fnet(f_lbl = "namnum", cex_lbl = .75)  # smaller freq labels
# plot_fnet(f_lbl = NA)        # no freq labels
# plot_fnet(f_lbl = "any")     # short name and value (abb = num)
#
# # f_lwd:
# plot_fnet(f_lwd =  0)  # no lines (default), set to tiny_lwd = .001, lty = 0 (same if NA/NULL)
# plot_fnet(f_lwd =  1)  # basic lines
# plot_fnet(f_lwd =  3)  # thicker lines
# plot_fnet(f_lwd = .5)  # thinner lines
#
# ## Prob (as links):
#
# # p_lbl: Label types
# plot_fnet(p_lbl = "mix")     # abbreviated names with numeric values (abb = num)
# plot_fnet(p_lbl = NA)      # no prob labels (NA/NULL/"none")
# plot_fnet(p_lbl = "nam")     # only prob names
# plot_fnet(p_lbl = "num")     # only numeric prob values
# plot_fnet(p_lbl = "namnum")  # names and numeric prob values
# plot_fnet(p_lbl = "namnum", cex_p_lbl = .70)  # smaller prob labels
# plot_fnet(by = "cddc", p_lbl = "min")  # minimal labels
# plot_fnet(by = "cdac", p_lbl = "min")
# plot_fnet(by = "cddc", p_lbl = "mix")  # mix abbreviated names and numeric values
# plot_fnet(by = "cdac", p_lbl = "mix")
# plot_fnet(by = "cddc", p_lbl = "abb")  # abbreviated names
# plot_fnet(by = "cdac", p_lbl = "abb")
# plot_fnet(p_lbl = "any") # short name and value (abb = num)
#
# # arr_c:
# plot_fnet(arr_c =  0)  # acc_c = 0: no arrows
# plot_fnet(arr_c = -3)  # arr_c = -1 to -3: points at both ends
# plot_fnet(arr_c = -2)  # point at far end
# plot_fnet(arr_c = +2)  # crr_c = 1-3: V-shape arrows at far end
# plot_fnet(arr_c = +3)  # V-shape arrows at both ends
# plot_fnet(arr_c = +6)  # arr_c = 4-6: T-shape arrows
#
#
# ## Plain plot versions:
#
# plot_fnet(area = "no", f_lbl = "nam", p_lbl = NA, col_pal = pal_rgb)
# plot_fnet(area = "no", f_lbl = "abb", p_lbl = "abb", col_pal = pal_bw)
# plot_fnet(area = "no", f_lbl = "num", p_lbl = "num", col_pal = pal_kn)
#
# plot_fnet(area = "sq", f_lbl = "abb", p_lbl = NA, col_pal = pal_rgb)
# plot_fnet(area = "sq", f_lbl = "num", p_lbl = NA, f_lwd = 1, col_pal = pal_bw)
# plot_fnet(area = "sq", f_lbl = "def", p_lbl = NA, f_lwd = 1, col_pal = pal_kn)
#
# ## Suggested combinations:
#
# plot_fnet(f_lbl = "def", p_lbl = "mix")
# plot_fnet(f_lbl = "namnum", p_lbl = "mix", cex_lbl = .80, cex_p_lbl = .75)
#
# plot_fnet(area = "sq", f_lbl = "nam", p_lbl = "abb", lbl_txt = txt_TF)
# plot_fnet(area = "sq", f_lbl = "num", p_lbl = "num", f_lwd = 1, col_pal = pal_rgb)
# plot_fnet(area = "sq", f_lbl = "def", p_lbl = "mix", f_lwd = 1, col_pal = pal_kn)

# # Use case: Highlight horizontal vs. vertical perspectives (example by Karin): ----
#
# # Colors:
# my_non <- "grey95"
# my_red <- "orange1"
# my_blu <- "skyblue1"
#
# # Define scenario:
# mammography <- riskyr(N = 10000, prev = .01, sens = .80, fart = .096,
#                       scen_lbl = "Mammography screening",
#                       N_lbl = "Women", cond_lbl = "Breast cancer", cond_true_lbl = "Cancer (C+)", cond_false_lbl = "no Cancer (C-)",
#                       dec_lbl = "Test result", dec_pos_lbl = "positive (T+)", dec_neg_lbl = "negative (T-)",
#                       hi_lbl = "B+ and T+", mi_lbl = "B+ and T-", fa_lbl = "B- and T+", cr_lbl = "B- and T-")
#
# # (a) Emphasize condition perspective (rows):
# my_col_1 <- init_pal(N_col = my_non,
#                      cond_true_col = my_blu, cond_false_col = my_red,
#                      dec_pos_col = my_non, dec_neg_col = my_non,
#                      hi_col = my_blu, mi_col = my_blu,
#                      fa_col = my_red, cr_col = my_red)
# plot(mammography, type = "fnet", col_pal = my_col_1,
#      f_lbl = "namnum", f_lwd = 2, p_lbl = "no", arr_c = 0)
#
# # (b) Emphasize decision perspective (columns):
# my_col_2 <- init_pal(N_col = my_non,
#                      cond_true_col = my_non, cond_false_col = my_non,
#                      dec_pos_col = my_red, dec_neg_col = my_blu,
#                      hi_col = my_red, mi_col = my_blu,
#                      fa_col = my_red, cr_col = my_blu)
# plot(mammography, type = "fnet", col_pal = my_col_2,
#      f_lbl = "namnum", f_lwd = 2, p_lbl = "no", arr_c = 0)


read_by <- function(by){
  # Helper function with
  # - input:  by argument and
  # - output: vector of by_top, by_bot, and (possibly different) by_now:

  # Initialize outputs:
  by_top <- NULL
  by_bot <- NULL
  by_now <- NULL

  # Interpret inputs:
  if ( !is.null(by) && !is.na(by) ) { by <- tolower(by) }  # by in lowercase
  if ( is.null(by) || is.na(by) )  { by <- "cddc" }        # use default
  if (by == "any" || by == "all" || by == "default" || by == "def" || by == "no" ) { by <- "cddc" }  # use default

  # Use by input:
  # Case 1: Plot 2 perspectives (prism, double tree):
  if (nchar(by) >= 4) {

    by_top <- substr(by, 1, 2)  # top perspective (row 2): by = "cd" "dc" "ac"
    by_bot <- substr(by, 3, 4)  # bottom perspective (row 4): by = "cd" "dc" "ac"

    # Catch & correct invalid entries:
    if (by_top == by_bot) {
      message("Specified 2 identical perspectives.")
    }

    # Invalid perspectives:
    if ((by_top %in% c("cd", "dc", "ac")) == FALSE) {
      message("Invalid 1st perspective! Valid by = {'cddc', 'cdac', 'dccd', 'dcac', 'accd', 'acdc'}.\nUsing by = 'cd..'.")
      by_top <- "cd"  # default
    }
    if ((by_bot %in% c("cd", "dc", "ac")) == FALSE) {
      message("Invalid 2nd perspective! Valid by = {'cddc', 'cdac', 'dccd', 'dcac', 'accd', 'acdc'}.\nUsing by = '..dc'.")
      by_bot <- "dc"  # default
    }

    # Valid 1st but invalid 2nd perspective:
    if ((by_top == "cd") && (by_bot != ("dc") & by_bot != ("ac") & by_bot != ("cd"))) {
      message("If 1st perspective by = 'cd', 2nd perspective should be 'dc' or 'ac'.\nUsing by = 'cddc'.")
      by_bot <- "dc"  # default 1
    }
    if ((by_top == "dc") && (by_bot != ("cd") & by_bot != ("ac") & by_bot != ("dc"))) {
      message("If 1st perspective by = 'dc', 2nd perspective should be 'cd' or 'ac'.\nUsing by = 'dccd'.")
      by_bot <- "cd"  # default 2
    }
    if ((by_top == "ac") && (by_bot != ("cd") & by_bot != ("dc") & by_bot != ("ac"))) {
      message("If 1st perspective by = 'ac', 2nd perspective should be 'cd' or 'dc'.\nUsing by = 'accd'.")
      by_bot <- "cd"  # default 3
    }

  }

  # Case 2: Plot 1 perspective (single tree):
  if (nchar(by) <= 2) {

    by_top <- substr(by, 1, 2)  # top perspective (row 2): by = "cd" "dc" "ac"

    if ((by_top %in% c("cd", "dc", "ac")) == FALSE) {
      message("Invalid perspective! Valid by = {'cd', 'dc', 'ac'}.\nUsing by = 'cd'.")
      by_top <- "cd"  # default
    }

    # by_bot <- "dc" # Temporary HACK (to allow testing Case 2 with plot code requiring 2 perspectives)!
    by_bot <- NA  # signal absence of 2nd perspective
  }

  # Determine current version of by (by_now, which may be different from original by):
  if ( !is.na(by_bot) ) {
    by_now <- paste0(by_top, by_bot)
  } else {
    by_now <- by_top
  } # if ( !is.na(by_bot) ) etc.
  # print(by_now)

  # Finish:
  return(c(by_top, by_bot, by_now))

} # read_by() end.

## Check:
# read_by(by = "cd")
# read_by(by = "cddc")
# read_by(by = "xx")
# read_by(by = "cdxx")
# read_by(by = "xxxxxx")


## Done: [2021 01 02] ------

## (0) Design basic cddc case based on plot_prism().
## (1) Removed 2nd population box (box_5) and area = "hr" options.
## (2) Added support for "cdac" and "dcac" cases.
## (3) Added diagonal links for joint probabilities
##     (using new options in plot_link() for setting pos1/pos2 to 5-8).

## ToDo: [2021 01 03] ------

## eof. ----------
hneth/riskyr documentation built on May 11, 2024, 12:10 a.m.