Despite the tremendous progress in the medical field, cardiovascular disease (CVD) remains the leading cause of death worldwide. Hypertension, specifically, affects over 1.1 billion people annually according to the American Heart Association [9]. This package serves to visualize and quantify various aspects of hypertension in a more digestible format using various metrics proposed in the literature.
Blood pressure data can be analyzed at varying degrees of granularity depending on the reading frequency, presence of a sleep indicator, and whether or not the temporal structure is accounted for. These factors almost always depend on the type of device used, where ABPM monitors are predominantly used for the short term (within 24 hours) and home monitoring devices or office readings are used for measuring variability over the medium and long term (day-to-day, visit-to-visit, etc) [11]. Unlike continuous heart rate monitors or continuous glucose monitors, there are currently no commercially-available continuous blood pressure monitors available for the middle to long term, posing a unique challenge for research.
Of primary concern to researchers is the ability to accurately quantify blood pressure variability (BPV). BPV has been shown to be an important factor in predicting cardiovascular events and sudden death, especially during susceptible periods such as the first two hours of waking up [10]. There have been many proposed methods for characterizing this variability; this package seeks to incorporate as many of these metrics as possible.
We introduce the first comprehensive open-source R package,
bp
, that both analyzes and visualizes
blood pressure data. In an effort to help clinicians make sense of their
patients’ data without requiring multiple software platforms for data
processing, bp
uses only a minimal amount of code to do so
and offers additional capabilities beyond the traditional proprietary
counterparts. At the time of writing, to the best of the authors’
knowledge, there are currently no other available software packages
through the Comprehensive R Archive Network (CRAN) dedicated to blood
pressure analysis.
In this paper, we demonstrate the main functionality of the
bp
package by exploring and analyzing both
a single-subject pilot study of [ 8 ] and a multi-subject study, HYPNOS
[ 11 ], to illustrate the differences between dataset structures and
elaborate how to adjust the settings within the R package to accommodate
either.
Blood pressure monitoring devices work by measuring the pressure of the artery’s restricted blood flow; for digital devices, the vibrations are translated into electrical signals. Unlike home monitors that only take readings upon the subject’s initiation, ambulatory blood pressure monitoring (ABPM) devices take automatic readings at pre-specified intervals over a 24-hour period or longer.
ABPM allows medical professionals to analyze blood pressure during sleep which has been shown to be a more accurate predictor of cardiovascular events than daytime blood pressure. ABPM also allows researchers to discern true hypertension from “whitecoat” hypertension in an office or laboratory setting. Because of the burden of assembling the device (and because of the lack of a commercial-grade alternative), ABPM measurements are intended for the short-term of 24-hours to a few days.
Home monitoring on the other hand, offers individuals the ability to record their blood pressure at will and can be tracked easily using mobile apps over the long-term of weeks, months, or years. However, because the user has to initiate the recording, readings cannot be taken during sleep.
As the nature of the two devices inhibits certain functionality depending on which device is used, we outline how to effectively analyze data for both types of devices.
According to the American Heart Association, there are currently 6 blood pressure stages that correspond to the readings from the monitoring devices: Low (Hypotension), Normal, Elevated, Stage 1 Hypertension, Stage 2 Hypertension, Hypertensive Crisis. Below is a table outlining the categories according to their definitions. Note that because of the ambiguity between Normal, Elevated, and Stage 1 diastolic blood pressure readings (because of the similar thresholds), this package splits the difference and sets a default threshold for Elevated DBP from 80 - 85 and Stage 1 Hypertension from 85 - 90. These thresholds can be adjusted by the user where applicable.
Blood Pressure Category | Systolic (mmHg) | Diastolic (mmHg) | |
---|---|---|---|
Low (Hypotension) | Less than 100 | and | Less than 60 |
Normal | 100 - 120 | and | 60 - 80 |
Elevated | 120 - 129 | and | 60 - 80 |
Stage 1 Hypertension | 130 - 139 | or | 80 - 89 |
Stage 2 Hypertension | 140 - 180 | or | 90 - 120 |
Hypertensive Crisis | Higher than 180 | and/or | Higher than 120 |
Recently, an adaption of these guidelines by (Lee et al 2020) provides a two-to-one mapping of SBP and DBP in order to avoid the instances where there is an unusually high SBP value and low DBP value, or vice versa. These new guidelines are as follows:
BP Stage | Systolic (mmHg) | Diastolic (mmHg) | |
---|---|---|---|
Low (optional) | <100 | and | <60 |
Normal | <120 | and | <80 |
Elevated | 120 - 129 | and | <80 |
Stage 1 - All | 130 - 139 | and | 80 - 89 |
Stage 1 - ISH (ISH - S1) | 130 - 139 | and | <80 |
Stage 1 - IDH (IDH - S1) | <130 | and | 80 - 89 |
Stage 2 - All | >140 | and | >90 |
Stage 2 - ISH (ISH - S2) | >140 | and | <90 |
Stage 2 - IDH (IDH - S2) | <140 | and | >90 |
Crisis (optional) | >180 | or | >120 |
bp
PackageThe general workflow of the bp
package consists of 1) a
data processing stage and 2) an analysis stage, in ideally as little as
two lines of code. The processing stage formats the user’s supplied
input data in such a way that it adheres to the rest of the
bp
functions. The analysis stage uses the processed data to
quantify various attributes of the blood pressure relationships or to
provide various visualizations. One of the key abilities of the
bp
package is bp_report
function which
generates a report that combines such visualization plots into one
easily digestible summary for clinicians or researchers to interpret an
individual’s (or multiple individuals’) blood pressure results. We will
walk through each of these stages in the subsequent sections.
process_data
functionBefore any analysis can be done, the user-supplied data set must be
first processed into the proper format using process_data
to adhere to package data structure requirements and naming conventions.
This function ensures that user-supplied data columns aren’t double
counted or missed, since blood pressure data are often inconsistent and
come from a wide variety of formats. While a tedious initial step, it
will save time in the long-run as the resulting processed data will not
require any future specification, which can then be directly plugged
into the analysis functions. It is worth noting that if the
user-supplied data set already adheres to the column naming conventions
and data types, then the process_data
function will be
unnecessary. However, it is good practice to still make use of this
function as a sanity check to verify all available variables.
The basic workflow is to load in the user-supplied unprocessed raw
data, process it with the process_data
function and save to
a new dataframe. Note that the capitalization does not matter when
specifying the columns.
## Load the sample bp_hypnos
## In this scenario, the bp_hypnos acts as the "user-supplied" data that is to be processed
data("bp_hypnos")
## Assign the output of the process_data function to a new dataframe object
hypnos_proc <- process_data(bp_hypnos,
bp_type = "ABPM",
sbp = 'syst',
dbp = 'diast',
date_time = 'date.time',
id = 'id',
visit = 'visit',
hr = 'hr',
wake = 'wake',
pp = 'pp',
map = 'map',
rpp = 'rpp')
#> 2 values that exceeded the DUL or DLL thresholds were coerced to NA.
Notice how the column names of the original bp_hypnos
changed in the processed data
. Notably, SYST
became SBP
, DIAST
became DBP
, and
DATE.TIME
became DATE_TIME
.
names(bp_hypnos)
#> [1] "NR." "DATE.TIME" "SYST" "MAP" "DIAST" "HR"
#> [7] "PP" "RPP" "WAKE" "ID" "VISIT" "DATE"
names(hypnos_proc)
#> [1] "ID" "GROUP" "DATE_TIME" "DATE" "DAY_OF_WEEK"
#> [6] "YEAR" "MONTH" "DAY" "HOUR" "TIME_OF_DAY"
#> [11] "SBP" "DBP" "BP_CLASS" "HR" "MAP"
#> [16] "MAP_OLD" "RPP" "PP" "PP_OLD" "WAKE"
#> [21] "VISIT" "NR." "MINUTE" "SECOND" "BP_TYPE"
#> [26] "SBP_CATEGORY" "DBP_CATEGORY"
While the results seem to be trivial at first glance, let’s see what
happens when we use a much different data set with a completely
different naming convention: the bp_jhs
data set. Unlike
bp_hypnos
which has all of the available columns needed in
the process_data
function with multiple subjects,
bp_jhs
is a single-subject data set without many of the
multi-subject identifiers such as ID
, VISIT
,
or WAKE
(as it is non-ABPM data). Further, there is no
MAP
or PP
column, but these (as we will see)
can be automatically created.
## Load the sample bp_jhs data set
## As before, this is what will be referred to as the "user-supplied" data set
data("bp_jhs")
## Assign the output of the process_data function to a new dataframe object
jhs_proc <- process_data(bp_jhs,
sbp = 'sys.mmhg.',
dbp = 'dias.mmhg.',
date_time = 'datetime',
hr = 'PULSE.BPM.')
#> DATE column created from DATE_TIME column.
#> No PP column found or specified. Automatically generated from SBP and DBP columns.
#> No RPP column found or specified. Automatically generated from SBP and HR columns.
#> No MAP column found or specified. Automatically generated from SBP and DBP columns.
head(jhs_proc, 5)
#> ID GROUP DATE_TIME DATE DAY_OF_WEEK YEAR MONTH DAY HOUR
#> 1 1 1 2019-08-01 09:15:54 2019-08-01 Thu 2019 8 1 9
#> 2 1 1 2019-07-31 11:39:59 2019-07-31 Wed 2019 7 31 11
#> 3 1 1 2019-07-31 11:38:07 2019-07-31 Wed 2019 7 31 11
#> 4 1 1 2019-07-30 13:47:46 2019-07-30 Tue 2019 7 30 13
#> 5 1 1 2019-07-30 13:46:15 2019-07-30 Tue 2019 7 30 13
#> TIME_OF_DAY SBP DBP BP_CLASS HR MAP RPP PP DAYOFWK MEAL_TIME BPDELTA
#> 1 Morning 132 80 Stage 1 79 97.33333 10428 52 Thu Breakfast 52
#> 2 Morning 126 77 Elevated 62 93.33333 7812 49 Wed Breakfast 49
#> 3 Morning 128 76 Elevated 60 93.33333 7680 52 Wed Breakfast 52
#> 4 Afternoon 130 81 Stage 1 63 97.33333 8190 49 Tue Lunch 49
#> 5 Afternoon 134 83 Stage 1 62 100.00000 8308 51 Tue Lunch 51
#> MINUTE SECOND BP_TYPE SBP_CATEGORY DBP_CATEGORY
#> 1 15 54 HBPM Stage 1 Stage 1
#> 2 39 59 HBPM Elevated Normal
#> 3 38 7 HBPM Elevated Normal
#> 4 47 46 HBPM Stage 1 Stage 1
#> 5 46 15 HBPM Stage 1 Stage 1
After a quick inspection of the original bp_jhs
data set
and the newly processed data
data set, it should be evident
that there was a lot going on “under the hood” of the
process_data
function. As we can see from the column names,
the awkward nuisance of typing sys.mmhg.
,
dias.mmhg.
, pulse.bpm.
, and
datetime
have now been replaced with the more concise
SBP
, DBP
, HR
, and
DATE_TIME
names, respectively. Additionally,
MAP
, PP
, RPP
,
SBP_Category
, and DBP_Category
were all
calculated as additional columns which previously did not exist in the
data. Additionally, if the supplied data has a column corresponding to a
“date/time” format, the columns Time_of_Day
and
DAY_OF_WEEK
will also be created for ease.
names(bp_jhs)
#> [1] "DateTime" "Month" "Day" "Year" "DayofWk"
#> [6] "Hour" "Meal_Time" "Sys.mmHg." "Dias.mmHg." "bpDelta"
#> [11] "Pulse.bpm."
names(jhs_proc)
#> [1] "ID" "GROUP" "DATE_TIME" "DATE" "DAY_OF_WEEK"
#> [6] "YEAR" "MONTH" "DAY" "HOUR" "TIME_OF_DAY"
#> [11] "SBP" "DBP" "BP_CLASS" "HR" "MAP"
#> [16] "RPP" "PP" "DAYOFWK" "MEAL_TIME" "BPDELTA"
#> [21] "MINUTE" "SECOND" "BP_TYPE" "SBP_CATEGORY" "DBP_CATEGORY"
NOTE: For consistency, process_data
will coerce all column names to upper-case.
After the data has been processed, we can now utilize the built-in
metrics from the literature to characterize the blood pressure
variability. To start, the following metrics are what is currently
offered through the bp
package:
Function | Metric Name | Source |
---|---|---|
bp_arv |
Average Real Variability | Mena et al (2005) |
bp_center |
Mean and Median | Amaro Lijarcio et al (2006) |
bp_cv |
Coefficient of Variation | Munter et al (2011) |
bp_mag |
Blood Pressure Magnitude (peak and trough) | Munter et al (2011) |
bp_range |
Blood Pressure Range | Levitan et al (2013) |
bp_sv |
Successive Variation | Munter et al (2011) |
bp_sleep_metrics |
Blood Pressure Sleep Metrics | (Multiple - see documentation) |
bp_stages |
Blood Pressure Stages Classification | American Heart Association |
bp_stats |
Aggregation of statistical summaries | N/A |
dip_calc |
Nocturnal Dipping % and Classification | Okhubo et al (1997) |
Time-Dependent Dispersion Metrics
bp_arv
- Average Real Variability
bp_sv
- Successive Variation
Time-Independent Dispersion Metrics
bp_mag
- Blood Pressure Magnitude
(peak and trough)
bp_range
- Blood Pressure Range
bp_cv
- Coefficient of Variation
Sleep-dependent Metrics
dip_calc
- Nocturnal Dipping % and
Classification
1 - (avg sleep BP / avg daytime BP)
. The severity of the
dipping percentage indicates the corresponding classification of that
individual (dipper, non-dipper, reverse dipper).bp_sleep_metrics
- Sleep-specific metrics for
BP
Let’s say we are working with the bp_hypnos
and would
like to compare the time-dependent nature of the bp_arv
with the bp_sv
for each subject.
head(bp_arv(hypnos_proc, bp_type = 'both'))
#> Missing SBP and/or DBP values found in data set. Removing for calculation.
#> # A tibble: 6 × 6
#> # Groups: ID, VISIT [3]
#> ID VISIT WAKE ARV_SBP ARV_DBP N
#> <fct> <fct> <fct> <dbl> <dbl> <int>
#> 1 70417 1 0 14.2 10.6 10
#> 2 70417 1 1 9.58 5.47 20
#> 3 70417 2 0 17.7 7.57 8
#> 4 70417 2 1 11.2 8.12 17
#> 5 70422 1 0 10.5 4 5
#> 6 70422 1 1 14.9 6.62 17
head(bp_sv(hypnos_proc, bp_type = 'both'))
#> Missing SBP and/or DBP values found in data set. Removing for calculation.
#> # A tibble: 6 × 6
#> # Groups: ID, VISIT [3]
#> ID VISIT WAKE SV_SBP SV_DBP N
#> <fct> <fct> <fct> <dbl> <dbl> <int>
#> 1 70417 1 0 15.8 13 10
#> 2 70417 1 1 11.2 7.50 20
#> 3 70417 2 0 18.9 8.22 8
#> 4 70417 2 1 13.0 10.2 17
#> 5 70422 1 0 11.2 5.74 5
#> 6 70422 1 1 19.1 8.80 17
Comparing vertically can be challenging, so with some help from
dplyr
we can obtain the following:
head(dplyr::left_join(bp_arv(hypnos_proc, bp_type = 'both'), bp_cv(hypnos_proc, bp_type = 'both')))
#> Missing SBP and/or DBP values found in data set. Removing for calculation.
#> Missing SBP and/or DBP values found in data set. Removing for calculation.
#> Joining with `by = join_by(ID, VISIT, WAKE, N)`
#> # A tibble: 6 × 10
#> # Groups: ID, VISIT [3]
#> ID VISIT WAKE ARV_SBP ARV_DBP N CV_SBP CV_DBP SD_SBP SD_DBP
#> <fct> <fct> <fct> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <dbl>
#> 1 70417 1 0 14.2 10.6 10 9.54 16.3 11.8 9.86
#> 2 70417 1 1 9.58 5.47 20 6.63 7.65 8.49 5.09
#> 3 70417 2 0 17.7 7.57 8 9.46 12.3 12.9 7.43
#> 4 70417 2 1 11.2 8.12 17 8.44 11.5 11.5 7.56
#> 5 70422 1 0 10.5 4 5 5.21 7.02 7.22 4.09
#> 6 70422 1 1 14.9 6.62 17 9.86 11.5 14.9 7.59
Note that this is possible thanks to the work we did in standardizing column names from the processing step.
Because the hypnos_proc
data contains BP readings during
sleep, sleep-specific metrics through the bp_sleep_metrics
function can be used to garner further insight:
bp_sleep_metrics(hypnos_proc)
#> $Sleep_Counts
#> # A tibble: 10 × 8
#> ID VISIT GROUP N_total N_wake N_sleep HRS_wake HRS_sleep
#> <fct> <fct> <fct> <int> <int> <int> <int> <int>
#> 1 70417 1 1 30 20 10 17 8
#> 2 70417 2 1 25 17 8 16 8
#> 3 70422 1 1 22 17 5 16 5
#> 4 70422 2 1 21 14 7 11 7
#> 5 70424 1 1 26 20 6 16 5
#> 6 70424 2 1 23 17 6 16 6
#> 7 70435 1 1 29 23 6 17 6
#> 8 70435 2 1 29 20 9 16 7
#> 9 70439 1 1 22 14 8 13 8
#> 10 70439 2 1 23 17 6 16 6
#>
#> $SBP_Sleep_Summary
#> # A tibble: 10 × 11
#> # Groups: ID, VISIT [10]
#> ID VISIT GROUP sleep_SBP wake_SBP sleep_SBP_sd wake_SBP_sd presleep_SBP
#> <fct> <fct> <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 70417 1 1 123. 128 11.8 8.49 132.
#> 2 70417 2 1 136. 136. 12.9 11.5 140
#> 3 70422 1 1 139. 151. 7.22 14.9 148
#> 4 70422 2 1 125. 152. 13.5 16.7 132.
#> 5 70424 1 1 110. 128. 14.2 13.3 128.
#> 6 70424 2 1 113 123. 8.65 15.6 132
#> 7 70435 1 1 106. 129. 10.7 10.2 145
#> 8 70435 2 1 136. 123. 9.55 14.7 144.
#> 9 70439 1 1 167 160. 7.09 15.1 159
#> 10 70439 2 1 149. 144. 15.7 9.17 138
#> # ℹ 3 more variables: prewake_SBP <dbl>, postwake_SBP <dbl>, lowest_SBP <dbl>
#>
#> $DBP_Sleep_Summary
#> # A tibble: 10 × 11
#> # Groups: ID, VISIT [10]
#> ID VISIT GROUP sleep_DBP wake_DBP sleep_DBP_sd wake_DBP_sd presleep_DBP
#> <fct> <fct> <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 70417 1 1 60.5 66.6 9.86 5.09 69
#> 2 70417 2 1 60.5 65.6 7.43 7.56 74.5
#> 3 70422 1 1 58.2 65.9 4.09 7.59 70.5
#> 4 70422 2 1 60.6 69.5 6.40 7.75 64
#> 5 70424 1 1 54.6 67.8 7.99 8.31 55
#> 6 70424 2 1 55 61.5 8 6.98 69
#> 7 70435 1 1 63 82.1 6.42 6.55 92
#> 8 70435 2 1 79.2 72.5 8.61 8.13 79.5
#> 9 70439 1 1 62.6 69.3 4.93 19.9 63
#> 10 70439 2 1 60.8 56.8 3.31 3.91 56
#> # ℹ 3 more variables: prewake_DBP <dbl>, postwake_DBP <dbl>, lowest_DBP <dbl>
#>
#> $Sleep_Metrics
#> # A tibble: 10 × 17
#> # Groups: ID, VISIT, GROUP [10]
#> ID VISIT GROUP dip_calc_SBP noct_fall_SBP ST_mbps_SBP PW_mbps_SBP
#> <fct> <fct> <fct> <dbl> <dbl> <dbl> <dbl>
#> 1 70417 1 1 0.0359 1.16 2.67 -3
#> 2 70417 2 1 -0.00450 1.09 -9 -22.5
#> 3 70422 1 1 0.0819 1.09 4.17 5.5
#> 4 70422 2 1 0.174 1.05 35.7 33.7
#> 5 70424 1 1 0.141 1.24 1.33 1.33
#> 6 70424 2 1 0.0848 1.21 11.7 7
#> 7 70435 1 1 0.179 1.37 11 11.5
#> 8 70435 2 1 -0.104 1.06 -4.5 -8.90
#> 9 70439 1 1 -0.0442 0.995 19.2 9
#> 10 70439 2 1 -0.0329 0.950 8.67 -9
#> # ℹ 10 more variables: ME_SBP_avg <dbl>, ME_SBP_diff <dbl>, wSD_SBP <dbl>,
#> # dip_calc_DBP <dbl>, noct_fall_DBP <dbl>, ST_mbps_DBP <dbl>,
#> # PW_mbps_DBP <dbl>, ME_DBP_avg <dbl>, ME_DBP_diff <dbl>, wSD_DBP <dbl>
Turning back to the bp_jhs
data set, let’s examine the
peaks and troughs of the BP readings. We would call the
bp_mag
function on our data.
head(bp_mag(jhs_proc, bp_type = 'both'))
#> # A tibble: 1 × 6
#> ID Peak_SBP Peak_DBP Trough_SBP Trough_DBP N
#> <fct> <dbl> <dbl> <dbl> <dbl> <int>
#> 1 1 20.3 15.1 19.7 17.9 222
Here, we notice something different. Because there weren’t
ID
, VISIT
, or WAKE
columns, the
bp_mag
aggregated everything together. This is technically
correct, but say we wanted to glean more information by breaking our
data down by DATE
instead; we would need to include the
inc_date = TRUE
optional argument to the function.
tail(bp_mag(jhs_proc, inc_date = TRUE, bp_type = 'both'))
#> # A tibble: 6 × 7
#> # Groups: ID [1]
#> ID DATE Peak_SBP Peak_DBP Trough_SBP Trough_DBP N
#> <fct> <date> <dbl> <dbl> <dbl> <dbl> <int>
#> 1 1 2019-07-26 8.25 3.5 6.75 2.5 4
#> 2 1 2019-07-28 5.5 3 4.5 3 4
#> 3 1 2019-07-29 7 2.75 9 2.25 4
#> 4 1 2019-07-30 2 1 2 1 2
#> 5 1 2019-07-31 1 0.5 1 0.5 2
#> 6 1 2019-08-01 0 0 0 0 1
Interpretation: While it may not seem
obvious at first glance, the blood pressure magnitude (whether a peak or
a trough) is calculated as peak = max(BP) − mean(BP)
and trough = mean(BP) − min(BP)
where BP could correspond to either SBP or DBP. If we manually inspect
the data from 2019-07-31
we see that N = 2 measurements and
within the bp_jhs
data set we see the two measurements are
126 and 128 for SBP and 77, and 76 for DBP. $\bar{x}_{SBP} = \frac{(126+128)}{2} = 127$
and $\bar{x}_{DBP} = \frac{(78+76)}{2} =
76.5$ so the respective peak and trough values from our output
make sense.
So far, we have processed the original data and ran a couple metrics
to get a clearer picture of the variability, now let’s visualize it.
Though the processed data can easily be incorporated into other
visualization packages or code (such as ggplot which we will demonstrate
in the first example below with bp_mag
), the following
visuals are currently included with the bp
package:
Function | Visual |
---|---|
bp_scatter |
Scatter plot of BP stages (American Heart Association) |
bp_ts_plots |
Time series plots |
bp_hist |
Histograms of BP stages |
dip_class_plot |
Dipping % category plot |
bp_report |
Exportable report of BP summary |
dow_tod_plots |
Day of Week / Time of Day chart |
The bp_hist
returns three histograms of all readings
corresponding to total number within each stage, frequency of SBP
readings, and frequency of DBP readings. Furthermore, it breaks the data
down by color according to which blood pressure stage it falls
under:
bp_hist(jhs_proc)
#> Warning in get_plot_component(plot, "guide-box"): Multiple components found;
#> returning the first one. To return all, use `return_all = TRUE`.
Let’s now suppose that we wish to break down our readings by Time of
Day and Day of Week. For this, we can implement the
dow_tod_plots
function. Because this function is mainly
used as a helper function for the bp_report
function, we
need to add a couple steps using the gridExtra
package
bptable_ex <- dow_tod_plots(jhs_proc)
#gridExtra::grid.arrange(bptable_ex[[1]], bptable_ex[[2]], bptable_ex[[3]], bptable_ex[[4]], nrow = 2)
As a final step before returning to our other example, let’s compile
everything that we have done so far into a more compact and digestible
report that visualizes everything simultaneously. To do so, we will rely
on the bp_report
function, which will generate a report in
PDF (although other formats such as PNG are available):
Suppose we wanted to look at the observations for the
bp_jhs
data set over time. The time series plotting
capabilities allow this to be visualized. The output returns two plots,
one for the total duration through time, and another showing repeated
measurements within a 24 hour period (by hour). In the event that there
are more than one series of recordings (such as the
bp_hypnos
data set where there are two visits per subject),
the wrap_var
and group_var
function arguments
can be employed.
Suppose now that we turn our attention back to the
bp_hypnos
example, suppose now we wish to examine sleep
patterns. Using the dipping category plot we can analyze BP behavior
during sleep
dip_class_plot(hypnos_proc)
#> Warning in ggplot2::geom_segment(ggplot2::aes(x = extreme_thresh * 100, : All aesthetics have length 1, but the data has 10 rows.
#> ℹ Please consider using `annotate()` or provide this layer with data containing
#> a single row.
#> Warning in ggplot2::geom_segment(ggplot2::aes(x = x_min, y = extreme_thresh * : All aesthetics have length 1, but the data has 10 rows.
#> ℹ Please consider using `annotate()` or provide this layer with data containing
#> a single row.
#> Warning in ggplot2::geom_text(ggplot2::aes(x = x_min * 0.9 + 1, y = 0, label = "INV"), : All aesthetics have length 1, but the data has 10 rows.
#> ℹ Please consider using `annotate()` or provide this layer with data containing
#> a single row.
#> Warning in ggplot2::geom_text(ggplot2::aes(x = x_min * 0.9 + 1, y = dip_thresh * : All aesthetics have length 1, but the data has 10 rows.
#> ℹ Please consider using `annotate()` or provide this layer with data containing
#> a single row.
#> Warning in ggplot2::geom_text(ggplot2::aes(x = x_max * 0.9 + 1, y = y_max, : All aesthetics have length 1, but the data has 10 rows.
#> ℹ Please consider using `annotate()` or provide this layer with data containing
#> a single row.
#> Warning in ggplot2::geom_text(ggplot2::aes(x = x_min * 0.9 + 1, y = y_max, : All aesthetics have length 1, but the data has 10 rows.
#> ℹ Please consider using `annotate()` or provide this layer with data containing
#> a single row.
As our understanding of cardiovascular disease continues to grow, this package will remain ongoing project. As such, collaboration is highly encouraged. Corrections to existing metrics, extensions or new method proposals and visualizations, and code optimization are all welcome.
In the short term, the following new features are to be incorporated with the next release of the package:
bp_report
function to include more
visuals on another page, and include the ability to break down visuals
by individuals (if data includes multiple subjects)Mancia, G., Di Rienzo, M., & Parati, G. (1993). Ambulatory blood pressure monitoring use in hypertension research and clinical practice. Hypertension, 21(4), 510-524.
Levitan, E., Kaciroti, N., Oparil, S. et al. Relationships between metrics of visit-to-visit variability of blood pressure. J Hum Hypertens 27, 589–593 (2013). doi: 10.1038/jhh.2013.19
Muntner, Paula,b; Joyce, Carac; Levitan, Emily B.a; Holt, Elizabethd; Shimbo, Daichie; Webber, Larry S.c; Oparil, Suzanneb; Re, Richardf; Krousel-Wood, Maried,g Reproducibility of visit-to-visit variability of blood pressure measured as part of routine clinical care, Journal of Hypertension: December 2011 - Volume 29 - Issue 12 - p 2332-2338 doi: 10.1097/HJH.0b013e32834cf213
O’Brien E, Sheridan J, O’Malley K . Dippers and non-dippers. Lancet 1988; 2: 397.
Ohkubo T, Imai Y, Tsuji I, Nagai K, Watanabe N, Minami N, Kato J, Kikuchi N, Nishiyama A, Aihara A, Sekino M, Satoh H, Hisamichi S. Relation between nocturnal decline in blood pressure and mortality. The Ohasama Study. Am J Hypertens. 1997 Nov;10(11):1201-7. doi: 10.1016/s0895-7061(97)00274-4. PMID: 9397237.
Mena L, Pintos S, Queipo NV, Aizpúrua JA, Maestre G, Sulbarán T. A reliable index for the prognostic significance of blood pressure variability. J Hypertens. 2005 Mar;23(3):505-11. doi: 10.1097/01.hjh.0000160205.81652.5a. PMID: 15716690.
Holt-Lunstad J, Jones BQ, Birmingham W. The influence of close relationships on nocturnal blood pressure dipping. Int J Psychophysiol. 2009 Mar;71(3):211-7. doi: 10.1016/j.ijpsycho.2008.09.008. Epub 2008 Oct 5. PMID: 18930771.
Schwenck J. Riding for Research: A 5,775-mile Cycling Journey Across North America. Harvard Dataverse https://dataverse.harvard.edu/dataverse/r4r
Webb S. AHA 2019 Heart Disease and Stroke Statistics. American College of Cardiology. https://www.acc.org/latest-in-cardiology/ten-points-to-remember/2019/02/15/14/39/aha-2019-heart-disease-and-stroke-statistics
Bilo G, Grillo A, Guida V, Parati G. Morning blood pressure surge: pathophysiology, clinical relevance and therapeutic aspects. Integr Blood Press Control. 2018;11:47-56. Published 2018 May 24. https://doi.org/10.2147/IBPC.S130277
Irina Gaynanova, Naresh Punjabi, Ciprian Crainiceanu, Modeling continuous glucose monitoring (CGM) data during sleep, Biostatistics, 2020. https://doi.org/10.1093/biostatistics/kxaa023