Skip to contents
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

Note: The following code depends on DiagrammeR package. But the generate_dot() and render_graph() functions in that package requires some bug fixes. The fixed version of that package is currently available at github: fenguoerbian/DiagrammeR@generate_dot_edge_attribute. A PR is submitted but hasn’t got merged yet. Otherwise one has to manually setup the dot string

# pak::pkg_install("github::fenguoerbian/DiagrammeR@generate_dot_edge_attribute")
library(DiagrammeR)

Introduction

This vignette shows the BLRM decision flowchart. The diagramme is draw with the R package DiagrammeR and these flowcharts also serve as simple demos on how to use the DiagrammeR package.

Basic BLRM decision flowchart

These following flowcharts is for standard dose escalation stage. Two versions are provided:

  1. Use R’s data.frame to build the diagramme data.

  2. Directly use the dot string to specify the diagramme.

Build the diagramme using R’s data.frame

# ------------ new stop rule for standard escalation part ------------
node_data <- tibble::tribble(
    ~x, ~y, ~rank, ~shape, ~fontsize, ~label,
    1.5,  0, 1, "box",    NA, "BLRM evaluation",
    3.0,  0, 2, "diamond", 6, "All doses toxic",
    3.0, -1, 3, "diamond", 6, "Max number 75 reached",
    3.0, -2, 4, "diamond", 6, "MTD already 12 subj",
    3.0, -3, 5, "diamond", 6, "MTD already 6 subj",
    4.5, -3, 5, "diamond", 6, "Post Pr > 0.5",
    6.0, -3, 5, "box",    NA, "Stop enrollment",
    1.5, -4, 6, "box",    NA, "Enroll another 3 subj"
) %>%
    mutate(id = 1 : n(),
           type = NA_character_,
           .before = everything()) %>%
    as.data.frame()

edge_data <- tibble::tribble(
    ~from, ~to, ~headport, ~tailport, ~label,
    1, 2, NA, NA, NA,
    2, 7, "n", "e", "Yes",
    2, 3, NA, NA, "No",
    3, 7, "n", "e", "Yes",
    3, 4, NA, NA, "No",
    4, 7, "n", "e", "Yes",
    4, 5, NA, NA, "No",
    5, 8, "e", "s", "No",
    5, 6, NA, NA, "Yes",
    6, 7, NA, NA, "Yes",
    6, 8, "e", "s", "No",
    8, 1, NA, NA, NA
) %>%
    mutate(id = 1 : n(),
           rel = NA_character_,
           .before = everything()) %>%
    as.data.frame()

graph <- create_graph() %>%
    add_global_graph_attrs(
        attr = "fixedsize",
        value = "fales",
        attr_type = "node"
    ) %>%
    add_global_graph_attrs(
        attr = "fontsize",
        value = 8,
        attr_type = "node"
    ) %>%
    add_node_df(node_data) %>%
    add_edge_df(edge_data)

Dot string version

# ---- dot string version ----
dot_str <- "
digraph {

graph [layout = 'neato',
       outputorder = 'edgesfirst',
       bgcolor = 'white']

node [fontname = 'Helvetica',
      fontsize = '8',
      shape = 'circle',
      fixedsize = 'false',
      width = '0.5',
      style = 'filled',
      fillcolor = 'aliceblue',
      color = 'gray70']

edge [fontname = 'Helvetica',
     fontsize = '8',
     len = '1.5',
     color = 'gray80',
     arrowsize = '0.5']

  '1' [label = 'BLRM evaluation', shape = 'box', pos = '1.5,0!']
  '2' [label = 'All doses toxic', shape = 'diamond', pos = '3,0!', fontsize = '6']
  '3' [label = 'Maximum number 75 reached', shape = 'diamond', pos = '3,-1!', fontsize = '6']
  '4' [label = 'MTD already 12 subj', shape = 'diamond', pos = '3,-2!', fontsize = '6']
  '5' [label = 'MTD already 6 subj', shape = 'diamond', pos = '3,-3!', fontsize = '6']
  '6' [label = 'Post Pr > 0.5', shape = 'diamond', pos = '4.6,-3!', fontsize = '6']
  '7' [label = 'Stop enrollment', shape = 'box', pos = '6,-3!']
  '8' [label = 'Enroll another 3 subj', shape = 'box', pos = '1.5,-4!']
  '1' [label = 'BLRM evaluation', shape = 'box', pos = '1.5,0!']
  '2' [label = 'All doses toxic', shape = 'diamond', pos = '3,0!']
  '3' [label = 'Maximum number 75 reached', shape = 'diamond', pos = '3,-1!']
  '4' [label = 'MTD already 12 subj', shape = 'diamond', pos = '3,-2!']
subgraph{rank = same
  '5' [label = 'MTD already 6 subj', shape = 'diamond', pos = '3,-3!']
  '6' [label = 'Post Pr > 0.5', shape = 'diamond', pos = '4.6,-3!']
  '7' [label = 'Stop enrollment', shape = 'box', pos = '6,-3!'] }

  '8' [label = 'Enroll another 3 subj', shape = 'box', pos = '1.5,-4!']
'1'->'2' [label = '']
'2'->'7' [label = 'Yes', tailport = 'e', headport = 'n']
'2'->'3' [label = 'No']
'3'->'7' [label = 'Yes', tailport = 'e', headport = 'n']
'3'->'4' [label = 'NO']
'4'->'7' [label = 'Yes', tailport = 'e', headport = 'n']
'4'->'5' [label = 'No']
'5'->'8' [label = 'No', tailport = 's', headport = 'e']
'5'->'6' [label = 'Yes']
'6'->'7' [label = 'Yes']
'6'->'8' [label = 'No', tailport = 's', headport = 'e']
'8'->'1' [label = '']
}
"
grViz(dot_str)

Accelerated titration plus basic BLRM decision flowchart

These following flowcharts is for accelerated titration (AT) stage plus standard dose escalation stage. The AT to standard dose escaltion transition takes place directly and subjects are enrolled to the previous dose without additional BLRM evaluation process. Two versions are provided:

  1. Use R’s data.frame to build the diagramme data.

  2. Directly use the dot string to specify the diagramme.

R data.frame version

# ------------ full stop rule with accelerated titration part ------------
node_data <- tibble::tribble(
    ~x, ~y, ~rank, ~shape, ~fontsize, ~label, ~ width, 
    1.5,  0, 1, "box",    NA, "BLRM evaluation", NA, 
    3.0,  0, 2, "diamond", 6, "All doses toxic", NA, 
    3.0, -1, 3, "diamond", 6, "Max number 75 reached", NA, 
    3.0, -2, 4, "diamond", 6, "MTD already 12 subj", NA, 
    3.0, -3, 5, "diamond", 6, "MTD already 6 subj", NA, 
    4.5, -3, 5, "diamond", 6, "Post Pr > 0.5", NA, 
    6.0, -3, 5, "box",    NA, "Stop enrollment", NA, 
    1.5, -4, 6, "box",    NA, "Enroll 3 subj",  NA, 
    1.5,  1, 0, "box",    NA, "Current dose\n enroll to 3 subj",  NA, 
    0,    1, 0, "diamond",NA, ">=G2 AE",  NA, 
    -1.5, 1, 0, "box",    NA, "Enroll 1 subj", NA,  
    0,    0, 1, "box",    NA, "BLRM evaluation",  NA, 
    0,   -4, 6, "diamond",NA, "reach dose lvl 4",  NA, 
    -2,    1.5, NA, "point", NA, "", 0, 
    0.75,  1.5, NA, "point", NA, "", 0, 
    0.75, -4.5, NA, "point", NA, "", 0, 
    -2,   -4.5, NA, "point", NA, "", 0, 
    0.8,   1.5, NA, "point", NA, "", 0, 
    6.5,   1.5, NA, "point", NA, "", 0, 
    6.5,  -4.5, NA, "point", NA, "", 0, 
    0.8,  -4.5, NA, "point", NA, "", 0,
    -0.625, 1.65, NA, "plaintext", NA, "Accelerated Dose Escalation Phase", NA, 
    3.65, 1.65,  NA, "plaintext", NA, "Standard Dose Escalation Phase", NA
) %>%
    mutate(id = 1 : n(),
           type = NA_character_,
           .before = everything()) %>%
    as.data.frame()

edge_data <- tibble::tribble(
    ~from, ~to, ~headport, ~tailport, ~label, ~ arrowhead, ~style, 
    1, 2, NA, NA, NA, NA, NA, 
    2, 7, "n", "e", "Yes", NA, NA, 
    2, 3, NA, NA, "No", NA, NA,
    3, 7, "n", "e", "Yes", NA, NA,
    3, 4, NA, NA, "No", NA, NA,
    4, 7, "n", "e", "Yes", NA, NA,
    4, 5, NA, NA, "No", NA, NA,
    5, 8, "e", "s", "No", NA, NA,
    5, 6, NA, NA, "Yes", NA, NA,
    6, 7, NA, NA, "Yes", NA, NA,
    6, 8, "e", "s", "No", NA, NA,
    8, 1, NA, NA, NA,  NA, NA,
    11, 10, NA, NA, NA,  NA, NA,
    10, 9, NA, NA, "Yes",  NA, NA,
    10, 12, NA, NA, "No",  NA, NA,
    9, 1, NA, NA, NA,  NA, NA,
    12, 13, NA, NA, NA,  NA, NA,
    13, 8, NA, NA, "Yes",  NA, NA,
    13, 11, NA, "w", "No",  NA, NA,
    14, 15, NA, NA, NA, "none", "dashed", 
    15, 16, NA, NA, NA,  "none", "dashed", 
    16, 17, NA, NA, NA,  "none", "dashed", 
    17, 14, NA, NA, NA, "none", "dashed", 
    18, 19, NA, NA, NA, "none", "dashed", 
    19, 20, NA, NA, NA,  "none", "dashed", 
    20, 21, NA, NA, NA,  "none", "dashed", 
    21, 18, NA, NA, NA, "none", "dashed", 
) %>%
    mutate(id = 1 : n(),
           rel = NA_character_,
           .before = everything()) %>%
    as.data.frame()


graph <- create_graph() %>%
    add_global_graph_attrs(
        attr = "splines",
        value = "splines",
        attr_type = "graph") %>%
    add_global_graph_attrs(
        attr = "fixedsize",
        value = "fales",
        attr_type = "node"
    ) %>%
    add_global_graph_attrs(
        attr = "fontsize",
        value = 8,
        attr_type = "node"
    ) %>%
    add_node_df(node_data) %>%
    add_edge_df(edge_data) %>%
    select_nodes_by_id(
        nodes = c(22, 23)
    ) %>%
    set_node_attrs_ws(
        node_attr = "style", 
        value = "solid"
    )

Dot string version

# ---- dot string version ----
dot_str <- "
digraph {

graph [layout = 'neato',
       outputorder = 'edgesfirst',
       bgcolor = 'white',
       splines = 'splines']

node [fontname = 'Helvetica',
      fontsize = '8',
      shape = 'circle',
      fixedsize = 'fales',
      width = '0.5',
      style = 'filled',
      fillcolor = 'aliceblue',
      color = 'gray70',
      fontcolor = 'gray50']

edge [fontname = 'Helvetica',
     fontsize = '8',
     len = '1.5',
     color = 'gray80',
     arrowsize = '0.5']

  '1' [label = 'BLRM evaluation', shape = 'box', fontsize = '8', width = '0.5', pos = '1.5,0!'] 
  '2' [label = 'All doses toxic', shape = 'diamond', fontsize = '6', width = '0.5', pos = '3,0!'] 
  '3' [label = 'Max number 75 reached', shape = 'diamond', fontsize = '6', width = '0.5', pos = '3,-1!'] 
  '4' [label = 'MTD already 12 subj', shape = 'diamond', fontsize = '6', width = '0.5', pos = '3,-2!'] 
  '5' [label = 'MTD already 6 subj', shape = 'diamond', fontsize = '6', width = '0.5', pos = '3,-3!'] 
  '6' [label = 'Post Pr > 0.5', shape = 'diamond', fontsize = '6', width = '0.5', pos = '4.5,-3!'] 
  '7' [label = 'Stop enrollment', shape = 'box', fontsize = '8', width = '0.5', pos = '6,-3!'] 
  '8' [label = 'Enroll 3 subj', shape = 'box', fontsize = '8', width = '0.5', pos = '1.5,-4!'] 
  '9' [label = 'Current dose
 enroll to 3 subj', shape = 'box', fontsize = '8', width = '0.5', pos = '1.5,1!'] 
  '10' [label = '>=G2 AE', shape = 'diamond', fontsize = '8', width = '0.5', pos = '0,1!'] 
  '11' [label = 'Enroll 1 subj', shape = 'box', fontsize = '8', width = '0.5', pos = '-1.5,1!'] 
  '12' [label = 'BLRM evaluation', shape = 'box', fontsize = '8', width = '0.5', pos = '0,0!'] 
  '13' [label = 'reach dose lvl 4', shape = 'diamond', fontsize = '8', width = '0.5', pos = '0,-4!'] 
  '14' [label = '', shape = 'point', fontsize = '8', width = '0', pos = '-2,1.5!'] 
  '15' [label = '', shape = 'point', fontsize = '8', width = '0', pos = '0.75,1.5!'] 
  '16' [label = '', shape = 'point', fontsize = '8', width = '0', pos = '0.75,-4.5!'] 
  '17' [label = '', shape = 'point', fontsize = '8', width = '0', pos = '-2,-4.5!'] 
  '18' [label = '', shape = 'point', fontsize = '8', width = '0', pos = '0.8,1.5!'] 
  '19' [label = '', shape = 'point', fontsize = '8', width = '0', pos = '6.5,1.5!'] 
  '20' [label = '', shape = 'point', fontsize = '8', width = '0', pos = '6.5,-4.5!'] 
  '21' [label = '', shape = 'point', fontsize = '8', width = '0', pos = '0.8,-4.5!'] 
  '22' [label = 'Accelerated Dose Escalation Phase', shape = 'plaintext', fontsize = '8', width = '0.5', pos = '-0.625,1.75!', style = 'solid'] 
  '23' [label = 'Standard Dose Escalation Phase', shape = 'plaintext', fontsize = '8', width = '0.5', pos = '3.65,1.75!', style = 'solid'] 
subgraph{rank = same
  '9' [label = 'Current dose
 enroll to 3 subj', shape = 'box', fontsize = '8', width = '0.5', pos = '1.5,1!'] 
  '10' [label = '>=G2 AE', shape = 'diamond', fontsize = '8', width = '0.5', pos = '0,1!'] 
  '11' [label = 'Enroll 1 subj', shape = 'box', fontsize = '8', width = '0.5', pos = '-1.5,1!'] }

subgraph{rank = same
  '1' [label = 'BLRM evaluation', shape = 'box', fontsize = '8', width = '0.5', pos = '1.5,0!'] 
  '12' [label = 'BLRM evaluation', shape = 'box', fontsize = '8', width = '0.5', pos = '0,0!'] }

  '2' [label = 'All doses toxic', shape = 'diamond', fontsize = '6', width = '0.5', pos = '3,0!'] 
  '3' [label = 'Max number 75 reached', shape = 'diamond', fontsize = '6', width = '0.5', pos = '3,-1!'] 
  '4' [label = 'MTD already 12 subj', shape = 'diamond', fontsize = '6', width = '0.5', pos = '3,-2!'] 
subgraph{rank = same
  '5' [label = 'MTD already 6 subj', shape = 'diamond', fontsize = '6', width = '0.5', pos = '3,-3!'] 
  '6' [label = 'Post Pr > 0.5', shape = 'diamond', fontsize = '6', width = '0.5', pos = '4.5,-3!'] 
  '7' [label = 'Stop enrollment', shape = 'box', fontsize = '8', width = '0.5', pos = '6,-3!'] }

subgraph{rank = same
  '8' [label = 'Enroll 3 subj', shape = 'box', fontsize = '8', width = '0.5', pos = '1.5,-4!'] 
  '13' [label = 'reach dose lvl 4', shape = 'diamond', fontsize = '8', width = '0.5', pos = '0,-4!'] }

'1'->'2'
'2'->'7' [headport = 'n', tailport = 'e'] 
'2'->'3'
'3'->'7' [headport = 'n', tailport = 'e'] 
'3'->'4'
'4'->'7' [headport = 'n', tailport = 'e'] 
'4'->'5'
'5'->'8' [headport = 'e', tailport = 's'] 
'5'->'6'
'6'->'7'
'6'->'8' [headport = 'e', tailport = 's'] 
'8'->'1'
'11'->'10'
'10'->'9'
'10'->'12'
'9'->'1'
'12'->'13'
'13'->'8'
'13'->'11' [tailport = 'w'] 
'14'->'15' [arrowhead = 'none', style = 'dashed'] 
'15'->'16' [arrowhead = 'none', style = 'dashed'] 
'16'->'17' [arrowhead = 'none', style = 'dashed'] 
'17'->'14' [arrowhead = 'none', style = 'dashed'] 
'18'->'19' [arrowhead = 'none', style = 'dashed'] 
'19'->'20' [arrowhead = 'none', style = 'dashed'] 
'20'->'21' [arrowhead = 'none', style = 'dashed'] 
'21'->'18' [arrowhead = 'none', style = 'dashed'] 
}
"
grViz(dot_str)