MetaInsight v7

MetaInsight v7: A Comprehensive and Reproducible Shiny App for Network Meta-analysis

Simon Smart

7th May 2026

About me

  • Software developer in Biostatistics group at University of Leicester
  • Background in agricultural science
  • Developing Shiny apps since 2018

Overview

  • What is network meta-analysis?
  • History of MetaInsight
  • Aims for v7
  • Demonstration of new features
  • How challenges were addressed

Network meta-analysis can help determine the ‘best’ treatment option

Network of six treatments where there are different numbers of trials that compared each pair

Line graph showing the output of an analysis where each treatment is ranked by outcome

Complex meta-analyses require extensive statistical and programming knowledge

  • {BUGSnet}, {bnma}, {coda}, {gemtc}, {meta}, {metafor}, {netmeta}
  • JAGS may be hard to install
  • Require data in different formats and use different terminology

Shiny removes barriers for accessing cutting-edge methods

  • MetaInsight was developed to make NMA more accessible
  • Originally developed by statisticians, but increasingly in collaboration with developers

Line graph showing cumulative citations of Owen 2019 since 2020, now a total of 300

MetaInsight has a global userbase

Sensitivity analyses can be run in parallel to the main analysis

Forest plot showing results for all the studies included

Forest plot showing results with some studies excluded

The ‘black box’ nature of apps can limit uptake

  • Open science principles require that code can be rerun
  • NICE require that NMAs are reproducible

Screenshot of NICE report showing WinBUGS code

shinyscholar was developed to address this

  • Forked from {wallace} to make development of reproducible apps easier
  • Convert into functions and package
  • App becomes interface to functions, dealing with interactivity

Hex logo of shinyscholar showing a black and white mortar cap

Aims for version 7

  • Make analyses reproducible
  • Upload risk of bias data
  • Improve quality and consistency of downloaded plots
  • Produce a downloadable report
  • Maintain user experience

Various adjustments were made to the shinyscholar template

  • Multiple parallel analyses
  • Maintain functionality of excluding studies at any point
  • Once run, modules should update automatically

Screenshot of the existing app highlighting a menu of options that is always visible

Screenshot of the existing app highlighting three layers of nested nav panels

Incorporating risk of bias scores improves sensitivity analyses

  • During reviews, risk of bias information can be collected e.g.
    • Randomisation, blinding, missing data
  • Scores can guide sensitivity analyses

Forest plot summarising study results and showing risk of bias scores

Integration with CINeMA helps to evaluate confidence in findings

Cinema logo

  • Uses risk of bias scores for studies to evaluate evidence for treatments

Network plot as in the first slide but with the nodes between each treatment pair coloured according to the risk of bias

Previously studies were excluded by clicking in the sidebar

Screenshot showing existing interface for excluding studies from an analysis with a datatable and separate list of checkbox inputs

A new interface has been developed to exclude studies

  • The table has been replaced with the summary forest plot but which is interactive
  • Clicking on a row excludes or includes the study

Slow tasks run in the background

  • Fitting models can block the app for other users
  • Uses shiny::ExtendedTask() and mirai::mirai()
  • Spinner appears whilst waiting
  • Can be cancelled

Uploaded datasets can create difficulties

  • Contain errors which could crash the app
  • Number of studies and treatments can vary
  • Treatment and study names can vary in length

Network plot that is unreadable due to the excessive number of treatments

Producing publication-ready figures

  • Ideally plots are ready to use in publications
  • Reuse plots from other packages, others custom-built
  • Mixture of base plots, {grid} and {ggplot2}

Screenshot of the existing app

Screenshot of the existing app

Screenshot of the existing app

Screenshot showing forest plots that are cutoff on small screens

Some downloaded plots had wide margins and low resolution

Forest plot downloaded from existing app showing wide white borders and low resolution

Plots are now all produced using a consistent workflow

  • Functions generate SVGs
  • In app they squash and stretch freely
  • Enables fullscreen viewing
  • Can all be rendered to png, pdf or saved as svg
  • Enables testing of reproducibility

Reproducibility relies on a strict structure

  • Each module has an id made up of the component and module summary_network
  • Each calls a synonymous function summary_network()
  • Input values are stored in common$meta$summary_network$<input id>
  • Values are knitted into an .Rmd chunk and combined to create a .qmd

Reproducibility relies on a strict structure

```{asis, echo = {{summary_network_knit}, eval = {{summary_network_knit}}, include = {{summary_network_knit}}}}
### Display the networks for the original data and data with excluded studies.
```
```{r, echo = {{summary_network_knit}, include = {{summary_network_knit}}}}
summary_network(configured_data,
                {{summary_network_style}}, 
                {{summary_network_label_all}}, 
                "Network plot of all studies")
```
### Display the networks for the original data and data with excluded studies.

```{r}
summary_network(configured_data, 
                "netplot", 
                1, 
                "Network plot of all studies")
```

Reproducibility also enables improved reporting

  • Use as the basis for writing a publication
  • Rendered in the app to produce an html report

Screenshot of the an html report produced by the app

Analyses can also be saved to a file

  • Can be restored later on
  • Share with colleagues
  • Access the data / models for further analysis

The app can also be run locally

install.packages("metainsight")
library(metainsight)
run_metainsight()

run_metainsight(load_file = "saved_file.rds")

Analyses can also be conducted without the app

configured_data <- setup_load("my_data.csv", outcome = "continuous") |>
  setup_configure(reference_treatment = "Placebo",
                  effects = "random",
                  outcome_measure = "MD",
                  ranking_option = "good",
                  seed = 123)

Analyses can also be conducted without the app

freq_forest(configured_data) |> 
  write_plot("frequentist_forest_plot.pdf")

bayes_model(configured_data) |> 
  bayes_forest() |>
  write_plot("bayesian_forest_plot.pdf")

Unit tests check that functions perform as expected

result <- setup_exclude(configured_data_con, c("Leo"))
expect_false("Leo" %in% result$connected_data$Study)

End-to-end tests that the app functions

app <- shinytest2::AppDriver$new(system.file("shiny", package = "metainsight"))
...
click_setup_exclude(app, "Leo")
exclusions <- app$get_value(input = "setup_exclude-exclusions")
expect_equal(exclusions, c("Leo"))

User feedback is important for developing new features

Github screenshot of user making feature request for bulk downloads, svg downloads, automatic x axis limits and reproducible models

Acknowledgments

  • Naomi Bradbury, Ryan Field, Tom Morris, Clareece Nevill, Janion Nevill, Alex Sutton, Nicola Cooper, Suzanne Freeman
  • Wellcome (via Chan Zuckerburg Initiative)
  • NIHR
  • Email, Github, Bluesky

CRSU logo Wellcome logo NIHR logo