---
title: "Pediatric Blood Pressure Distributions"
output:
 rmarkdown::html_vignette:
   toc: true
   number_sections: true
bibliography: references.bib
vignette: >
 %\VignetteIndexEntry{Pediatric Blood Pressure Distributions}
 %\VignetteEngine{knitr::rmarkdown}
 %\VignetteEncoding{UTF-8}
---


```{r label = "setup", include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, fig.align = "center")
library(pedbp)
```


# Introduction

Part of the work of @martin2022machine required transforming blood
pressure measurement into percentiles based on published norms.  This
work was complicated by the fact that data for pediatric blood pressure
percentiles is sparse and generally only applicable to children at least one
year of age and requires height, a commonly unavailable data point in
electronic health records for a variety of reasons.

A solution to building pediatric blood pressure percentiles was developed and
is presented here for others to use.  Inputs for the developed method are:

1. Patient sex (male/female) _required_
2. Systolic blood pressure (mmHg) _required_
3. Diastolic blood pressure (mmHg) _required_
4. Patient height (cm) _if known_.

Given the inputs, the following logic is used to determine which data sets
will be used to inform the blood pressure percentiles.  Under one year of
age, the data from @gemelli1990longitudinal will be used; a height input is
not required for this patient subset. For those at least one year of age with
a known height, data from @nhlbi2011exper (hereafter referred to as
'NHLBI/CDC' as the report incorporates recommendations and inputs from the
National Heart, Lung, and Blood Institute [NHLBI] and the Centers for Disease
Control and Prevention [CDC]). If height is unknown and age is at least three
years, then data from @lo2013prehypertension is used.  Lastly, for children
between one and three years of age with unknown height, blood pressure
percentiles are estimated by the NHLBI/CDC data using as a default the median
height for each patient's sex and age.


```{r echo = FALSE, results = "asis"}
cat(paste0("<img src=\"", normalizePath(system.file("images", "flowchart.png", package = "pedbp")), "\">\n"))
```



# Estimating Pediatric Blood Pressure Distributions

There are two functions provided for working with blood pressure
distributions.  These methods use Gaussian distributions for both systolic
and diastolic blood pressures with means and standard deviations either
explicitly provided in an aforementioned source or derived by optimizing the parameters
such that the sum of squared errors between the provided quantiles from an
aforementioned source and the distribution quantiles is minimized.  The
provided functions, a distribution function and a quantile function, follow a
similar naming convention to the distribution functions found in the stats
library in R.


```{r Distribution Function}
args(p_bp)

# Quantile Function
args(q_bp)
```



Both methods expect an age in months and an indicator for sex.  If height is
missing, e.g., NA, then the default height percentile of 50 will be used as
applicable based on the patient's age group.  The end user may modify the
default height percentile.

If height is entered, then the height percentile is determined via an LMS
method for age and sex using corresponding LMS data from the CDC (more
information on LMS methods and data is provided later in this vignette). The
parameters for the blood pressure distribution are found in a look up table
using the nearest age and height percentile.

## Percentiles

What percentile for systolic and diastolic blood pressure is 100/60 for a 44
month old male with unknown height?


```{r }
p_bp(q_sbp = 100, q_dbp = 60, age = 44, male = 1)
```


Those percentiles would be modified if height was 183 cm:

```{r }
p_bp(q_sbp = 100, q_dbp = 60, age = 44, male = 1, height = 183)
```


The package can also be used to determine the blood pressure percentiles
corresponding to a child of a given height percentile.
First find the height quantile using the q_stature_for_age function, and then
use this height measurement (provided in centimeters) as the height input for
the p_bp function.

```{r }
ht <- q_stature_for_age(p = 0.90, age = 44, male = 1)
ht

p_bp(q_sbp = 100, q_dbp = 60, age = 44, male = 1, height = ht)
```


A plotting method to show where the observed blood pressures are on the
distribution function is also provided.

```{r fig.width = 5, fig.height = 5}
bp_cdf(age = 44, male = 1, height = ht, sbp = 100, dbp = 60)
```




Vectors of blood pressures can be used as well.  NA values will return NA.

```{r }
bps <-
  p_bp(
         q_sbp  = c(100, NA, 90)
       , q_dbp  = c(60, 82, 48)
       , age    = 44
       , male   = 1
       , height = ht
      )
bps
```


If you want to know which data source was used in computing each of the
percentile estimates you can look at the bp_params attribute:

```{r }
attr(bps, "bp_params")
str(bps)
```


## Quantiles

If you have a percentile value and want to know the associated
systolic and diastolic blood pressures:


```{r }
q_bp(
       p_sbp = c(0.701, NA, 0.36)
     , p_dbp = c(0.85, 0.99, 0.50)
     , age = 44
     , male = 1
     , height = ht
    )
```



## Working With More Than One Patient

The p_bp and q_bp methods are designed accept vectors for each of the arguments.
These methods expected each argument to be length 1 or all the same length.


```{r label = "bp_batch_example"}
eg_data <- read.csv(system.file("example_data", "for_batch.csv", package = "pedbp"))
eg_data

bp_percentiles <-
  p_bp(
         q_sbp  = eg_data$sbp..mmHg.
       , q_dbp  = eg_data$dbp..mmHg.
       , age    = eg_data$age
       , male   = eg_data$male
       , height = eg_data$height
       )
bp_percentiles

str(bp_percentiles)
```


Going from percentiles back to quantiles:

```{r }
q_bp(
       p_sbp  = bp_percentiles$sbp_percentile
     , p_dbp  = bp_percentiles$dbp_percentile
     , age    = eg_data$age
     , male   = eg_data$male
     , height = eg_data$height
     )
```


# Blood Pressure Charts

## When Height is Unknown or Irrelevant

The following graphic shows the percentile curves by age and sex when height
is unknown, or irrelevant (for those under 12 months of age).


```{r label = "chart1_setup", echo = FALSE}
percentile_factor <- function(p) {
  factor(p, levels = sort(unique(p)), labels = paste0(sort(unique(p)) * 100, "th"))
}

q_bp_with_source <- function(bpp, age, male, height = NA, height_percentile = 0.5) {
  d <- q_bp(bpp, bpp, age, male, height, height_percentile)
  data.table::data.table(source = attr(d, "bp_params")$source, sbp = d$sbp, dbp = d$dbp)
}

d <- data.table::CJ(male = 0:1
                    , age = seq(min(bp_parameters$age), max(bp_parameters$age), by = 0.5)
                    # , age = unique(bp_parameters$age)
                    , bp_percentile = c(5, 10, 25, 50, 75, 90, 95) / 100)

d <- d[, as.list(q_bp_with_source(bp_percentile, age, male))
       , by = .(male, age, bp_percentile)]

d <- data.table::melt(d
                      , id.vars = c("source", "male", "age", "bp_percentile")
                      , measure.vars = c("sbp", "dbp")
                      )
d[, variable := factor(variable, c("sbp", "dbp"), c("Systolic", "Diastolic"))]
d[, bp_percentile := percentile_factor(bp_percentile)]

# d[, .(range(age)), by = .(source)]
bkgrnd <-
  data.table::data.table(
      source = c("Gemelli", "NHLBI", "Lo")
    , xmin   = c(0, 12, 36)
    , xmax   = c(12, 36, 204)
    , ymin   = rep(-Inf, 3)
    , ymax   = rep(Inf, 3)
    )

g <- function(d) {
  ggplot2::ggplot(d) +
    ggplot2::theme_bw() +
    ggplot2::aes(x = age, y = value, linetype = variable, color = bp_percentile) +
    ggplot2::geom_rect(data = bkgrnd
                       , inherit.aes = FALSE
                       , alpha = 0.3
                       , mapping = ggplot2::aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = source)) +
    ggplot2::geom_line() +
    ggplot2::facet_grid( ~ factor(male, 0:1, c("Female", "Male"))) +
    ggplot2::scale_x_continuous(name = "Age"
                                , breaks = seq(0, max(d$age) + 12, by = 12)
                                , labels = paste(
                                                   paste0(seq(0, max(d$age) + 12, by = 12), "m")
                                                 , paste0(seq(0, max(d$age) + 12, by = 12) / 12, "yr")
                                                 , sep = "\n")
                                ) +
    ggplot2::scale_y_continuous(name = "mmHg",breaks=c(0, 30, 60, 90, 120), limits = c(15, 140)) +
    ggplot2::scale_linetype(name = "") +
    ggplot2::scale_color_hue(name = "BP\nPercentile") +
    ggplot2::scale_fill_manual(name = "Data\nSource", values = c("Gemelli" = ggplot2::alpha("#236192", 0.5)
                                                                , "NHLBI"  = ggplot2::alpha("#6F263D", 0.5)
                                                                , "Lo"     = ggplot2::alpha("#A2AAAD", 0.5)
                                                                )) +
    ggplot2::guides(
                    linetype = ggplot2::guide_legend(order = 1, ncol = 1),
                    fill     = ggplot2::guide_legend(order = 2, ncol = 1),
                    color    = ggplot2::guide_legend(order = 3, ncol = 4)
                    ) +
    ggplot2::theme(
                   legend.position = "bottom"
                   )
}
```




```{r label = "chart1_female", echo = FALSE, fig.width = 8, fig.height = 6}
g(d[male == 0])
```




```{r label = "chart1_male", echo = FALSE, fig.width = 8, fig.height = 6}
g(d[male == 1])
```



## Median Blood Pressures -- Varying default height percentile

If height is unknown, there will be no difference in the estimated percentile
for blood pressures when modifying the default height_percentile with the
exception of values for patients between the ages of 12 and 36 months.
Patients under 12 months of age have percentiles estimated using data from
@gemelli1990longitudinal which does not consider height (length).  For
patients over 36 months of age data from @lo2013prehypertension, which also
does not consider height, is used.

The following graphic shows the median blood pressure in mmHg by age when
varying the default height percentile used.  The colors refer to the height
percentile.


```{r label = "chart2_setup", echo = FALSE, results = FALSE}
d <- data.table::CJ(male = 0:1
                    # , age = unique(bp_parameters$age)
                    , age = seq(min(bp_parameters$age), max(bp_parameters$age), by = 0.5)
                    , bp_percentile = 50 / 100
                    , height_percentile = unique(na.omit(bp_parameters$height_percentile)) / 100)
d <- d[, as.list(q_bp_with_source(bp_percentile, age, male, height_percentile = height_percentile))
       , by = .(male, age, bp_percentile, height_percentile)]

d <- data.table::melt(d
                      , id.vars = c("source", "male", "age", "bp_percentile","height_percentile")
                      , measure.vars = c("sbp", "dbp")
                      )
d[, variable := factor(variable, c("sbp", "dbp"), c("Systolic", "Diastolic"))]
d[, height_percentile := percentile_factor(height_percentile)]
d <- subset(d, age <= 84)
d[, range(age), by = .(source)]
bkgrnd <-
  data.table::data.table(
      source = c("Gemelli", "NHLBI", "Lo")
    , xmin   = c(0, 12, 36)
    , xmax   = c(12, 36, max(d$age))
    , ymin   = rep(-Inf, 3)
    , ymax   = rep(Inf, 3)
    )

g <- function(d) {
  ggplot2::ggplot(d) +
    ggplot2::theme_bw() +
    ggplot2::aes(x = age, y = value, linetype = variable, color = height_percentile) +
    ggplot2::geom_rect(data = bkgrnd
                       , inherit.aes = FALSE
                       , alpha = 0.3
                       , mapping = ggplot2::aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = source)) +
    ggplot2::geom_line() +
    ggplot2::facet_grid( ~ factor(male, 0:1, c("Female", "Male"))) +
    ggplot2::scale_x_continuous(name = "Age"
                                , breaks = seq(0, 84, by = 12)
                                , labels = paste(
                                                   paste0(seq(0, 84, by = 12), "m")
                                                 , paste0(seq(0, 84, by = 12) / 12, "yr")
                                                 , sep = "\n")
                                ) +
    ggplot2::scale_y_continuous(name = "Median BP (mmHg)",breaks=c(0, 30, 60, 90, 120), limits = c(15, 140)) +
    ggplot2::scale_linetype(name = "") +
    ggplot2::scale_color_hue(name = "Height\nPercentile") +
    ggplot2::scale_fill_manual(name = "Data\nSource", values = c("Gemelli" = ggplot2::alpha("#236192", 0.5)
                                                                , "NHLBI"  = ggplot2::alpha("#6F263D", 0.5)
                                                                , "Lo"     = ggplot2::alpha("#A2AAAD", 0.5)
                                                                )) +
    ggplot2::guides(
                    linetype = ggplot2::guide_legend(order = 1, ncol = 1),
                    fill     = ggplot2::guide_legend(order = 2, ncol = 1),
                    color    = ggplot2::guide_legend(order = 3, ncol = 4)
                    ) +
    ggplot2::theme(
                   legend.position = "bottom"
                   )
}
```




```{r label = "chart2_female", echo = FALSE, fig.width = 8, fig.height = 6}
g(d[male == 0])
```




```{r label = "chart2_male", echo = FALSE, fig.width = 8, fig.height = 6}
g(d[male == 1])
```



## Median Blood Pressures for Children with Known Heights

The following chart shows the median blood pressure by age for different
heights based on percentiles for age.


```{r label = "chart3", echo = FALSE, results = "hide"}
d <- data.table::CJ(male = 0:1
                    , age = seq(min(bp_parameters$age), max(bp_parameters$age), by = 0.5)
                    , bp_percentile = 50 / 100
                    , height_percentile = unique(na.omit(bp_parameters$height_percentile)) / 100)

d[, height := NA_real_]
d[age < 36, height := q_length_for_age_inf(height_percentile, age, male), by = .(male, age, height_percentile)]
d[age >= 36, height := q_stature_for_age(height_percentile, age, male), by = .(male, age, height_percentile)]


d <-
  d[, as.list(q_bp_with_source(bp_percentile, age, male, height)) , by = .(male, age, bp_percentile, height_percentile)]

d <- data.table::melt(d
                      , id.vars = c("source", "male", "age", "bp_percentile", "height_percentile")
                      , measure.vars = c("sbp", "dbp")
                      )

d[, variable := factor(variable, c("sbp", "dbp"), c("Systolic", "Diastolic"))]
d[, height_percentile := percentile_factor(height_percentile)]

d[, .(xmin = min(age), xmax = max(age)), by = .(source)]
bkgrnd <- data.table::data.table(source = c("Gemelli", "NHLBI"), xmin = c(0, 12), xmax = c(12, max(d$age)), ymin = c(-Inf, -Inf), ymax = c(Inf, Inf))

g <- function(d) {
  ggplot2::ggplot(d) +
    ggplot2::theme_bw() +
    ggplot2::geom_rect(data = bkgrnd
                       , inherit.aes = FALSE
                       , alpha = 0.3
                       , mapping = ggplot2::aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = source)) +
    ggplot2::aes(x = age, y = value, linetype = variable, color = height_percentile) +
    ggplot2::geom_line() +
    ggplot2::facet_grid( ~ factor(male, 0:1, c("Female", "Male"))) +
    ggplot2::scale_x_continuous(name = "Age"
                                , breaks = seq(0, max(d$age) + 12, by = 12)
                                , labels = paste(
                                                   paste0(seq(0, max(d$age) + 12, by = 12), "m")
                                                 , paste0(seq(0, max(d$age) + 12, by = 12) / 12, "yr")
                                                 , sep = "\n")
                                ) +
    ggplot2::scale_y_continuous(name = "Median BP (mmHg)",breaks=c(0, 30, 60, 90, 120), limits = c(15, 140)) +
    ggplot2::scale_linetype(name = "") +
    ggplot2::scale_color_hue(name = "Height\nPercentile") +
    ggplot2::scale_fill_manual(name = "Data\nSource", values = c("Gemelli" = ggplot2::alpha("#236192", 0.5)
                                                                , "NHLBI"  = ggplot2::alpha("#6F263D", 0.5)
                                                                , "Lo"     = ggplot2::alpha("#A2AAAD", 0.5)
                                                                )) +
    ggplot2::guides(
                    linetype = ggplot2::guide_legend(order = 1, ncol = 1),
                    fill     = ggplot2::guide_legend(order = 2, ncol = 1),
                    color    = ggplot2::guide_legend(order = 3, ncol = 4)
                    ) +
    ggplot2::theme(
                   legend.position = "bottom"
                   # , legend.direction = "vertical"
                   )
}
```




```{r label = "chart3_female", echo = FALSE, fig.width = 8, fig.height = 6}
g(d[male == 0])
```




```{r label = "chart3_male", echo = FALSE, fig.width = 8, fig.height = 6}
g(d[male == 1])
```


# Shiny Application

An interactive [Shiny](https://shiny.rstudio.com/) application is also
available. After installing the pedbp package and the suggested packages, you
can run the app locally via


```{r label = "shiny", eval = FALSE}
shiny::runApp(system.file("shinyapps", "pedbp", package = "pedbp"))
```


The shiny application allows for interactive exploration of blood pressure
percentiles for an individual patient and allows for batch processing a set
of patients as well.

An example input file for batch processing is provided within the package an
can be accessed via:

```{r label = "shiny_batch_example_file", eval = FALSE}
system.file("example_data", "for_batch.csv", package = "pedbp")
```


# CDC Growth Charts


```{r label = 'lms_data_table', include = FALSE}
lms <- data.table::setDT(data.table::copy(pedbp:::cdc_lms_data))
```


Using the [Percentile Data Files with LMS values](https://www.cdc.gov/growthcharts/percentile_data_files.htm)
provided by the CDC, we provide eight distribution tools:

1. weight for age for infants
2. length for age for infants
3. weight for length for infants
4. head circumference for age
5. weight for stature
6. weight for age
7. stature for age
8. BMI for age

All lengths/heights are in centimeters, ages in months, and weights in
kilograms.

The length-for-age and stature-for-age methods were needed for the blood
pressure methods above.

All methods use the published LMS parameters to define z-scores,
percentiles, and quantiles for skewed distributions.  L is a $\lambda$
parameter, the Box-Cox transformation power; $M$ the median value, and $S$ a
generalized coefficient of variation.  For a given percentile or z-score, the
corresponding physical measurement, $X,$ is defined as

$$X = \begin{cases}
   M \left(1 + \lambda S Z \right)^{\frac{1}{\lambda}} & \lambda \neq 0 \\
   M \exp\left( S Z \right) & \lambda = 0.
\end{cases}$$

From this we can get the z-score for a given measurement $X:$

$$ Z = \begin{cases}
  \frac{\left(\frac{X}{M}\right)^{\lambda} - 1}{\lambda S} & \lambda \neq 0 \\
  \frac{\log\left(\frac{X}{M}\right) }{ S } & \lambda = 0.
  \end{cases}$$

Percentiles are determined using the standard normal distribution of z-scores.

For all eight of the noted methods we provide a distribution function,
quantile function, and function that returns z-scores.

Estimates for finer differences in age, for example, are possible for these
methods than the blood pressure methods.  This is due to the permissible
linear interpolation of the LMS parameters for the CDC charts whereas the
blood pressure assessment is restricted to values within a look up table.

## Length and Stature For Age

A 13 year old male standing 154 cm tall is in the
`r  paste0(round(p_stature_for_age(q = 154, age = 13 * 12, male = 1L) * 100, 2), "th")  `
percentile:

```{r }
p_stature_for_age(q = 154, age = 13 * 12, male = 1L)
```


To find the height corresponding to the 50th, 60th, and 75th percentiles for
height for 9.5-year old girls:

```{r }
q_stature_for_age(p = c(0.50, 0.60, 0.75), age = 9.5 * 12, male = 0L)
```


If you want the standard score for a percentile, you can use qnorm around
p_stature_for_age, or simply call z_stature_for_age.

```{r }
qnorm(p_stature_for_age(q = 154, age = 13 * 12, male = 1L))
z_stature_for_age(q = 154, age = 13 * 12, male = 1L)
```


A length/height for age chart based on the CDC data:

```{r echo = FALSE}
lfa <- data.table::CJ(p = c(0.01, 0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95, 0.99),
                      age = seq(0, 18*12, by = 3),
                      male = 0:1)

lfa[age <  36, l := q_length_for_age_inf(p, age, male), by = .(p, age, male)]
lfa[age >= 36, l := q_stature_for_age(p, age, male), by = .(p, age, male)]
lfa[, lab := paste(p * 100, "%")]
lfa[, male := factor(male, 0:1, c("Female", "Male"))]
lfa[, p := percentile_factor(p)]

g <- function(lfa) {
  ggplot2::ggplot(lfa) +
    ggplot2::theme_bw() +
    ggplot2::aes(x = age, y = l, color = p) +
    ggplot2::geom_line() +
    ggplot2::facet_wrap( ~ male) +
    ggplot2::scale_x_continuous(name = "Age"
                                , breaks = seq(0, max(lfa$age) + 12, by = 12)
                                , labels = paste(
                                                   paste0(seq(0, max(lfa$age) + 12, by = 12), "m")
                                                 , paste0(seq(0, max(lfa$age) + 12, by = 12) / 12, "yr")
                                                 , sep = "\n")
                                ) +
    ggplot2::scale_y_continuous(name = "Length or Height (cm)") +
    ggplot2::scale_color_hue(name = "Length for Age percentile") +
    ggplot2::theme(
                   legend.position = "bottom"
                   )
}
```




```{r label = "lfa_female", echo = FALSE, fig.width = 8, fig.height = 6}
g(lfa[male == "Female"])
```




```{r label = "lfa_male", echo = FALSE, fig.width = 8, fig.height = 6}
g(lfa[male == "Male"])
```


## Weight for Age

There are two methods for determining weight for age both based on CDC
National Center for Health Statistics data: one for infants (weighed laying
flat) up to 36 months [@cdc_weight_for_age_0_36], 
and one for children (weighed on a standing scale) over 24 months
[@cdc_weight_for_age].

A 33 pound (
`r  round(33 * 0.453592, 2) `
kg) 4 year old male is in the
`r  paste0(round(100 * p_weight_for_age(33 * 0.453592, age = 4 * 12, male = 1), 2), 'th')  `
percentile.

```{r }
p_weight_for_age(33 * 0.453592, age = 4 * 12, male = 1)
```


The 20th percentile weight for an 18 month old infant female is
`r  round(q_weight_for_age_inf(p = 0.2, age = 18, male = 0), 5) `
kg.

```{r }
round(q_weight_for_age_inf(p = 0.2, age = 18, male = 0), 5)
```


## Weight for Length or Stature

Similar to weight-for-age, there are two methods for determining
weight-for-length.  Both methods utilize data from the CDC National Center for
Health Statistics.  The first method is used for infants under 36 months
(used for children who are measured laying flat), and the second is used for
child over 24 months (used for children able to be measured while standing
up).  The overlapping range between the methods will differ.

The median weight for a 95 cm long infant
`r  q_weight_for_length_inf(0.5, 95, 1)  `
kg, whereas the median weight for a 95 cm tall child is
`r  q_weight_for_stature(0.5, 95, 1)  `
kg.


```{r }
q_weight_for_length_inf(0.5, 95, 1)
q_weight_for_stature(0.5, 95, 1)
```


A 5.8 kg, 61 cm long female infant is in the
`r  p_weight_for_length_inf(5.8, 61, 0)  `
weight percentile.

```{r }
p_weight_for_length_inf(5.8, 61, 0)
```


## BMI for Age

For a twelve year old, a BMI of 22.2 corresponds to the
`r  paste0(round(p_bmi_for_age(q = 22.2, age = 144, male = 0) * 100, 2), "th")  `
BMI percentile for a female, and the
`r  paste0(round(p_bmi_for_age(q = 22.2, age = 144, male = 1) * 100, 2), "th")  `
BMI percentile for a male.

```{r }
p_bmi_for_age(q = 22.2, age = c(144, 144), male = c(0, 1))
```


The median BMI values for a 10 year old male and females are:

```{r }
q_bmi_for_age(p = 0.5, age = c(120, 120), male = c(1, 0))
```


## Head Circumference

A 10 month old male has a median head circumference of
`r  q_head_circ_for_age(0.5, 10, 1)  `
cm.

A head circumference of 42 cm for an 8 month old female is in the
`r  paste0(round(100*p_head_circ_for_age(42, 8, 0), 5), "th") `
percentile.


```{r }
q_head_circ_for_age(0.5, 10, 1)
p_head_circ_for_age(42, 8, 0)
```



# Additional Utilities

## Estimating Gaussian Mean and Standard Deviation

The NHLBI data for blood pressures provided values in percentiles.  To get a
mean and standard deviation that would work well for estimating other
percentiles and quantiles via a Gaussian distribution we optimized for values
of the mean and standard deviation such that for the provided quantiles $q_i$
at the $p_i$ percentiles and $X \sim N\left(\mu, \sigma\right)$,

$$ \sum_{i} \left(\Pr(X \leq q_i) - p_i \right)^2, $$

was minimized.  The NHLBI data is provided to the end user.

```{r }
data(list = "nhlbi_bp_norms", package = "pedbp")
str(nhlbi_bp_norms)
```


For an example of how we fitted the parameters:

```{r }
d <- nhlbi_bp_norms[nhlbi_bp_norms$age == 144 & nhlbi_bp_norms$height_percentile == 50, ]
d <- d[d$male == 0, ]
d

est_norm(q = d$sbp, p = d$bp_percentile / 100)
est_norm(q = d$dbp, p = d$bp_percentile / 100)

bp_parameters[bp_parameters$male == 0 & bp_parameters$age == 144 & bp_parameters$height_percentile == 50, ]
```


The est_norm method comes with a plotting method too.  The provided quantiles
are plotted as open dots and the fitted distribution function is plotted to
show the fit.

```{r fig.width = 5, fig.height = 5}
plot( est_norm(q = d$dbp, p = d$bp_percentile / 100) )
```


If you want to emphasize a data point you can do that as well.  Here is an
example from a set of quantiles and percentiles which are not Gaussian.


```{r }
qs <- c(-1.92, 0.05, 0.1, 1.89) * 1.8 + 3.14
ps <- c(0.025, 0.40, 0.50, 0.975)

# with equal weights
w0 <- est_norm(qs, ps)
# weight to ignore one of the middle value and make sure to hit the other
w1 <- est_norm(qs, ps, weights = c(1, 2, 0, 1))
# equal weight the middle, more than the tails
w2 <- est_norm(qs, ps, weights = c(1, 2, 2, 1))
```




```{r label = "est_norm_plots", fig.width = 9, fig.height = 5}
gridExtra::grid.arrange(
  plot(w0) + ggplot2::ggtitle(label = "w0", subtitle = paste0("Mean: ", round(w0$par[1], 2), " SD: ", round(w0$par[2], 3)))
  , plot(w1) + ggplot2::ggtitle(label = "w1", subtitle = paste0("Mean: ", round(w1$par[1], 2), " SD: ", round(w1$par[2], 3)))
  , plot(w2) + ggplot2::ggtitle(label = "w2", subtitle = paste0("Mean: ", round(w2$par[1], 2), " SD: ", round(w2$par[2], 3)))
  , nrow = 1
)
```




# References
<div id="refs"></div>

# Session Info

```{r label = "sessioninfo"}
sessionInfo()
```

