Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes #84 xportr deep dive vignette #141

Merged
merged 96 commits into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
819bba9
docs: #84 Example data and spec upload
bms63 May 1, 2023
3132916
docs: #84 ignore folder data and specs stored to pass build
bms63 May 1, 2023
87c2dde
chore: #84 merge in devel
bms63 May 9, 2023
974b6ae
feat: #84 moving to site to bootswatch
bms63 May 11, 2023
d5a2fcf
chore: #84 changed named of spec files. start on deepdive vignette
bms63 May 11, 2023
ea2d744
feat: #84 Laying out Intro sections.
bms63 May 11, 2023
beac75f
update: #122 merge in devel
bms63 May 14, 2023
3f419c1
update: #84 merge in pkgdown update, explain data package, testing ou…
bms63 May 15, 2023
cf19f4d
chore: #44 bringing in new metadata update
bms63 May 20, 2023
a633382
feat: #84 developing deepdive overview section. fixed image in Readme
bms63 May 20, 2023
ef1f903
feat: #84 xportr apply all, new pictogram
bms63 May 21, 2023
9092f25
chore: #84 merge in devel
bms63 May 24, 2023
38d1993
feat: #84 explanding type section
bms63 May 24, 2023
d967bd7
chore: #84 news file updated
bms63 May 24, 2023
9d390bb
chore: fix for index
bms63 May 24, 2023
3a6f3ec
Merge branch 'devel' into 84_xportr_deep_dive_vignette
elimillera May 31, 2023
ebdc579
Move adsl to data/
elimillera May 31, 2023
2b43a7a
Merge remote-tracking branch 'origin/120-replace-metacore-with-metada…
elimillera May 31, 2023
6beb272
Change is null logic
elimillera May 31, 2023
36f188a
remove here
elimillera May 31, 2023
5eddeb8
fix var_spec
elimillera May 31, 2023
5a63b2c
set eval to false
elimillera May 31, 2023
c83e778
Move bulk processing out to issue
elimillera May 31, 2023
4796cb4
Add var_spec documentation.
elimillera May 31, 2023
b25cb4e
Add package style
elimillera May 31, 2023
f8dffd7
docs: #84 fixing display issue for cli in get started, working on war…
bms63 Jun 6, 2023
1f25b30
chore: #84 lintr fix
bms63 Jun 6, 2023
e03ca10
chore: #84 style files
bms63 Jun 6, 2023
6c373e7
docs: #84 finsihing core function examples
bms63 Jun 7, 2023
6d004b8
docs: #84 final touches on functions
bms63 Jun 7, 2023
cb115ac
chore: #84 stler and lintr
bms63 Jun 7, 2023
1af8a61
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
e675ca1
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
353bb62
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
8c051a5
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
77577a9
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
cda1fd2
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
efe8402
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
a49ac37
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
611cc17
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
3383d91
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
092120f
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
1d23013
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
b5566c1
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
dc32384
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
6f0957d
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
92ec2c0
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
b99a874
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
88ede73
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
caf20a0
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
91f2b65
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
2117b9b
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
76d22ba
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
c95a690
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
e12b51b
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
433accb
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
848ba3b
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
1ab4323
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
8ab0912
Update vignettes/deepdive.Rmd
bms63 Jun 8, 2023
f9193b9
docs: #84 removed TODOs. moved library() calls
bms63 Jun 8, 2023
dfb66b1
docs: #84 news tweak
bms63 Jun 8, 2023
b309c84
docs: #150 removing br
bms63 Jun 8, 2023
a51bbbe
chore: #84 missing package
bms63 Jun 8, 2023
9e6003d
docs: #150 display msgs, removed additional br, improved wordflow
bms63 Jun 8, 2023
93b481d
chore: #150 lint
bms63 Jun 8, 2023
ba7e540
chore: #150 style
bms63 Jun 8, 2023
bea320e
docs: #84 merge in devel
bms63 Jun 11, 2023
6fffb8f
fix: #84 order update brought in
bms63 Jun 11, 2023
58dee7b
update: #84 merge in get started updates
bms63 Jun 11, 2023
0203d28
chore: #84 fixing style and lint
bms63 Jun 11, 2023
d2ee389
docs: #84 formatting DT
bms63 Jun 13, 2023
28b001d
Merge branch 'devel' into 84_xportr_deep_dive_vignette
bms63 Jun 13, 2023
58fddba
Update vignettes/deepdive.Rmd
bms63 Jun 13, 2023
c3d829d
Merge branch 'devel' into 84_xportr_deep_dive_vignette
bms63 Jun 14, 2023
fcd5337
chore: #84 spelling updates across package
bms63 Jun 14, 2023
93800fc
Update vignettes/deepdive.Rmd
bms63 Jun 14, 2023
a81cf50
review: #84 comments from PR review
bms63 Jun 14, 2023
b0b7df0
Merge branch '84_xportr_deep_dive_vignette' of https://github.com/ato…
bms63 Jun 14, 2023
f9f441b
Update vignettes/deepdive.Rmd
bms63 Jun 14, 2023
b157beb
docs: #84 css update for DT
bms63 Jun 14, 2023
bd40b2e
Merge branch '84_xportr_deep_dive_vignette' of https://github.com/ato…
bms63 Jun 14, 2023
4d616c2
chore: lint the pkgdown yaml configuration
vedhav Jun 14, 2023
aeac637
docs: #84 scrollable checks, moved png
bms63 Jun 15, 2023
2240608
Merge branch '84_xportr_deep_dive_vignette' of https://github.com/ato…
bms63 Jun 15, 2023
0a0253e
chore: #84 lint and style
bms63 Jun 15, 2023
ead17a8
docs: #84 options verbose section
bms63 Jun 15, 2023
c0c9dcb
bundles all suggestions for datatables in xportr and deepdive
averissimo Jun 15, 2023
f59f106
fix: styler problems
averissimo Jun 15, 2023
4ac1758
fix: typo
averissimo Jun 15, 2023
f8d2800
Merge pull request #160 from atorus-research/84_datatables
bms63 Jun 15, 2023
fb7ad19
docs: #84 readme update, revert type back
bms63 Jun 15, 2023
f632838
Merge branch 'devel' into 84_xportr_deep_dive_vignette
bms63 Jun 15, 2023
fa58e0c
Merge branch 'devel' into 84_xportr_deep_dive_vignette
bms63 Jun 15, 2023
cf60609
review: #84 format update
bms63 Jun 15, 2023
ebea401
Merge branch '84_xportr_deep_dive_vignette' of https://github.com/ato…
bms63 Jun 15, 2023
67b6925
docs: #84 adjusted type discussion
bms63 Jun 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@
^advs\.xpt$
^advs_Define-Excel-Spec_match_admiral\.xlsx
^cran-comments\.md$
^example_data_specs$
^deepdive.Rmd$
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export(xportr_format)
export(xportr_label)
export(xportr_length)
export(xportr_logger)
export(xportr_metadata)
export(xportr_order)
export(xportr_type)
export(xportr_write)
Expand Down
11 changes: 7 additions & 4 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@

## New Features and Bug Fixes

* Fixed an issue where `xportr_type` would overwrite column labels, widths, and "sas.formats"
* Fixed messaging of `xportr_order`to give better visability of the number of variables being reordered.
* Add new argument to `xportr_write` to allow users to specify how xpt validation checks are handled.
* Fixed an issue where `xportr_type()` would overwrite column labels, widths, and "sas.formats"
* Fixed messaging of `xportr_order()`to give better visability of the number of variables being reordered.
* Add new argument to `xportr_write()` to allow users to specify how xpt validation checks are handled.
* Fixed bug where character_types were case sensitive. They are now case insensitive.
* Updated `xportr_type` to make type coercion more explicit.
* Updated `xportr_type()` to make type coercion more explicit.
* Added function `xportr_metadata()` to explicitly set metadata at the start of a pipeline (#44)

## Documentation

* Moved `{pkgdown}` site to bootswatch. Enabled search and linked slack icon (#122).
* Additional vignette showcasing functions and quality of life utilities for processing `xpts` created (#84)


# xportr 0.2.0
* Added a new validation test that errors when users pass invalid formats (#60 #64). Thanks to @zdz2101!
Expand Down
15 changes: 12 additions & 3 deletions R/df_label.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
#' SEX = c("M", "F", "M")
#' )
#'
#' metacore <- data.frame(
#' metadata <- data.frame(
#' dataset = c("adsl", "adae"),
#' label = c("Subject-Level Analysis", "Adverse Events Analysis")
#' )
#'
#' adsl <- xportr_df_label(adsl, metacore)
xportr_df_label <- function(.df, metacore, domain = NULL) {
#' adsl <- xportr_df_label(adsl, metadata)
xportr_df_label <- function(.df, metacore = NULL, domain = NULL) {
domain_name <- getOption("xportr.df_domain_name")
label_name <- getOption("xportr.df_label")

Expand All @@ -38,6 +38,15 @@ xportr_df_label <- function(.df, metacore, domain = NULL) {

## End of common section

## Pull out correct metadata
if (is.null(metacore)) {
if (is.null(attr(.df, "metadata"))) {
stop("Metadata must be set with `metacore` or `xportr_metadata()`")
} else {
metacore <- attr(.df, "metadata")
}
}

if (inherits(metacore, "Metacore")) {
metacore <- metacore$ds_spec
}
Expand Down
14 changes: 11 additions & 3 deletions R/format.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
#' BRTHDT = c(1, 1, 2)
#' )
#'
#' metacore <- data.frame(
#' metadata <- data.frame(
#' dataset = c("adsl", "adsl"),
#' variable = c("USUBJID", "BRTHDT"),
#' format = c(NA, "DATE9.")
#' )
#'
#' adsl <- xportr_format(adsl, metacore)
xportr_format <- function(.df, metacore, domain = NULL, verbose = getOption("xportr.format_verbose", "none")) {
#' adsl <- xportr_format(adsl, metadata)
xportr_format <- function(.df, metacore = NULL, domain = NULL, verbose = getOption("xportr.format_verbose", "none")) {
domain_name <- getOption("xportr.domain_name")
format_name <- getOption("xportr.format_name")
variable_name <- getOption("xportr.variable_name")
Expand All @@ -40,6 +40,14 @@ xportr_format <- function(.df, metacore, domain = NULL, verbose = getOption("xpo

## End of common section

if (is.null(metacore)) {
if (is.null(attr(.df, "metadata"))) {
stop("Metadata must be set with `metacore` or `xportr_metadata()`")
} else {
metacore <- attr(.df, "metadata")
}
}

if (inherits(metacore, "Metacore")) {
metacore <- metacore$var_spec
}
Expand Down
14 changes: 11 additions & 3 deletions R/label.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
#' SEX = c("M", "F", "M")
#' )
#'
#' metacore <- data.frame(
#' metadata <- data.frame(
#' dataset = "adsl",
#' variable = c("USUBJID", "SITEID", "AGE", "SEX"),
#' label = c("Unique Subject Identifier", "Study Site Identifier", "Age", "Sex")
#' )
#'
#' adsl <- xportr_label(adsl, metacore)
xportr_label <- function(.df, metacore, domain = NULL,
#' adsl <- xportr_label(adsl, metadata)
xportr_label <- function(.df, metacore = NULL, domain = NULL,
verbose = getOption("xportr.label_verbose", "none")) {
domain_name <- getOption("xportr.domain_name")
variable_name <- getOption("xportr.variable_name")
Expand All @@ -43,6 +43,14 @@ xportr_label <- function(.df, metacore, domain = NULL,

## End of common section

if (is.null(metacore)) {
if (is.null(attr(.df, "metadata"))) {
stop("Metadata must be set with `metacore` or `xportr_metadata()`")
} else {
metacore <- attr(.df, "metadata")
}
}

if (inherits(metacore, "Metacore")) {
metacore <- metacore$var_spec
}
Expand Down
14 changes: 11 additions & 3 deletions R/length.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
#' BRTHDT = c(1, 1, 2)
#' )
#'
#' metacore <- data.frame(
#' metadata <- data.frame(
#' dataset = c("adsl", "adsl"),
#' variable = c("USUBJID", "BRTHDT"),
#' length = c(10, 8)
#' )
#'
#' adsl <- xportr_length(adsl, metacore)
xportr_length <- function(.df, metacore, domain = NULL,
#' adsl <- xportr_length(adsl, metadata)
xportr_length <- function(.df, metacore = NULL, domain = NULL,
verbose = getOption("xportr.length_verbose", "none")) {
domain_name <- getOption("xportr.domain_name")
variable_length <- getOption("xportr.length")
Expand All @@ -41,6 +41,14 @@ xportr_length <- function(.df, metacore, domain = NULL,

## End of common section

if (is.null(metacore)) {
if (is.null(attr(.df, "metadata"))) {
stop("Metadata must be set with `metacore` or `xportr_metadata()`")
} else {
metacore <- attr(.df, "metadata")
}
}

if (inherits(metacore, "Metacore")) {
metacore <- metacore$var_spec
}
Expand Down
4 changes: 2 additions & 2 deletions R/messages.R
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ var_names_log <- function(tidy_names_df, verbose) {

# Message stating any renamed variables each original variable and it's new name
if (nrow(only_renames) > 0) {
walk(only_renames$renamed_msg, ~ xportr_logger(.x, verbose))
purrr::walk(only_renames$renamed_msg, ~ xportr_logger(.x, verbose))
}

# Message checking for duplicate variable names after renamed (Pretty sure
# this is impossible) but good to have a check none-the-less.
dups <- tidy_names_df %>% filter(renamed_n > 1)
if (nrow(dups) != 0) {
cli_alert_danger(
cli::cli_alert_danger(
glue(
.sep = " ",
"Duplicate renamed term(s) were created.",
Expand Down
14 changes: 11 additions & 3 deletions R/order.R
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
#' USUBJID = c(1001, 1002, 1003)
#' )
#'
#' metacore <- data.frame(
#' metadata <- data.frame(
#' dataset = c("adsl", "adsl", "adsl", "adsl"),
#' variable = c("STUDYID", "USUBJID", "TRT01A", "BRTHDT"),
#' order = 1:4
#' )
#'
#' adsl <- xportr_order(adsl, metacore)
xportr_order <- function(.df, metacore, domain = NULL, verbose = getOption("xportr.order_verbose", "none")) {
#' adsl <- xportr_order(adsl, metadata)
xportr_order <- function(.df, metacore = NULL, domain = NULL, verbose = getOption("xportr.order_verbose", "none")) {
domain_name <- getOption("xportr.domain_name")
order_name <- getOption("xportr.order_name")
variable_name <- getOption("xportr.variable_name")
Expand All @@ -37,6 +37,14 @@ xportr_order <- function(.df, metacore, domain = NULL, verbose = getOption("xpor

## End of common section

if (is.null(metacore)) {
if (is.null(attr(.df, "metadata"))) {
stop("Metadata must be set with `metacore` or `xportr_metadata()`")
} else {
metacore <- attr(.df, "metadata")
}
}

if (inherits(metacore, "Metacore")) {
metacore <- metacore$ds_vars
}
Expand Down
18 changes: 14 additions & 4 deletions R/type.R
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#' @export
#'
#' @examples
#' metacore <- data.frame(
#' metadata <- data.frame(
#' dataset = "test",
#' variable = c("Subj", "Param", "Val", "NotUsed"),
#' type = c("numeric", "character", "numeric", "character")
Expand All @@ -30,8 +30,8 @@
#' Param = c("param1", "param2", "param3")
#' )
#'
#' df2 <- xportr_type(.df, metacore, "test")
xportr_type <- function(.df, metacore, domain = NULL,
#' df2 <- xportr_type(.df, metadata, "test")
xportr_type <- function(.df, metacore = NULL, domain = NULL,
verbose = getOption("xportr.type_verbose", "none")) {
# Name of the columns for working with metadata
domain_name <- getOption("xportr.domain_name")
Expand All @@ -50,7 +50,17 @@ xportr_type <- function(.df, metacore, domain = NULL,
## End of common section

## Pull out correct metadata
if ("Metacore" %in% class(metacore)) metacore <- metacore$var_spec
if (is.null(metacore)) {
if (is.null(attr(.df, "metadata"))) {
stop("Metadata must be set with `metacore` or `xportr_metadata()`")
} else {
metacore <- attr(.df, "metadata")
}
}

if (inherits(metacore, "Metacore")) {
metacore <- metacore$var_spec
}

if (domain_name %in% names(metacore)) {
metacore <- metacore %>%
Expand Down
1 change: 1 addition & 0 deletions R/utils-xportr.R
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ xpt_validate <- function(data) {

# 3.0 VARIABLE TYPES ----
types <- tolower(extract_attr(data, attr = "SAStype"))

expected_types <- c(
"", "text", "integer", "float", "datetime", "date", "time",
"partialdate", "partialtime", "partialdatetime",
Expand Down
39 changes: 39 additions & 0 deletions R/xportr_metadata.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#' Set variable specifications and domain
#'
#' @param .df An R object with columns that can be coerced
#' @param metacore Either a data.frame that has the names of all possible columns
#' and their types, or a `Metacore` object from the `Metacore` package. Required
#' column names are dataset, variables, type
#' @param domain Name of the dataset. Ex ADAE/DM. This will be used to subset
#' the metacore object. If none is passed it is assumed to be the name of the
#' dataset passed in `.df`.
#'
#' @return `.df` dataset with metadata and domain attributes set
#' @export
#'
#' @examples
#' metadata <- data.frame(
#' dataset = "test",
#' variable = c("Subj", "Param", "Val", "NotUsed"),
#' type = c("numeric", "character", "numeric", "character")
#' )
#'
#' .df <- data.frame(
#' Subj = as.character(123, 456, 789),
#' Different = c("a", "b", "c"),
#' Val = c("1", "2", "3"),
#' Param = c("param1", "param2", "param3")
#' )
#'
#' df2 <- xportr_metadata(.df, metadata, "test")
xportr_metadata <- function(.df, metacore, domain = NULL) {
## Common section to detect domain from argument or pipes

df_arg <- tryCatch(as_name(enexpr(.df)), error = function(err) NULL)
domain <- get_domain(.df, df_arg, domain)
if (!is.null(domain)) attr(.df, "_xportr.df_arg_") <- domain

## End of common section

structure(.df, metadata = metacore)
}
13 changes: 13 additions & 0 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,19 @@ adsl %>%
xportr_write("adsl.xpt", label = "Subject-Level Analysis Dataset")
```

The `xportr_metadata()` function can reduce duplication by setting the variable specification and domain explicitly at the top of a pipeline.

```{r, message=FALSE, eval=FALSE}
adsl %>%
xportr_metadata(var_spec, "ADSL") %>%
xportr_type() %>%
xportr_length() %>%
xportr_label() %>%
xportr_order() %>%
xportr_format() %>%
xportr_write("adsl.xpt", label = "Subject-Level Analysis Dataset")
```

That's it! We now have a xpt file created in R with all appropriate types, lengths, labels, ordering and formats. Please check out the [Get Started](https://atorus-research.github.io/xportr/articles/xportr.html) for more information and detailed walk through of each `xportr_` function.

We are in talks with other Pharma companies involved with the [`{pharmaverse}`](https://pharmaverse.org/) to enhance this package to play well with other downstream and upstream packages.
Expand Down
46 changes: 23 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,19 @@ to any validators or data reviewers.

<br>

- Variable names must start with a letter (not an underscore), be
comprised of only uppercase letters (A-Z), numerals (0-9) and be
free of non-ASCII characters, symbols, and underscores.
- Allotted length for each column containing character (text) data
should be set to the maximum length of the variable used across all
data sets (≤ 200)
- Coerces variables to only numeric or character types
- Display format support for numeric float and date/time values
- Variables names are ≤ 8 characters.
- Variable labels are ≤ 200 characters.
- Data set labels are ≤ 40 characters.
- Presence of non-ASCII characters in Variable Names, Labels or data
set labels.
- Variable names must start with a letter (not an underscore), be
comprised of only uppercase letters (A-Z), numerals (0-9) and be free
of non-ASCII characters, symbols, and underscores.
- Allotted length for each column containing character (text) data
should be set to the maximum length of the variable used across all
data sets (≤ 200)
- Coerces variables to only numeric or character types
- Display format support for numeric float and date/time values
- Variables names are ≤ 8 characters.
- Variable labels are ≤ 200 characters.
- Data set labels are ≤ 40 characters.
- Presence of non-ASCII characters in Variable Names, Labels or data set
labels.

**NOTE:** Each check has associated messages and warning.

Expand All @@ -90,13 +90,13 @@ developed using R.

To do this we will need to do the following:

- Apply types
- Apply lengths
- Apply variable labels
- Apply formats
- Re-order the variables
- Apply a dataset label
- Write out a version 5 xpt file
- Apply types
- Apply lengths
- Apply variable labels
- Apply formats
- Re-order the variables
- Apply a dataset label
- Write out a version 5 xpt file

All of which can be done using a well-defined specification file and the
`xportr` package!
Expand Down Expand Up @@ -134,12 +134,12 @@ Each `xportr_` function has been written in a way to take in a part of
the specification file and apply that piece to the dataset.

``` r
adsl %>%
adsl %>%
xportr_type(var_spec, "ADSL") %>%
xportr_length(var_spec, "ADSL") %>%
xportr_label(var_spec, "ADSL") %>%
xportr_order(var_spec, "ADSL") %>%
xportr_format(var_spec, "ADSL") %>%
xportr_order(var_spec, "ADSL") %>%
xportr_format(var_spec, "ADSL") %>%
xportr_write("adsl.xpt", label = "Subject-Level Analysis Dataset")
```

Expand Down
Loading