///|
pub(all) struct ObservationPoint {
id : String?
code : String?
subject : String?
issued : String?
value : Double?
unit : String?
} derive(Debug, Eq, ToJson)
///|
pub fn observation_point(value : Json) -> ObservationPoint {
{
id: field_string(value, "id"),
code: resource_code_text(value),
subject: resource_subject(value),
issued: field_string(value, "issued"),
value: observation_measurement(value),
unit: Some(observation_measurement_unit(value)),
}
}
///|
pub fn observation_points(values : Array[Json]) -> Array[ObservationPoint] {
values.filter_map(fn(value) {
if resource_type(value) == Some("Observation") {
Some(observation_point(value))
} else {
None
}
})
}
///|
pub fn observation_series(
values : Array[Json],
code : String,
) -> Array[ObservationPoint] {
observation_points(values).filter(fn(point) { point.code == Some(code) })
}
///|
pub fn observation_series_values(
values : Array[ObservationPoint],
) -> Array[Double] {
values.filter_map(fn(point) { point.value })
}
///|
pub fn observation_series_mean(values : Array[ObservationPoint]) -> Double? {
let numbers = observation_series_values(values)
if numbers.length() == 0 {
None
} else {
Some(
numbers.fold(init=0.0, fn(total, number) { total + number }) /
numbers.length().to_double(),
)
}
}
///|
pub fn observation_series_median(values : Array[ObservationPoint]) -> Double? {
let numbers = observation_series_values(values)
if numbers.length() == 0 {
None
} else {
numbers.sort()
let middle = numbers.length() / 2
if numbers.length() % 2 == 1 {
Some(numbers[middle])
} else {
Some((numbers[middle - 1] + numbers[middle]) / 2.0)
}
}
}
///|
pub fn observation_series_min(values : Array[ObservationPoint]) -> Double? {
let numbers = observation_series_values(values)
numbers.sort()
numbers.get(0)
}
///|
pub fn observation_series_max(values : Array[ObservationPoint]) -> Double? {
let values = observation_series_values(values)
values.sort()
values.last()
}
///|
pub fn observation_series_unit(values : Array[ObservationPoint]) -> String? {
values.filter_map(fn(point) { point.unit }).get(0)
}
///|
pub fn observation_series_summary(values : Array[ObservationPoint]) -> String {
let mean = observation_series_mean(values)
.map(fn(value) { "\{value}" })
.unwrap_or("none")
let median = observation_series_median(values)
.map(fn(value) { "\{value}" })
.unwrap_or("none")
"points=\{values.length()} mean=\{mean} median=\{median}"
}
///|
pub fn observation_points_csv(values : Array[ObservationPoint]) -> String {
let lines = values.map(fn(point) {
csv_row([
point.id.unwrap_or(""),
point.code.unwrap_or(""),
point.subject.unwrap_or(""),
point.issued.unwrap_or(""),
point.value.map(fn(value) { "\{value}" }).unwrap_or(""),
point.unit.unwrap_or(""),
])
})
["id,code,subject,issued,value,unit"].add(lines).join("\n")
}