Title: | Create Consort Diagram |
---|---|
Description: | To make it easy to create CONSORT diagrams for the transparent reporting of participant allocation in randomized, controlled clinical trials. This is done by creating a standardized disposition data, and using this data as the source for the creation a standard CONSORT diagram. Human effort by supplying text labels on the node can also be achieved. |
Authors: | Alim Dayim [aut, cre] |
Maintainer: | Alim Dayim <[email protected]> |
License: | MIT + file LICENSE |
Version: | 1.2.2 |
Built: | 2025-02-06 21:16:30 UTC |
Source: | https://github.com/adayim/consort |
To make it easy to create CONSORT diagrams for the transparent reporting of participant allocation in randomized, controlled clinical trials. This is done by creating a standardized disposition data, and using this data as the source for the creation a standard CONSORT diagram. Human effort by supplying text labels on the node can also be achieved.
Create/add vertically aligned labeled nodes or side nodes.
add_box( prev_box = NULL, txt, just = c("center", "left", "right"), text_width = NULL, ... )
add_box( prev_box = NULL, txt, just = c("center", "left", "right"), text_width = NULL, ... )
prev_box |
Previous node object, the created new node will be vertically aligned with this node. Left this as 'NULL' if this is the first node. The first node will be aligned in the top center. |
txt |
Text in the node. If the 'prev_box' is a horizontally aligned multiple nodes, a vector of with the same length must be provided. |
just |
The justification for the text: left, center or right. |
text_width |
a positive integer giving the target column for wrapping
lines in the output. String will not be wrapped if not defined (default).
The |
... |
Other parameters pass to textbox, |
A consort
object.
add_side_box
add_split
textbox
add_label_box
txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") g <- add_split(g, txt = c("Arm A (n=100)", "Arm B (n=100")) g <- add_side_box(g, txt = c( "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)", "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)" ) ) g <- add_box(g, txt = c("Final analysis (n=100)", "Final analysis (n=100")) g <- add_label_box(g, txt = c("1" = "Screening", "3" = "Randomized", "4" = "Final analysis"))
txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") g <- add_split(g, txt = c("Arm A (n=100)", "Arm B (n=100")) g <- add_side_box(g, txt = c( "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)", "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)" ) ) g <- add_box(g, txt = c("Final analysis (n=100)", "Final analysis (n=100")) g <- add_label_box(g, txt = c("1" = "Screening", "3" = "Randomized", "4" = "Final analysis"))
In a consort diagram, this can be used to indicate different stage.
add_label_box( prev_box, txt, only_terminal = TRUE, just = c("center", "left", "right"), ... )
add_label_box( prev_box, txt, only_terminal = TRUE, just = c("center", "left", "right"), ... )
prev_box |
A completed diagram created with |
txt |
Text in the node. If a character string is provided, the label will be aligned to the last box if a character is provided. If a named vector, the labels will align to corresponding row of the node. And the names is the number indicating row number of box to horizontally align with and value is the text in the box. |
only_terminal |
If the txt is only for the terminal box, default. Otherwise, the side box will also be accounted for. |
just |
The justification for the text: center (default), left or right. |
... |
Other parameters pass to textbox, |
A consort
object.
add_side_box
add_split
textbox
add_box
txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") g <- add_split(g, txt = c("Arm A (n=100)", "Arm B (n=100")) g <- add_side_box(g, txt = c( "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)", "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)" ) ) g <- add_box(g, txt = c("Final analysis (n=100)", "Final analysis (n=100")) g <- add_label_box(g, txt = c("1" = "Screening", "3" = "Randomized", "4" = "Final analysis"))
txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") g <- add_split(g, txt = c("Arm A (n=100)", "Arm B (n=100")) g <- add_side_box(g, txt = c( "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)", "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)" ) ) g <- add_box(g, txt = c("Final analysis (n=100)", "Final analysis (n=100")) g <- add_label_box(g, txt = c("1" = "Screening", "3" = "Randomized", "4" = "Final analysis"))
Add an exclusion node on the right side. If the length of text label is two, then the first one will be aligned on the left and the second on the right. Otherwise, all the side nodes will be aligned on the right.
add_side_box(prev_box, txt, side = NULL, text_width = NULL, ...)
add_side_box(prev_box, txt, side = NULL, text_width = NULL, ...)
prev_box |
Previous node object, the created new node will be aligned at the right bottom of the 'prev_box'. |
txt |
Text in the node. If the 'prev_box' is a horizontally aligned multiple nodes, a vector of with the same length must be provided. |
side |
Position of the side box, 'left' or 'right' side of the terminal box. Will be aligned on the left and right side if only two groups, right otherwise. This will be ignored for for 'grViz' plot, see grViz. |
text_width |
a positive integer giving the target column for wrapping
lines in the output. String will not be wrapped if not defined (default).
The |
... |
Other parameters pass to textbox, |
A consort
object.
add_box
add_split
textbox
add_label_box
txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") g <- add_split(g, txt = c("Arm A (n=100)", "Arm B (n=100")) g <- add_side_box(g, txt = c( "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)", "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)" ) ) g <- add_box(g, txt = c("Final analysis (n=100)", "Final analysis (n=100")) g <- add_label_box(g, txt = c("1" = "Screening", "3" = "Randomized", "4" = "Final analysis"))
txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") g <- add_split(g, txt = c("Arm A (n=100)", "Arm B (n=100")) g <- add_side_box(g, txt = c( "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)", "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)" ) ) g <- add_box(g, txt = c("Final analysis (n=100)", "Final analysis (n=100")) g <- add_label_box(g, txt = c("1" = "Screening", "3" = "Randomized", "4" = "Final analysis"))
This function will create a horizontally aligned nodes. The horizontal coordinate will be automatically calculated if the coordinates not provided.
add_split( prev_box, txt, just = c("center", "left", "right"), text_width = NULL, ... )
add_split( prev_box, txt, just = c("center", "left", "right"), text_width = NULL, ... )
prev_box |
Previous node that the newly created split box will be aligned. |
txt |
Text in the node. If the 'prev_box' is a horizontally aligned multiple nodes, a vector of with the same length must be provided. |
just |
The justification for the text: left, center or right. |
text_width |
a positive integer giving the target column for wrapping
lines in the output. String will not be wrapped if not defined (default).
The |
... |
Other parameters pass to textbox, |
A consort.list
object.
txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") g <- add_split(g, txt = c("Arm A (n=100)", "Arm B (n=100")) g <- add_side_box(g, txt = c( "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)", "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)" ) ) g <- add_box(g, txt = c("Final analysis (n=100)", "Final analysis (n=100")) g <- add_label_box(g, txt = c("1" = "Screening", "3" = "Randomized", "4" = "Final analysis"))
txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") g <- add_split(g, txt = c("Arm A (n=100)", "Arm B (n=100")) g <- add_side_box(g, txt = c( "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)", "Excluded (n=15):\n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)" ) ) g <- add_box(g, txt = c("Final analysis (n=100)", "Final analysis (n=100")) g <- add_label_box(g, txt = c("1" = "Screening", "3" = "Randomized", "4" = "Final analysis"))
Build a grob
consort diagram, use this if you want
to save plots with ggsave
. build_grid
does not support multiple split for the moment, please use
build_grviz
or plot(g, grViz = TRUE)
for
multiple split nodes instead.
build_grid(x)
build_grid(x)
x |
A conosrt object. |
A gList
object
## Not run: txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") # g <- ggsave("consort_diagram.pdf", plot = build_grid(g)) ## End(Not run)
## Not run: txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") # g <- ggsave("consort_diagram.pdf", plot = build_grid(g)) ## End(Not run)
Build a grob
consort diagram, use this if you want
to save plots with ggsave
build_grviz(x)
build_grviz(x)
x |
A conosrt object. |
A Graphviz
code
## Not run: txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") # plot(g, grViz = TRUE) ## End(Not run)
## Not run: txt1 <- "Population (n=300)" txt1_side <- "Excluded (n=15): \n \u2022 MRI not collected (n=3)\n \u2022 Tissues not collected (n=4)\n \u2022 Other (n=8)" g <- add_box(txt = txt1) g <- add_side_box(g, txt = txt1_side) g <- add_box(g, txt = "Randomized (n=200)") # plot(g, grViz = TRUE) ## End(Not run)
This function is used to create an arrow line to connect two boxes. User should provide the starting and ending side of the arrow.
connect_box(start, end, connect, type = c("s", "p"), name = NULL)
connect_box(start, end, connect, type = c("s", "p"), name = NULL)
start |
Starting point of the arrow. |
end |
Ending point of the arrow. |
connect |
The connection of the box. It should be the combination of the
position. The |
type |
Should be one the |
name |
A character identifier of the line grob, passed to |
A lines grob with arrow.
fg1 <- textbox(text = "This is a test") fg2 <- textbox(text = "This is an other test", 0.7, 0.2) grid::grid.draw(fg1) grid::grid.draw(fg2) connect_box(fg1, fg2, connect = "bl", type = "p")
fg1 <- textbox(text = "This is a test") fg2 <- textbox(text = "This is an other test", 0.7, 0.2) grid::grid.draw(fg1) grid::grid.draw(fg2) connect_box(fg1, fg2, connect = "bl", type = "p")
Create CONSORT diagram from a participant disposition data.
consort_plot( data, orders, side_box, allocation = NULL, labels = NULL, kickoff_sidebox = TRUE, cex = 0.8, text_width = NULL )
consort_plot( data, orders, side_box, allocation = NULL, labels = NULL, kickoff_sidebox = TRUE, cex = 0.8, text_width = NULL )
data |
Data set with disposition information for each participants. |
orders |
A named vector or a list, names as the variable in the dataset and values as labels in the box. The order of the diagram will be based on this. A list can be used to report multiple variable in a single node, the first variable in a list element will be used to report the total and the exact items will be summarised for the remaining variable. This is limitted to non-side box. |
side_box |
Variable vector, appeared as side box in the diagram. The next box will be the subset of the missing values of these variables. |
allocation |
Name of the grouping/treatment variable (optional), the
diagram will split into branches on this variables forward. For a factorial
design, with two splits for example, a character vector with a maximum of
length two can be provided. The extra box will be skipped if the values
in the |
labels |
Named vector, names is the location of the terminal node. The position location should plus 1 after the allocation variables if the allocation is defined. |
kickoff_sidebox |
remove (default) the side box observations from the following counting. |
cex |
Multiplier applied to font size, Default is 0.8 |
text_width |
a positive integer giving the target column for wrapping
lines in the output. String will not be wrapped if not defined (default).
The |
The calculation of numbers is as in an analogous to Kirchhoff's Laws of electricity. The numbers in terminal nodes must sum to those in the ancestor nodes. All the drop outs will be populated as a side box. Which was different from the official CONSORT diagram template, which has dropout inside a vertical node.
A consort
object.
add_side_box
,add_split
,
add_side_box
textbox
## Prepare test data data(dispos.data) df <- dispos.data[!dispos.data$arm3 %in% "Trt C", ] p <- consort_plot(data = df, orders = list(c(trialno = "Population"), c(exclusion = "Excluded"), c(arm = "Randomized patient"), c(arm3 = "", subjid_notdosed="Participants not treated"), c(followup = "Pariticpants planned for follow-up", lost_followup = "Reason for tot followed"), c(assessed = "Assessed for final outcome"), c(no_value = "Reason for not assessed"), c(mitt = "Included in the mITT analysis")), side_box = c("exclusion", "no_value"), allocation = c("arm", "arm3"), labels = c("1" = "Screening", "2" = "Randomization", "5" = "Follow-up", "7" = "Final analysis"), cex = 0.7)
## Prepare test data data(dispos.data) df <- dispos.data[!dispos.data$arm3 %in% "Trt C", ] p <- consort_plot(data = df, orders = list(c(trialno = "Population"), c(exclusion = "Excluded"), c(arm = "Randomized patient"), c(arm3 = "", subjid_notdosed="Participants not treated"), c(followup = "Pariticpants planned for follow-up", lost_followup = "Reason for tot followed"), c(assessed = "Assessed for final outcome"), c(no_value = "Reason for not assessed"), c(mitt = "Included in the mITT analysis")), side_box = c("exclusion", "no_value"), allocation = c("arm", "arm3"), labels = c("1" = "Screening", "2" = "Randomization", "5" = "Follow-up", "7" = "Final analysis"), cex = 0.7)
This is a demo data to demonstrate the use of the package. One row per participant. Participants who are excluded should provide a reason, missing otherwise.
dispos.data
dispos.data
A data frame with 300 rows and 11 columns:
Participants ID of the participants
Exclusion reason before and after induction
Participants ID of the participants who are included in the induction phase, an extra treatment before randomisation.
Exclusion reason before randomisation, including before and after induction
Arms pariticipants randomised to.
Participants ID of the participants who had at least one dose of the protocol treatment.
Reason for participants not dosed.
Participants ID planned for follow-up.
Reason for participants not dosed.
Participants ID participants attended assessment.
Reason for participants missing final assessment.
Participants ID included in the mITT analysis.
This function use the data to generate label and bullet points for the box.
gen_text(x, label = NULL, bullet = FALSE)
gen_text(x, label = NULL, bullet = FALSE)
x |
A list or a vector to be used. |
label |
A character string as a label at the beginning of the text label. The count for each categories will be returned if no label is provided. |
bullet |
If shows bullet points. If the value is 'TRUE', the bullet points will be tabulated, default is 'FALSE'. |
A character string of vector.
val <- data.frame( am = factor(ifelse(mtcars$am == 1, "Automatic", "Manual"), ordered = TRUE), vs = factor(ifelse(mtcars$vs == 1, "Straight", "V-shaped"), ordered = TRUE), car = row.names(mtcars) ) gen_text(val$car, label = "Cars in the data") gen_text(val$car, label = "Cars in the data", bullet = FALSE) gen_text(split(val$car, val$am), label = "Cars in the data") gen_text(split(val$car, val$am), label = "Cars in the data", bullet = FALSE) gen_text(split(val[,c("vs", "car")], val$am), label = "Cars in the data", bullet = FALSE) gen_text(val[,c("vs", "car")], label = "Cars in the data", bullet = FALSE)
val <- data.frame( am = factor(ifelse(mtcars$am == 1, "Automatic", "Manual"), ordered = TRUE), vs = factor(ifelse(mtcars$vs == 1, "Straight", "V-shaped"), ordered = TRUE), car = row.names(mtcars) ) gen_text(val$car, label = "Cars in the data") gen_text(val$car, label = "Cars in the data", bullet = FALSE) gen_text(split(val$car, val$am), label = "Cars in the data") gen_text(split(val$car, val$am), label = "Cars in the data", bullet = FALSE) gen_text(split(val[,c("vs", "car")], val$am), label = "Cars in the data", bullet = FALSE) gen_text(val[,c("vs", "car")], label = "Cars in the data", bullet = FALSE)
This function will get the coordinates of the textbox object.
get_coords(x)
get_coords(x)
x |
A textbox object |
A list of coordinates will return:
left |
Left (x-min) side coordinate. |
right |
Right (x-max) side coordinate. |
bottom |
Bottom (y-min) side coordinate. |
top |
Top (y-max) side coordinate. |
top.mid |
Coordinate vector of top middle, measured by grob. |
left.mid |
Coordinate vector of left middle, measured by grob. |
bottom.mid |
Coordinate vector of bottom middle, measured by grob. |
right.mid |
Coordinate vector of right middle, measured by grob. |
x |
X (center x) coordinate. |
y |
Y (center y) coordinate. |
width |
Width of the textbox, derived with |
height |
Height of the textbox, derived with |
half_width |
Half width of the box. |
half_height |
Half height of the box. |
fg <- textbox(text = "This is a test") get_coords(fg)
fg <- textbox(text = "This is a test") get_coords(fg)
This function can be used to move the box to a given position with
editGrob changing the x
and y
value.
move_box(obj, x = NULL, y = NULL, pos_type = c("absolute", "relative"))
move_box(obj, x = NULL, y = NULL, pos_type = c("absolute", "relative"))
obj |
A |
x |
A unit element or a number that can be converted to |
y |
A unit element or a number that can be converted to |
pos_type |
If the provided coordinates are |
A box object with updated x and y coordinates.
fg <- textbox(text = "This is a test") fg2 <- move_box(fg, 0.3, 0.3)
fg <- textbox(text = "This is a test") fg2 <- move_box(fg, 0.3, 0.3)
Method for plot objects and display the output in on a grid device.
## S3 method for class 'consort' plot(x, grViz = FALSE, ...) ## S3 method for class 'consort' print(x, grViz = FALSE, ...)
## S3 method for class 'consort' plot(x, grViz = FALSE, ...) ## S3 method for class 'consort' print(x, grViz = FALSE, ...)
x |
A |
grViz |
If use grViz to print the plot.
Default is |
... |
Not used. |
None.
add_side_box
,add_split
,
add_side_box
, grid.draw
Create a grob with text inside. To extract the units describing grob boundary location can be accessed with grobX and grobY. The units describing width and height can be accessed with grobWidth and grobHeight.
textbox( text, x = unit(0.5, "npc"), y = unit(0.5, "npc"), just = c("center", "left", "right"), txt_gp = getOption("txt_gp", default = gpar(color = "black", cex = 1)), box_fn = roundrectGrob, box_gp = getOption("box_gp", default = gpar(fill = "white")), name = "textbox" ) grid.textbox(...)
textbox( text, x = unit(0.5, "npc"), y = unit(0.5, "npc"), just = c("center", "left", "right"), txt_gp = getOption("txt_gp", default = gpar(color = "black", cex = 1)), box_fn = roundrectGrob, box_gp = getOption("box_gp", default = gpar(fill = "white")), name = "textbox" ) grid.textbox(...)
text |
A character text to be passed to textGrob. |
x |
A number or unit object specifying x-location. |
y |
A number or unit object specifying y-location. |
just |
The justification of the text, '"left"', '"right' and '"center"'. See textGrob for more details. |
txt_gp |
An object of class gpar style to be applied to the
text. This will also be read from global options of |
box_fn |
Function to create box for the text. Parameters of 'x=0.5',
'y=0.5' and 'box_gp' will be passed to this function and return a |
box_gp |
An object of class gpar style to be applied to the box. |
name |
A character identifier. |
... |
Parameters passed to |
A text box grob. grid.textbox() returns the value invisibly.
fg <- textbox(text = "This is a test") grid::grid.draw(fg) grid.textbox(text = "This is a test") grid.textbox(text = "This is a test")
fg <- textbox(text = "This is a test") grid::grid.draw(fg) grid.textbox(text = "This is a test") grid.textbox(text = "This is a test")