R/direct.evidence.plot.R

Defines functions direct.evidence.plot

Documented in direct.evidence.plot

#' Plot for direct evidence proportions in a network meta-analysis using \code{netmeta}
#'
#' This function plots relevant measures quantifying the direct evidence proportion, mean path length
#' and aggregated minimal parallelism of a frequentist network meta-analysis model generated by
#' \code{\link[netmeta]{netmeta}}.
#'
#' @usage direct.evidence.plot(x, random=FALSE, comparison.label.size=2,
#' numeric.label.size=3, subplot.ratio=c(5, 1.3, 1.3))
#'
#' @param x An object of class \code{netmeta} containing the results of a network meta-analysis
#' using the \code{\link[netmeta]{netmeta}} function.
#' @param random Logical. If set to \code{TRUE}, results for the random-effects model are displayed.
#' If set to \code{FALSE}, results for the fixed-effect model are displayed. \code{FALSE} by default.
#' @param comparison.label.size A numeric value for the size of comparison labels
#' to be used in the plot. Default is \code{2}.
#' @param numeric.label.size A numeric value for the label size of numeric values
#' to be used in the plot. Default is \code{3}.
#' @param subplot.ratio A numeric vector containing three numbers. Defines the width for each of
#' the three subplots included in the plot (from left to right). Default is \code{c(5,1.3,1.3)}.
#'
#' @details
#' The function generates a plot containing three subplots displaying relevant characteristics
#' to evaluate the reliability of effect size estimates within a network meta-analysis model.
#' \itemize{
#' \item \strong{Direct Evidence Proportion}. This bar chart displays the proportion of direct
#' evidence (orange) contained in each network estimate. It is of note that both direct and indirect
#' evidence may contribute to the violation of the assumption of consistency underlying network
#' meta-analysis models. Nevertheless, this plot allows to distinguish comparison estimates
#'  for which direct evidence was used, and to what extent, and comparisons which had to be inferred
#'  by indirect evidence alone.
#' \item \strong{Minimal Parallelism}. This bar chart displays the minimum number of independent paths
#' contributing to the effect estimate on an aggregated level. Large values of parallelism can be
#' interpreted as supporting the robustness of the estimate.
#' \item \strong{Mean Path Length}. This bar chart displays the mean path length, which characterizes
#' the degree of indirectness of an estimate. Higher mean path lengths indicate less reliable
#' estimates, given that more similarity assumptions have to be made when serially combining
#' direct comparisons. Following König, Krahn and Binder
#' (\href{https://www.ncbi.nlm.nih.gov/pubmed/24123165}{2013}), comparisons with mean path lengths
#' greater than two should be interpreted with caution. This threshold is displayed as a blue vertical
#' line in the plot.
#' }
#'
#'
#' @references Harrer, M., Cuijpers, P., Furukawa, T.A, & Ebert, D. D. (2019).
#' \emph{Doing Meta-Analysis in R: A Hands-on Guide}. DOI: 10.5281/zenodo.2551803. \href{https://bookdown.org/MathiasHarrer/Doing_Meta_Analysis_in_R/frequentist-network-meta-analysis.html}{Chapter 11.1}
#'
#' König J., Krahn U., Binder H. (2013): Visualizing the flow of evidence in network meta-analysis and
#' characterizing mixed treatment comparisons. \emph{Statistics in Medicine, 32}, 5414–29
#'
#' @author Mathias Harrer & David Daniel Ebert
#'
#' @import ggplot2 netmeta
#' @importFrom gridExtra grid.arrange arrangeGrob
#' @importFrom scales percent
#' @importFrom graphics abline axis lines mtext par plot points rect segments text
#' @importFrom stats as.formula hat influence ks.test optimize pbinom pchisq pf pnorm pt punif qchisq qf qnorm qt reformulate reorder setNames uniroot
#'
#' @return
#' \itemize{
#' \item \code{data}: A \code{data.frame} containing columns for the proportion of direct and indirect
#' evidence of each comparison (\code{proportion.direct} and \code{proportion.indirect}), the
#' mean path length (\code{meanpath}) and the minimal parallelism (\code{minpar})
#' for each comparison.
#' \item \code{plot}: The generated plot (if the function output was saved to an object).
#' }
#'
#' @export direct.evidence.plot
#'
#' @seealso
#' \code{\link[netmeta]{netmeta}}, \code{\link[netmeta]{netmeasures}}
#'
#' @examples
#' \dontrun{
#' # Load Senn2013 data from netmeta
#' suppressPackageStartupMessages(library(netmeta))
#' data(Senn2013)
#'
#' # Conduct network meta-analysis (fixed-effects model)
#' nma = netmeta(TE, seTE, treat1, treat2, studlab,
#'               data=Senn2013, sm='MD', comb.random=FALSE)
#'
#' # Generate the plot
#' dep = direct.evidence.plot(nma, random=FALSE, comparison.label.size = 1,
#' numeric.label.size=1, subplot.ratio=c(3,1,1))
#' dep}



direct.evidence.plot = function(x,
                                random = FALSE,
                                comparison.label.size = 2,
                                numeric.label.size = 3,
                                subplot.ratio = c(5,1.3, 1.3)) {

    # Validate
    x = x
    random = random
    cts = comparison.label.size
    nts = numeric.label.size
    spr = subplot.ratio

    if (class(x) != "netmeta") {
        stop("Input to this function has to be an object of class 'netmeta' created by the 'netmeta::netmeta' function.")
    }

    # PLOT 1: Direct and Indirect Evidence ####

    # Get Measures
    measures = netmeasures(x, random = random)$proportion
    indirect = 1 - measures
    measures = data.frame(comparison = names(measures), direct = measures, indirect = indirect)
    rownames(measures) = c()
    measures$direct = round(measures$direct, 4)
    measures$indirect = round(measures$indirect, 4)
    measures.reshape = with(measures, {
        data.frame(comparison = rep(comparison, 2),
                   variable = rep(c("direct", "indirect"),
                                  each = nrow(measures)),
                   value = c(direct, indirect))
    })
    names = measures.reshape[measures.reshape$variable == "direct", ]$comparison
    direct = measures.reshape[measures.reshape$variable == "direct", ]$value
    names = names[order(match(names, direct))]

    # Reorder Label
    measures$comparison = factor(measures$comparison,
                                 levels = measures$comparison[rev(order(measures$direct))])
    levels = levels(measures$comparison)
    measures.reshape$comparison = factor(measures.reshape$comparison, levels = levels)



    # Plot
    PlotDirectEvidence = ggplot2::ggplot(measures.reshape, aes(x = factor(comparison, levels = rev(levels(comparison))), fill = factor(variable,
        levels = c("indirect", "direct")), y = value)) + geom_bar(stat = "identity", position = "fill") +
        coord_flip() + theme_minimal() + theme(legend.position = "left") + scale_y_continuous(labels = scales::percent) +
        ylab("Percentage") + xlab("Network Estimate") + guides(fill = guide_legend(title = "Evidence")) +
        scale_fill_manual(values = c("lightblue", "orange")) + geom_hline(aes(yintercept = 0.25), color = "white") +
        geom_hline(aes(yintercept = 0.5), color = "white") + geom_hline(aes(yintercept = 0.75), color = "white")




    # PLOT 2: Mean Path Length ####

    # Get Measures
    mpath = netmeasures(x, random = random)$meanpath
    path.df = data.frame(comparison = names(mpath), mpath = mpath)
    rownames(path.df) = c()
    path.df$comparison = factor(path.df$comparison, levels = levels)


    # Plot for summary plot
    PlotMeanPathLength_s = ggplot2::ggplot(path.df, aes(x = factor(comparison, levels = rev(levels(comparison))), y = mpath)) + geom_bar(stat = "identity",
        fill = "lightgray") + coord_flip() + geom_hline(aes(yintercept = 2), color = "blue") + geom_text(aes(x = comparison,
        y = 0.4, label = comparison), color = "gray23", size = cts) + geom_text(aes(x = comparison, y = mpath +
        0.1, label = round(mpath, 1)), size = nts) + ylab("Mean Path Length") + theme(axis.title.y = element_blank(),
        axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.ticks.x = element_blank(), panel.background = element_blank()) +
        scale_x_discrete(position = "top")



    # PLOT 3: Parallelism ####

    # Get Measures
    mpar = netmeasures(x, random = random)$minpar
    mpar.df = data.frame(comparison = names(mpar), mpar = mpar)
    rownames(mpar.df) = c()
    mpar.df$comparison = factor(mpar.df$comparison, levels = levels)

    # Plot for summary plot
    PlotMinimalParallelism_s = ggplot2::ggplot(mpar.df, aes(x = factor(comparison, levels = rev(levels(comparison))), y = mpar)) +
        geom_bar(stat = "identity", fill = "lightgray") + coord_flip() + geom_text(aes(x = comparison, y = mpar +
        0.1, label = round(mpar, 1)), size = nts) + geom_text(aes(x = comparison, y = 0.4, label = comparison),
        color = "gray23", size = cts) + ylab("Minimal Parallelism") + theme(axis.ticks.y = element_blank(),
        axis.ticks.x = element_blank(), axis.title.y = element_blank(), axis.text.y = element_blank(), panel.background = element_blank())


    # Process for return ####

    # Save data used for plotting in df
    data = data.frame(proportion.direct = measures$direct,
                      proportion.indirect = measures$indirect,
                      meanpath = mpath,
                      minpar = mpar)

    # Set title
    if (random == FALSE) {
        plot_title = "Direct evidence proportion for each network estimate (fixed-effect model)"
    } else {
        plot_title = "Direct evidence proportion for each network estimate (random-effects model)"
    }

    grid = gridExtra::arrangeGrob(PlotDirectEvidence, PlotMinimalParallelism_s, PlotMeanPathLength_s, ncol = 3, widths = spr,
        heights = c(4), top = plot_title)

    returnlist = list(data = data, plot = grid)

    class(returnlist) = "direct.evidence.plot"

    invisible(returnlist)

    returnlist

}
MathiasHarrer/dmetar documentation built on April 4, 2024, 6:57 p.m.