mcguinlu / robvis

A package to quickly visualise risk-of-bias assessment results
https://mcguinlu.github.io/robvis/
Other
58 stars 22 forks source link

PROBAST Risk of Bias visualizations #142

Closed LasaiBarrenada closed 1 year ago

LasaiBarrenada commented 1 year ago

I adapted your rob_traffic_light() function for the Prediction model study Risk Of Bias Assessment Tool (PROBAST). I think this could be useful for other users conducting systematic reviews of prediction models. The code is basically the same but I added an additional argument to let users control the size of the y axis (size_text) and I changed the display of facets in y to horizontal. I think that having an argument to change the angle of the y facet could be interesting otherwhise the study names cannot be displayed if they are a lot of studies. I think that this could be extended to the other functions in the package but I have not done it.

I am not familiar with GitHub collaboration or how issues work so I paste here the code. Let me know if there is a more convenient way for contributing.

rob_traffic_light_lasai <-function (data, tool, colour = "cochrane", psize = 20, quiet = FALSE, size_text = 10) 
{
  judgement <- NULL
  Study <- NULL
  domain <- NULL
  if (tool == "PROBAST") {
    if (length(colour) > 1) {
      low_colour <- colour[c(1)]
      concerns_colour <- colour[c(2)]
      high_colour <- colour[c(3)]
    }
    else {
      if (colour == "colourblind") {
        low_colour <- "#fee8c8"
        concerns_colour <- "#fdbb84"
        high_colour <- "#e34a33"
      }
      if (colour == "cochrane") {
        low_colour <- "#02C100"
        concerns_colour <- "#E2DF07"
        high_colour <- "#BF0000"
      }
    }
    for (i in 2:6) {
      data[[i]] <- tolower(data[[i]])
      data[[i]] <- trimws(data[[i]])
      data[[i]] <- substr(data[[i]], 0, 1)
    }
    data.tmp <- data[, c(1:6)]
    if (NCOL(data.tmp) < 6) {
      stop("Column missing (number of columns < 6).")
    }
    names(data.tmp)[1] <- "Study"
    names(data.tmp)[2] <- "Participants"
    names(data.tmp)[3] <- "Predictors"
    names(data.tmp)[4] <- "Outcome"
    names(data.tmp)[5] <- "Analysis"
    names(data.tmp)[6] <- "Overall"
    rob.tidy <- suppressWarnings(tidyr::gather(data.tmp, 
                                               domain, judgement, -Study))
    ssize <- psize - (psize/4)
    rob.tidy$Study <- factor(rob.tidy$Study, levels = unique(data.tmp$Study))
    rob.tidy$judgement <- as.factor(rob.tidy$judgement)
    rob.tidy$judgement <- factor(rob.tidy$judgement, levels(rob.tidy$judgement)[c(1,4, 3, 2)]) 
    if (length(unique(rob.tidy$judgement)) == 1) {
      adjust_caption <- -1.3
    }
    if (length(unique(rob.tidy$judgement)) == 2) {
      adjust_caption <- -1.9
    }
    if (length(unique(rob.tidy$judgement)) == 3) {
      adjust_caption <- -2.5
    }
    if (length(unique(rob.tidy$judgement)) == 4) {
      adjust_caption <- -3.1
    }
    trafficlightplot <- ggplot2::ggplot(rob.tidy, ggplot2::aes(x = 0.1, 
                                                               y = 1, colour = judgement)) + ggplot2::facet_grid(Study ~ 
                                                                                                                   factor(domain, levels = c("Participants", "Predictors", "Outcome", "Analysis", 
                                                                                                                                              "Overall")),switch = "y",  space = "fixed") + 
      ggplot2::geom_point(size = 6) + ggplot2::geom_point(size = 4, 
                                                          colour = "black", ggplot2::aes(shape = judgement)) + 
      ggplot2::geom_rect(data = rob.tidy[which(rob.tidy$domain != 
                                                 "Overall"), ], fill = "#ffffff", xmin = -Inf, 
                         xmax = Inf, ymin = -Inf, ymax = Inf, show.legend = FALSE) + 
      ggplot2::geom_rect(data = rob.tidy[which(rob.tidy$domain == 
                                                 "Overall"), ], fill = "#d3d3d3", xmin = -Inf, 
                         xmax = Inf, ymin = -Inf, ymax = Inf, show.legend = FALSE) + 
      ggplot2::geom_point(size = psize, show.legend = FALSE) + 
      ggplot2::geom_point(shape = 1, colour = "black", 
                          size = psize, show.legend = FALSE) + ggplot2::geom_point(size = ssize, 
                                                                                   colour = "black", ggplot2::aes(shape = judgement), 
                                                                                   show.legend = FALSE) +  
      ggplot2::scale_x_discrete(position = "top", name = "") + 
      ggplot2::scale_y_continuous(limits = c(1, 1), labels = NULL, 
                                  breaks = NULL, name = "", position = "left") + 
      ggplot2::scale_colour_manual(values = c(h = high_colour, 
                                              u = concerns_colour, l = low_colour), labels = c(h = "High", 
                                                                                               u = "Unclear", l = "Low")) + ggplot2::scale_shape_manual(values = c(h = 120, 
                                                                                                                                                                         u = 45, l = 43), labels = c(h = "High", u = "Unclear", 
                                                                                                                                                                                                     l = "Low")) + ggplot2::scale_size(range = c(5, 20)) + 
      ggplot2::theme_bw() + ggplot2::theme(panel.border = ggplot2::element_rect(colour = "grey"), 
                                           strip.placement = "outside",
                                           panel.spacing = ggplot2::unit(0, "line"), legend.position = "bottom", 
                                           legend.justification = "right", legend.direction = "vertical", 
                                           legend.margin = ggplot2::margin(t = -0.2, r = 0, 
                                                                           b = adjust_caption, l = -10, unit = "cm"), strip.text.x = ggplot2::element_text(size = 10), 
                                           strip.text.y = ggplot2::element_text(angle = 0, 
                                                                                size = size_text), legend.text = ggplot2::element_text(size = 9), 
                                           strip.text.y.left = element_text(angle = 0),
                                           legend.title = ggplot2::element_text(size = 9,angle = 0),
                                           strip.background = ggplot2::element_rect(fill = "#a9a9a9"), 
                                           plot.caption = ggplot2::element_text(size = 10, 
                                                                                hjust = 0, vjust = 1)) + ggplot2::guides(shape = ggplot2::guide_legend(override.aes = list(fill = NA)))+
ggplot2::labs(shape = "Judgement", colour = "Judgement", caption = "\n\n\n\n\n")
    }
  if (quiet != TRUE) {
    return(trafficlightplot)
  }
}
mcguinlu commented 1 year ago

Hey @LasaiBarrenada, thanks for this - PROBAST is a tool I have wanted to include in robvis for a while (see Issue #6 from 2019!), so thanks for encouraging me to finally get to it!

The best practice way to contribute is via a Pull Request/PR (see intro guide here) - it makes it easier for me to review your proposed additions and ensures that you get credit for the code you have written.

If you'd like to open a PR, I'd be very happy to review/support it!


Some responses to your comments

I think that having an argument to change the angle of the y facet could be interesting otherwhise the study names cannot be displayed if they are a lot of studies

The study labels being vertically orientated is a known issue, and a solution is available via #81

an additional argument to let users control the size of the y axis (size_text)

I have intentionally not included this functionality, in favour of allowing users to perform post-hoc adjustments to the image using ggplot2, e.g.:

robvis::rob_traffic_light(data_rob2,
                          tool = "ROB2") +
ggplot2::theme(strip.text.x = ggplot2::element_text(size = 20))
LasaiBarrenada commented 1 year ago

Thanks for the answer Luke, I was not aware that the plot allowed post hoc adjustments. When I have time I will open an issue.