1 Introduction

The nmaplateplot package is a graphical display of results from network meta-analysis (NMA). It is suitable for outcomes like odds ratio (OR), risk ratio (RR), risk difference (RD) and standardized mean difference (SMD). It also has an option to visually display and compare the surface under the cumulative ranking (SUCRA) of different treatments. Moreover, nmaplateplot is good at details, including choosing colors, text size, circle size, layout and adding title.

1.1 Quick example: Efficacy and acceptability of 12 Antidepressants

We use a dataset to quickly demonstrate the plate plot.

The ad12.eff.acc dataset contains the point estimates (posterior medians), interval estimates (95% credible intervals), p-values of odds ratios (ORs) for both efficacy and acceptability of 12 antidepressants based on arm-based network meta-analysis.

library(nmaplateplot)
library(svglite)
## Warning: package 'svglite' was built under R version 4.3.3
data("ad12.eff.acc")
plateplot(ad12.eff.acc, design_method = c("circle", "circle"),
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

Let us explain the components of the plate plot:

The upper diagonal part graphically presents ORs for efficacy, while the lower diagonal part graphically presents ORs for acceptability.

Each cell in off-diagonal part contains 2 (for p > 0.05) or 3 (for p < 0.05) concentric circles with white circle (inner circle) representing lower bound of interval estimates if result is significant, grey circle (middle circle) representing point estimates, and outer circle with varying colors representing upper bound of interval estimates. The varying colors are associated with p-values shown in the color bar. The circles’ size is positively associated with (point/interval) estimates.

For example: 1) the plate with (blue/grey/white) color in the 1st row and 12th column cell means MIR is significantly more effective than REB in terms of response rate (efficacy); 2) the plate with (red/grey) color in the 2nd row and 1st column cell means MIR is less acceptable (higher dropout rate) than ESC, though this effect is not statistically significant.

The diagonal texts are names of 12 antidepressant drugs with 2 numbers in each cell standing for SUCRA(%) for efficacy and acceptability of these treatments. The background colors in diagonal part are associated with SUCRA values as shown in the color bar.

In addition to the plate plot which graphically and intuitively displays the NMA results, the package can directly print the point estimates with 95% credible intervals.

# option design_method controls whether you want upper and lower diagonal parts to display "text" or "circle" respectively.
plateplot(ad12.eff.acc, design_method = c("text", "text"),
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

The estimates with p-value < 0.05 are underscored. Symbols “a”, “b” and “c” are added to estimates with p-value < 0.05, < 0.01 and < 0.001 respectively. The varying colors of text are associated with p-values shown in the color bar.

For example: 1) 1.91 (1.41, 2.56) in the 1st row and 12th column cell prints odds of efficacy in the upper-left defined treatment (MIR) compared with odds of efficacy in the lower-right defined treatment (REB); 2) 1.27 (0.98, 1.66) in the 2nd row and 1st column cell prints odds of acceptability in the upper-left defined treatment (MIR) compared with odds of acceptability in the lower-right defined treatment (ESC).

1.2 Input dataset

The input dataset must be a list containing at least 5 data frames named: Point_estimates, Interval_estimates_LB, Interval_estimates_UB, Pvalues, and Treatment_specific_values.

nma_res_minimum <- ad12.eff.acc
nma_res_minimum$Treatment_specific_values$Value_Upper <- NULL
nma_res_minimum$Treatment_specific_values$Value_Lower <- NULL
# This is the minimum input for the plateplot function
nma_res_minimum$Treatment_specific_values
##    Trt_ID Trt_abbrv
## 1       1       BUP
## 2       2       CIT
## 3       3       DUL
## 4       4       ESC
## 5       5       FLU
## 6       6       FVX
## 7       7       MIL
## 8       8       MIR
## 9       9       PAR
## 10     10       REB
## 11     11       SER
## 12     12       VEN
round(nma_res_minimum$Point_estimates,2)
##      V1   V2   V3   V4   V5   V6   V7   V8   V9  V10  V11  V12
## 1  0.00 0.99 1.13 0.83 1.10 1.13 1.18 0.80 1.07 1.53 0.89 0.85
## 2  0.89 0.00 1.14 0.84 1.11 1.14 1.19 0.80 1.08 1.54 0.89 0.86
## 3  1.24 1.39 0.00 0.74 0.97 1.00 1.04 0.71 0.95 1.35 0.78 0.75
## 4  0.87 0.97 0.70 0.00 1.32 1.36 1.42 0.96 1.29 1.83 1.06 1.02
## 5  1.09 1.23 0.88 1.26 0.00 1.03 1.08 0.73 0.98 1.39 0.81 0.78
## 6  1.27 1.42 1.02 1.47 1.16 0.00 1.04 0.71 0.95 1.35 0.78 0.75
## 7  1.25 1.40 1.01 1.45 1.14 0.98 0.00 0.68 0.91 1.30 0.75 0.72
## 8  1.10 1.23 0.89 1.27 1.01 0.86 0.88 0.00 1.35 1.92 1.11 1.07
## 9  1.18 1.32 0.95 1.36 1.08 0.93 0.94 1.07 0.00 1.43 0.83 0.80
## 10 1.42 1.58 1.15 1.64 1.29 1.11 1.13 1.29 1.20 0.00 0.58 0.56
## 11 0.93 1.04 0.75 1.08 0.85 0.73 0.74 0.85 0.79 0.66 0.00 0.96
## 12 1.15 1.29 0.93 1.33 1.05 0.90 0.92 1.04 0.98 0.81 1.23 0.00
round(nma_res_minimum$Interval_estimates_LB,2)
##      V1   V2   V3   V4   V5   V6   V7   V8   V9  V10  V11  V12
## 1  0.00 0.79 0.87 0.68 0.92 0.86 0.85 0.63 0.88 1.15 0.73 0.71
## 2  0.70 0.00 0.88 0.70 0.93 0.88 0.87 0.64 0.90 1.18 0.73 0.71
## 3  0.91 1.02 0.00 0.59 0.77 0.74 0.73 0.54 0.76 0.98 0.61 0.59
## 4  0.70 0.79 0.54 0.00 1.13 1.05 1.04 0.76 1.09 1.40 0.89 0.86
## 5  0.91 1.00 0.68 1.06 0.00 0.82 0.81 0.60 0.85 1.09 0.69 0.68
## 6  0.94 1.05 0.72 1.10 0.89 0.00 0.74 0.54 0.74 0.98 0.61 0.58
## 7  0.90 0.99 0.69 1.05 0.86 0.69 0.00 0.49 0.68 0.89 0.55 0.53
## 8  0.85 0.94 0.64 0.98 0.80 0.65 0.61 0.00 1.10 1.42 0.90 0.87
## 9  0.96 1.06 0.73 1.12 0.93 0.71 0.68 0.85 0.00 1.09 0.70 0.67
## 10 1.03 1.18 0.79 1.20 0.99 0.78 0.75 0.92 0.90 0.00 0.44 0.42
## 11 0.74 0.83 0.55 0.87 0.71 0.55 0.53 0.66 0.65 0.48 0.00 0.81
## 12 0.94 1.02 0.69 1.09 0.90 0.69 0.66 0.83 0.81 0.60 1.01 0.00
round(nma_res_minimum$Interval_estimates_UB,2)
##      V1   V2   V3   V4   V5   V6   V7   V8   V9  V10  V11  V12
## 1  0.00 1.24 1.47 1.02 1.31 1.49 1.63 1.01 1.30 2.06 1.07 1.02
## 2  1.15 0.00 1.47 1.01 1.31 1.48 1.63 1.01 1.30 2.03 1.08 1.05
## 3  1.69 1.89 0.00 0.91 1.21 1.36 1.46 0.93 1.17 1.87 0.99 0.95
## 4  1.08 1.20 0.91 0.00 1.55 1.77 1.94 1.19 1.52 2.44 1.27 1.22
## 5  1.33 1.50 1.17 1.52 0.00 1.30 1.43 0.88 1.12 1.79 0.93 0.89
## 6  1.73 1.92 1.50 1.97 1.51 0.00 1.47 0.91 1.20 1.86 1.00 0.96
## 7  1.79 2.02 1.49 2.05 1.56 1.45 0.00 0.93 1.21 1.86 1.02 0.98
## 8  1.44 1.62 1.23 1.64 1.25 1.17 1.24 0.00 1.64 2.61 1.38 1.31
## 9  1.46 1.64 1.25 1.65 1.24 1.21 1.27 1.34 0.00 1.87 0.98 0.94
## 10 1.97 2.15 1.64 2.24 1.71 1.62 1.69 1.81 1.62 0.00 0.76 0.73
## 11 1.16 1.31 1.02 1.33 1.01 0.97 1.02 1.08 0.96 0.89 0.00 1.14
## 12 1.42 1.62 1.26 1.63 1.22 1.19 1.26 1.32 1.17 1.09 1.51 0.00
round(nma_res_minimum$Pvalues,3)
##       V1    V2    V3    V4    V5    V6    V7    V8    V9   V10   V11   V12
## 1  0.000 0.948 0.353 0.073 0.304 0.367 0.327 0.062 0.491 0.006 0.207 0.087
## 2  0.390 0.000 0.307 0.060 0.251 0.316 0.290 0.061 0.417 0.002 0.247 0.130
## 3  0.165 0.033 0.000 0.006 0.800 0.995 0.803 0.012 0.628 0.068 0.044 0.020
## 4  0.196 0.770 0.008 0.000 0.001 0.020 0.030 0.705 0.004 0.000 0.509 0.797
## 5  0.341 0.046 0.357 0.010 0.000 0.795 0.613 0.001 0.732 0.010 0.004 0.000
## 6  0.116 0.023 0.902 0.012 0.265 0.000 0.812 0.007 0.660 0.066 0.053 0.024
## 7  0.178 0.055 0.966 0.027 0.351 0.932 0.000 0.017 0.515 0.164 0.066 0.036
## 8  0.462 0.125 0.468 0.067 0.956 0.345 0.463 0.000 0.004 0.000 0.336 0.522
## 9  0.120 0.010 0.693 0.002 0.307 0.574 0.689 0.557 0.000 0.009 0.026 0.007
## 10 0.034 0.003 0.472 0.002 0.064 0.564 0.551 0.139 0.215 0.000 0.000 0.000
## 11 0.534 0.733 0.066 0.505 0.066 0.032 0.067 0.179 0.017 0.006 0.000 0.671
## 12 0.175 0.034 0.598 0.006 0.527 0.470 0.596 0.727 0.789 0.178 0.036 0.000
# The text output based on minimum input
plateplot(nma_res_minimum, design_method = c("text", "text"),
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

You may have noticed the inconsistency between the input dataset and the plot: e.g. the values in the 2nd row and 1st column cell of the plot is 1.12 (0.87, 1.46), while according to the input dataset, it seems to be 0.89 (0.68, 1.15). The reason is simple: we use two different types of layouts for input and output respectively.

1.2.1 Two types of layouts: row-column and upper-left lower-right

The dataset you input should follow row-column (rc) layout, which means odds ratio in each cell should stand for odds in the row defined treatment compared with odds in the column defined treatment. This kind of layout is much easier for you to construct input dataset. If you want the output plot to follow this type of layout as well, you can use options transform_rc_ullr_boolean = FALSE.

plateplot(nma_res_minimum, design_method = c("text", "text"),
             transform_rc_ullr_boolean = FALSE,
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

Now you can see the consistency between the input dataset and the plot. If you want choose another layout upper-left lower-right (ullr) for your output (which is the default one and is generally more suitable), you can either choose the default one or use options transform_rc_ullr_boolean = TRUE. This type of layout means that odds ratio should stand for odds in the upper-left defined treatment compared with odds in the lower-right defined treatment.

plateplot(nma_res_minimum, design_method = c("text", "text"),
             transform_rc_ullr_boolean = TRUE,
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

1.2.2 SUCRA values

On top of the minimum input, you can make the plot to graphically display SUCRA values.

# only show SUCRA for lower diagonal part
nma_res_SUCRA_LD <- ad12.eff.acc
nma_res_SUCRA_LD$Treatment_specific_values$Value_Lower <- NULL
plateplot(nma_res_SUCRA_LD, design_method = c("circle", "circle"),
             transform_rc_ullr_boolean = TRUE,
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

# only show SUCRA for upper diagonal part
nma_res_SUCRA_UD <- ad12.eff.acc
nma_res_SUCRA_UD$Treatment_specific_values$Value_Upper <- NULL
plateplot(nma_res_SUCRA_UD, design_method = c("circle", "circle"),
             transform_rc_ullr_boolean = TRUE,
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

# show both, but they are different
nma_res_SUCRA_Bothd <- ad12.eff.acc
plateplot(nma_res_SUCRA_Bothd, design_method = c("circle", "circle"),
             transform_rc_ullr_boolean = TRUE,
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

# show both and they are same
nma_res_SUCRA_Boths <- ad12.eff.acc
nma_res_SUCRA_Boths$Treatment_specific_values$Value_Lower <- 
  nma_res_SUCRA_Boths$Treatment_specific_values$Value_Upper
plateplot(nma_res_SUCRA_Boths, design_method = c("circle", "circle"),
             transform_rc_ullr_boolean = TRUE,
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

1.3 Save the plot

It is recommended to save the plot by setting height at least 6 inches, and dpi at least 600. In addition, we suggested using “pdf”, “tiff”, or “svg” devices to create graphs that can be included in the Latex, Word, or HTML files respectively.

nma_res_minimum <- plateplot(nma_res_minimum, design_method = c("text", "text"),
                                upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")
ggsave("nma_res_minimum.pdf", plot = nma_res_minimum, device = "pdf",
       width = 10, height = 6, dpi = 600)
ggsave("nma_res_minimum.tiff", plot = nma_res_minimum, device = "tiff", compression = "lzw",
       width = 10, height = 6, dpi = 600)
ggsave("nma_res_minimum.svg", plot = nma_res_minimum, device = "svg",
       width = 10, height = 6, dpi = 600)

2 Plotting parameters

2.1 Different types of outcomes

We use two example datasets to show the settings for the function to handle different types of outcomes. The first one is ad12.eff.acc, which contains results of odds ratios for both efficacy (upper diagonal part) and acceptability (lower diagonal part) of 12 antidepressants. The second one (ad12.rr.rd) contains results of risk ratios (upper diagonal part) and risk differences (lower diagonal part) for efficacy of 12 antidepressants.

The first option needs to be considered is lower_better. An array of two logical values for upper and lower diagonal parts respectively. TRUE indicates lower estimates implying better treatment, and vice versa. Hence, we should choose FALSE for efficacy and TRUE for acceptability.

The second option is null_value_zero. An array of two logical values for upper and lower diagonal parts respectively. TRUE indicates the neutral value of estimates is zero, and FALSE indicates the neutral value of estimates is one. Obviously, we should choose FALSE for risk ratio and odds ratio, and choose TRUE for risk difference and standardized mean difference.

data("ad12.rr.rd")
plateplot(ad12.rr.rd,
             null_value_zero = c(FALSE, TRUE), lower_better = c(FALSE, FALSE),
             design_method = c("text", "text"), 
             upper_diagonal_name = "Efficacy: Risk ratio", lower_diagonal_name = "Efficacy: Risk difference")

data("ad12.eff.acc")
plateplot(ad12.eff.acc, 
             null_value_zero = c(FALSE, FALSE), lower_better = c(FALSE, TRUE),
             design_method = c("text", "text"),
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

2.2 Ordering treatments

Although the function will automatically order the treatments based on SUCRA. You can manually control that by specifying the order explicitly.

data("ad12.eff.acc")
ad12.eff.acc$Treatment_specific_values$Order <- c(1:6,12:7)
plateplot(ad12.eff.acc, 
             null_value_zero = c(FALSE, FALSE), lower_better = c(FALSE, TRUE),
             design_method = c("circle", "circle"),
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

2.3 Controlling symbols

The function will give symbols “a”, “b” and “c” based on p-values (< 0.05, < 0.01, and < 0.001 respectively). You can manually control them too. You need to use the alphabet instead of real symbols like ‘*’ and ‘&’.

data("ad12.eff.acc")
ad12.eff.acc$Symbol_indicators <- as.data.frame(matrix(NA, nrow = 12, ncol = 12))
plateplot(ad12.eff.acc, 
             null_value_zero = c(FALSE, FALSE), lower_better = c(FALSE, TRUE),
             design_method = c("text", "text"),
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

2.4 Changing plate (circle) size

You can specify the minimum (and maximum) circle size of upper and lower diagonal parts respectively by plate_circle_minsize and plate_circle_maxsize . Moreover, if you believe upper and lower diagonal should have same function to adjust the circle size, you can set plate_circle_samesize = TRUE.

data("ad12.eff.acc")
plateplot(ad12.eff.acc, design_method = c("circle", "circle"), 
             plate_circle_minsize = c(1.0, 1.0), plate_circle_maxsize = c(8.0, 8.0), 
             plate_circle_samesize = FALSE,
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

2.5 Changing text size

One option only (text_size) controls all the text size in the plot.

plateplot(ad12.rr.rd,
             null_value_zero = c(FALSE, TRUE), lower_better = c(FALSE, FALSE),
             design_method = c("text", "text"), text_size = 2.0,
             upper_diagonal_name = "Efficacy: Risk ratio", lower_diagonal_name = "Efficacy: Risk difference")

2.6 Changing text to the bold face

One option only (bold) controls the bold face in the text plot. The default is FALSE.

plateplot(ad12.rr.rd,
             null_value_zero = c(FALSE, TRUE), lower_better = c(FALSE, FALSE),
             design_method = c("text", "text"), text_size = 2.8, bold = TRUE,
             upper_diagonal_name = "Efficacy: Risk ratio", lower_diagonal_name = "Efficacy: Risk difference")

2.7 Abbreviating long treatment names

Use max_substring to control the length of treatment names.

plateplot(ad12.eff.acc, design_method = c("circle", "circle"), max_substring = 2,
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

2.8 Changing colors to indicate treatment rankings

diagonal_color: an array of 2 color names to define colors for SUCRA=0 and SUCRA=1.

plateplot(ad12.eff.acc, design_method = c("circle", "circle"), 
             diagonal_color = c("white", "green3"),
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

2.9 Changing colors for texts and plate circles

text_and_circle_color: an array of 5 color names (A, B, C, D, E). “(A, B, C)” is used to define varying colors (based on p-values) for texts or circles represent upper bound of interval estimate. “D” is color for circles represent point estimate. “E” is color for circles represent lower bound of interval estimate.

plateplot(ad12.eff.acc, design_method = c("circle", "circle"), 
             text_and_circle_color = c("blue", "white", "red", "grey70", "black"),
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

plateplot(ad12.eff.acc, design_method = c("text", "text"), 
             text_and_circle_color = c("red", "black", "blue"),
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

2.10 Changing background colors for upper and lower diagonal parts

offdiagonal_color: an array of 2 colors for upper and lower diagonal parts.

plateplot(ad12.eff.acc, design_method = c("circle", "circle"), 
             offdiagonal_color = c("cornsilk1", "white"),
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

2.11 Adding the title

plateplot(ad12.eff.acc, design_method = c("circle", "circle"), 
             title = "Efficacy and acceptability of 12 antidepressants",
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

3 Additional examples

3.1 NMA results with missing values

This example dataset contains results of odds ratios for efficacy of 12 antidepressants based on arm-based NMA (upper diagonal part) and pairwise meta-analysis (lower diagonal part).

data("ad12.pma.nma")
plateplot(ad12.pma.nma, design_method = c("circle", "circle"), 
             plate_circle_minsize = c(2, 2), plate_circle_maxsize = c(30, 30), 
             plate_circle_samesize = TRUE,
             upper_diagonal_name = "Network meta-analysis", lower_diagonal_name = "Pairwise meta-analysis")

plateplot(ad12.pma.nma, design_method = c("circle", "text"), 
             upper_diagonal_name = "Network meta-analysis", lower_diagonal_name = "Pairwise meta-analysis")

3.2 Large NMA results (number of treatments is 22)

This example dataset contains results of odds ratios for efficacy (upper diagonal part) and acceptability (lower diagonal part) of 21 antidepressants and placebo.

data("ad22")
plateplot(ad22, design_method = c("circle", "circle"), 
             plate_circle_minsize = c(1.5, 1.5), plate_circle_maxsize = c(7, 7), 
             text_size = 1.5, plate_circle_samesize = FALSE,
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")

plateplot(ad22, design_method = c("text", "text"), text_size = 1.5,
             upper_diagonal_name = "Efficacy", lower_diagonal_name = "Acceptability")