This document is for developers who would like to understand the internal of the forestly package.
Overview
The forestly package is developed to generate interactive forest plot for the safety analysis in clinical trials.
To generate an interactive forest plot, we develop three main functions as listed below. And the details of these three main functions will be introduced in the next three sections separately.
-
tidy_ae_table: This function is used to obtain adverse event (AE) information ready for visualization. -
download_ae_reports: This function is used to generate a download button, so users can download the AE summary tables by clicking this button. -
forestly: This function is used to generate an interactive forest plot.
A minimal example summarized the major steps in using the forestly package is
mydata <- tidy_ae_table(...) # Step 1: create tidy AE data
download_ae_reports(mydata) # Step 2: generate download button
forestly(mydata) # Step 3: generate interactive forest plot
# (the order of Step 2 and Step 3 can be reversed)Main function 1: tidy_ae_table()
The main function tidy_ae_table() is used to obtain AE
information ready for visualization. Specifically speaking, it merges
standardized adsl and adae tables together,
and outputs a AE summary table. The AE summary table summarizes the
number/ratio of subjects experiencing a certain AE for both treatment
arm and control arm.
There are some utility functions developed inside of
tidy_ae_table() and we list them as follows.
tidy_population(): This function is used to prepare the observation datasets for the use in functiontidy_ae_table(). The function filter theadsldataset, and define the proper treatment order in the dataset.tidy_observation(): This function is used to prepare the observation datasets for the use in functiontidy_ae_table(). The function filter theadaedataset, and define the proper treatment order in the dataset.`
prop_test_mn(): This function tests equal proportion using Miettinen and Nurminen method. In theforestlypackage, it generates the confidence interval (CI) for the risk difference between treatment arm and control arm.define_ae_selectList(): This function is to specify the AE labels to be displayed in the select list of the interactive forestly plot. It has two arguments, (1)ae_criterionand (2)ae_label. The first argumentae_criterionis a (vector of) string, which defines the criterion to select a class of AE to display in the interactive forest plot. For example, ifae_criterion = 'AESER == "Y"', then it will select the serious AE. The second argumentae_labelis a (vector of) string, which defines the labels to be displayed in the select list of interactive forest plot. If these two arguments are both string vectors, then they must be a 1:1 map. This function is used in the argumentsae_interested =in functiontidy_ae_table()(see examples below). It throws errors if the length of theae_criteriondoesn’t match that ofae_label.
# Example 1: if you would like to display the serious AE
tidy_ae_table(...,
ae_interested = define_ae_selectList(ae_criterion = 'AESER == "Y"',
ae_label = "serious AE"),
...).
# Example 2: if you would like to display both serious AE and drug-related AE
tidy_ae_table(...,
ae_interested = define_ae_selectList(ae_criterion = c('AESER != "N"', 'AEREL != "None"'),
ae_label = c("serious AE", "drug-related AE")
...).
tidy_multi_ae_label(): This a function is design torbinddata together according to the interested AE labels defined inae_interested =. For example, if you use Example 1 above,tidy_multi_ae_label()will generate an AE summary table as rbind(summary table of all AE, summary of serious AE).tidy_ae_listing(): This function generates a data frame which serves as the listed details in the the reactable.
Main function 2: tlf_download()
This function generates a download button for users to download AE tables.
-
tlf_ae_summary: a function to create AE summary table. -
tlf_ae_specific: a function to create specific AE table. -
tlf_ae_listing: a function to create AE listing.
The output of the tlf_xxx functions are
r2rtf objects created by rtf_encode
-
tlf_download: a function to download multiple TLFs in Rmarkdown. Rewriteae_download_reportto allow it usetlf_xxxfunctions as input.
tlf_ae_summary() # generate the AE summary table
tlf_ae_specific() # generate the specific AE table
# tlf[[4]] <- tlf_ae_listing() # As needed ????
tlf_download() # download the above tables
Main function 3: ae_forestly()
This function generates an interactive forest plot for the object
returned by format_ae_forestly(). The interactive forest
plot is built on the lt
package: the main table and the inline figures are a single
lt table made interactive with
lt::lt_interactive(), surrounded by a few forestly-owned
HTML controls.
The output has two kinds of pieces.
The first is the forestly controls (an ordinary
<div> of HTML widgets): a parameter dropdown, an
incidence range slider, and an optional CSV download button. They are
plain DOM elements, not part of the table. On change they drive the
table through the controller lt exposes on the rendered
table element as el._lt, calling
el._lt.filter(id, fn) to install a row predicate. The
slider and dropdown filter on hidden helper columns
(hide_prop/hide_n and parameter)
that stay in the table spec but are hidden from view. This logic lives
in inst/js/forestly-widgets.js and needs no
crosstalk.
The second is the lt table itself, which summarizes the
AE information:
- Per-arm
n/(%)columns grouped under treatment-group spanners. - An inline proportion dot plot drawn by
lt::lt_dotplot()(one staggered dot per arm on a shared scale, with a footer legend). - An inline risk-difference error bar drawn by
lt::lt_errorbar()(one point and 95% CI per comparison, with a zero reference line and a favor-direction axis). - Expandable row detail (
lt_interactive(detail=)): clicking a row’s caret renders that term’s AE listing as its own small interactivelttable, assembled on demand from a listing shipped once (see below).
There are some utility functions used to develop
ae_forestly():
-
format_lt_forestly(): Turnsformat_ae_forestly()’soutdatainto the structurallttable (columns, labels, spanners, the dot plot and error bar, column widths, hidden helper columns). It is deliberately interaction-free so it can be tested in isolation;ae_forestly()layerslt_interactive()and the controls on top. The figure design is driven by metadata thatformat_ae_forestly()computes once across all rows:- color:
fig_prop_color/fig_diff_color, passed tolt_dotplot(color=)/lt_errorbar(color=); - label: the arm names and the
diff_labelfavor-direction axis; - column width: the per-column widths in
outdata$widths, passed tolt::lt_width(); - range:
fig_prop_range/fig_diff_range, passed tolt_dotplot(limits=)/lt_errorbar(limits=).
- color:
The drill-down listing is embedded once as a shared record store captured in the detail callback’s closure; each table row carries only the record indices it needs (run-length or delta encoded), so the listing is never duplicated per row. The
ltinteractivity (lt-interactive.js) and inline-plot (lt-plot.js) runtimes are bundled as HTML dependencies vialt::lt_dependency(); only the numbers travel to the client and the SVG is drawn in the browser.
