Create CONSORT Diagram using R package DiagrammeR

  1. dir=none on exclusion edges makes them side branches (no arrows).

  2. shape = note and fillcolor = mistyrose give a “note” look for exclusions.

  3. Section labels are positioned using invisible edges.

library(DiagrammeR)

gr<-grViz("
digraph flowchart {

  graph [layout = dot, rankdir = TB]

  # Node defaults
  node [shape = box, style = filled, fillcolor = lightgray, fontname = Helvetica]

  # Main flow nodes
  study1 [label = 'Study 1 (n=160)']
  study2 [label = 'Study 2 (n=140)']
  population [label = 'Population (n=300)']
  exclusion_pop [label = 'Excluded (n=15)\\n• MRI not collected (n=3)\\n• Tissues not collected (n=4)\\n• Other (n=8)', shape = note, fillcolor = mistyrose]

  randomized [label = 'Randomized (n=200)']
  armA [label = 'Arm A (n=100)']
  armB [label = 'Arm B (n=100)']

  exclusion_A [label = 'Excluded (n=15)\\n• MRI not collected (n=3)\\n• Tissues not collected (n=4)\\n• Other (n=8)', shape = note, fillcolor = mistyrose]
  exclusion_B [label = 'Excluded (n=7)\\n• MRI not collected (n=3)\\n• Tissues not collected (n=4)', shape = note, fillcolor = mistyrose]

  final_A [label = 'Final analysis (n=85)']
  final_B [label = 'Final analysis (n=93)']

  # Section labels (plaintext nodes)
  label_screening [label = 'Screening', shape = plaintext, fontsize = 12]
  label_randomized [label = 'Randomized', shape = plaintext, fontsize = 12]
  label_final [label = 'Final analysis', shape = plaintext, fontsize = 12]

  # Rank groups
  { rank = same; study1; study2 }
  { rank = same; armA; armB }
  { rank = same; final_A; final_B }

  # Edges
  study1 -> population
  study2 -> population
  population -> exclusion_pop [dir=none]
  population -> randomized

  randomized -> armA
  randomized -> armB

  armA -> exclusion_A [dir=none]
  armB -> exclusion_B [dir=none]

  armA -> final_A
  armB -> final_B

  # Invisible edges to help label positioning
  label_screening -> population [style = invis]
  label_randomized -> randomized [style = invis]
  label_final -> final_A [style = invis]

}
")

Save as TIFF by first Saving to high resolution png

# Export to SVG
svg_code <- export_svg(gr)

# Save as high-res PNG
rsvg_png(charToRaw(svg_code), file = "flowchart.png", width = 2000, height = 1200)

# Convert PNG to TIFF using magick
img <- image_read("flowchart.png")
image_write(img, path = "flowchart.tiff", format = "tiff", density = "300x300")