---
title: "Post-editting forestplot"
author: "Alimu Dayimu"
date: "`r Sys.Date()`"
output: 
  rmarkdown::html_vignette:
    toc: yes
vignette: >
  %\VignetteIndexEntry{Post-editting forestplot}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  dpi=300,
  comment = "#>"
)
```



# Principle

The layout of the forest plot is determined by the dataset provided. All the elements of the forest plot are placed in the cells. This makes it very easy to edit any elements in the plot given the row and columns. The graphical parameters of the element can further be edited in the particular cell. Here, we will start with a simple meta-analysis forest plot.   

The plotting steps demonstrated in this vignette may not necessarily be optimal. There are other R packages out there that are better at the plot demonstrated here. Please choose the best one that suits you. Our final plot is shown in the below.

```{r final-plot, out.width = '95%', echo = FALSE}
knitr::include_graphics("img/metaplot.png")
```


# Draw a forest plot
We will start drawing a forest plot with an example from [metafor](https://www.metafor-project.org/doku.php/plots:forest_plot_revman), which is similar to the plot above. We first load the data and draw a simple forest plot.

```{r meta-forest, out.width="95%", fig.width  = 10.6, fig.height = 3.6}
library(grid)
library(forestploter)

# Read meta-analysis example data
dt <- read.csv(system.file("extdata", "metadata.csv", package = "forestploter"))

str(dt)

# Prepare a blank column for the CI
dt$cicol <- paste(rep(" ", 20), collapse = " ")

# Select some columns for plotting, this will be used as a skeleton of the forest plot
dt_fig <- dt[,c(1:7, 17, 8:13)]

colnames(dt_fig) <- c("Study or Subgroup",
                      "Events","Total","Events","Total",
                      "Weight",
                      "", "",
                      LETTERS[1:6])

dt_fig$Weight <- sprintf("%0.1f%%", dt_fig$Weight)
dt_fig$Weight[dt_fig$Weight == "NA%"] <- ""

# Convert NA to a blank string
dt_fig[is.na(dt_fig)] <- ""

# Background to white and summary diamond to black
tm <- forest_theme(core = list(bg_params=list(fill = c("white"))),
                   summary_col = "black",
                   arrow_label_just = "end",
                   arrow_type = "closed")

p <- forest(dt_fig,
            est = dt$est,
            lower = dt$lb, 
            upper = dt$ub,
            sizes = sqrt(dt$weights/100),
            is_summary = c(rep(F, nrow(dt)-1), T),
            ci_column = 8,
            ref_line = 1,
            x_trans = "log",
            arrow_lab = c("Favours caffeine","Favours decaf"),
            xlim = c(0.05, 100),
            ticks_at = c(0.1, 1, 10, 100),
            theme = tm)
p


```


# Editing forest plot

The package has some functionality to modify the forest plot. Below are the functions to edit various aspects of the plot:

* The `edit_plot` function can be used to change the graphical parameter of text, background, and CI. For example the color or font face of some cells. Other parameters controlling the background and text can be passed, the position of the text for example.
* The `add_text` function can be used to add text to certain rows/columns. If you want a complicated text-align, you can leave some rows and/or columns blank and use this function to add the text.
* The `insert_text` function can be used to insert a row before or after a certain row and add text. This function can be used to insert text between groups. The idea is to draw all data and insert text after some rows to separate groups.
* The `add_border` function can be used to add a border to a specific cell.
* The `add_grob` function can be used to add different grobs.

## Edit plot
Below is to make the total row text bold and change the color of the diamond shape. Then change the background color of the total row. After that, align texts in the last six columns to the center. 
```{r edit-metaplot, out.width="95%", fig.width  = 10.6, fig.height = 3.6}
# Change font face
g <- edit_plot(p, row = 9, 
               gp = gpar(fontface = "bold"))

# Change color
g <- edit_plot(g, col = 8, row = 9, which = "ci", 
          gp = gpar(col = "blue", fill = "blue"))

# Change the background of the total row
g <- edit_plot(g, col = 1:7, 
               row = 9, 
               which = "background", 
               gp = gpar(fill = "#f6eff7"))

# Align texts to center
g <- edit_plot(g, col = 9:14, 
               which = "text",
               # gp = gpar(),
               hjust = unit(0.5, "npc"),
               x = unit(0.5, "npc"))
g

```


For the text-align, `hjust = unit(0, "npc")` and `x = unit(0, "npc")` to align left. `hjust = unit(0.5, "npc")` and `x = unit(0.5, "npc")` to align the text in the center. `hjust = unit(1, "npc")` and `x = unit(0.9, "npc")` to align right.


## Add and insert text
In this step, we want to add some text to the header and total number of events in the data.

```{r text-metaplot, out.width="95%", fig.width  = 10.6, fig.height = 3.6}
# Add or insert some text to the header on top of CI columns
g <- add_text(g, text = "IV, Random, 95% CI",
              part = "header", 
              col = 7:8,
              gp = gpar(fontface = "bold"))

g <- insert_text(g, text = "Odds ratio",
                 part = "header", 
                 col = 7:8,
                 gp = gpar(fontface = "bold"))

# Group outcomes
g <- add_text(g, text = "Caffeine",
              part = "header",
              row = 1,
              col = 2:3,
              gp = gpar(fontface = "bold"))

g <- add_text(g, text = "Decaf",
              part = "header", 
              row = 1,
              col = 4:5,
              gp = gpar(fontface = "bold"))

# Add text on the top of the risk of bias data
g <- add_text(g, text = "Risk of Bias",
              part = "header", 
              row = 1,
              col = 9:14,
              gp = gpar(fontface = "bold"))

# Insert event count
g <- insert_text(g, 
                 text = c("Total events:"),
                 row = 9,
                 col = 1,
                 before = FALSE,
                 just = "left")

# Note: The row counts need to add one to account for 
# `insert_text` in the previous step
g <- add_text(g, text = "58",
              col = 2,
              row = 10,
              just = "left")

g <- add_text(g, text = "46",
              col = 4,
              row = 10,
              just = "left")

g
```

## Add borders
In the next step, we will add some borders at the header. The default is to add a border at the bottom of the cell(s).
```{r border-metaplot, out.width="95%", fig.width  = 10.6, fig.height = 3.6}
# Add or insert some text to the header
g <- add_border(g, 
                part = "header", 
                row = 1,
                col = 9:14,
                gp = gpar(lwd = .5))

g <- add_border(g, 
                part = "header", 
                row = 2,
                gp = gpar(lwd = 1))

g

```


## Add grobs
In the next step, we will add a rounded rectangle border with a dashed line around the risk of bias data. Then draw a circle grob with different colors at the bottom of the text.
```{r grob-metaplot, out.width="95%", fig.width  = 10.6, fig.height = 3.6}
g <- add_grob(g, 
              row = 1:c(nrow(dt_fig) - 1), 
              col = 9:14,
              order = "background",
              gb_fn = roundrectGrob,
              r = unit(0.05, "snpc"),
              gp = gpar(lty = "dotted",
                        col = "#bdbdbd"))

# Draw a circle grob, you can also draw a `pointsGrob`
cols <- c("#eeee00", "#00cc00", "#cc0000")
symb <- c("?", "+", "-")
for(i in seq_along(symb)){
  pos <- which(dt_fig == symb[i], arr.ind=TRUE)
  for(j in 1:nrow(pos)){
    g <- add_grob(g, 
                  row = pos[j,1], 
                  col = pos[j,2],
                  order = "background",
                  gb_fn = circleGrob,
                  r = 0.4,
                  gp = gpar(fill = cols[i]))
  }
}

g

```

The text we are going to create involves math expressions and multiple lines. Any one of these can easily be done with `add_text` and setting `parse=TRUE`. We can use the code below to achieve what we want. The line break below is based on the solution [here](https://stackoverflow.com/questions/18237134/line-break-in-expression) using the `atop` function. You can also use [latex2exp](https://CRAN.R-project.org/package=latex2exp) package for math expression.

```{r txtgrob-metaplot, out.width="95%", fig.width  = 10.6, fig.height = 3.6}
txt <- bquote(atop(paste("Heterogeneity: ", tau^2, " = 0.22; ",
                         chi^2, " = 9.39, df = 6 (P = 0.15)",
                         I^2, " = 36%"),
            "Total for overall effect: Z = 1.15(P=0.25)"))

add_text(g, text = txt,
         col = 1:6,
         row = 11,
         just = "left",
         parse = TRUE,
         gp = gpar(fontsize = 8))
```

We can see that the second line is not left aligned, we can use `add_grob` to take advantage of other packages that create `grobs` objects. Now we will use the
[gridtext](https://CRAN.R-project.org/package=gridtext) package to generate a complex text and add it to the plot with `add_grob`. More details about the package can be found [here](https://wilkelab.org/gridtext/index.html). You can write markdown or HTML text and render it to the plot. Currently, it does not support math equations. See other Unicode math symbols [here](https://www.stat.auckland.ac.nz/~paul/R/CM/AdobeSym.html)

```{r gridtext-metaplot, out.width="95%", fig.width  = 10.6, fig.height = 3.6}
txt <- "Heterogeneity: &tau;<sup>2</sup> = 0.22; &chi;<sup>2</sup> = 9.39,
df=6 (P=0.15);I<sup>2</sup> = 36%<br><span style='color:blue'>**Total for overall effect:**</span> Z = 1.15(P=0.25)"

add_grob(g, 
         row = 11, 
         col = 1:6,
         order = "background",
         gb_fn = gridtext::richtext_grob,
         text = txt,
         gp = gpar(fontsize = 8),
         hjust = 0, vjust = 1, halign = 0, valign = 1,
         x = unit(0, "npc"), y = unit(1, "npc"))

```


