knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
library(printr)

Create a dMeasure object

library(dMeasure)
packageVersion("dMeasure")

# creates a dMeasure object named 'a'. Could be named something else.
a <- dMeasure::dMeasure$new()

Configuration file

Configuration file location

The location of the .sqlite configuration file is stored in ""~/.DailyMeasure_cfg.yaml"

The .sqlite file contains information required to access the Best Practice database. By default, the .sqlite file location is "~/.DailyMeasure_cfg.sqlite"

a$configuration_file_path <- "~/.DailyMeasure_cfg.sqlite" # set quietly to default!
a$configuration_file_path

The location of the .sqlite file can be changed. If the specified file does not exist, the .sqlite file will be created.

a$configuration_file_path <- "~/.MySpecialConfig.sqlite"
a$configuration_file_path

Opening and reading the configuration file

a$open_configuration_db()
a$read_configuration_db()

Best Practice Database Server configuration

Add a server definition, and show server definitions.

# quietly remove any current server description whic is called 'Myserver'!
id <- a$server.list() %>% dplyr::filter(Name == "MyServer") %>% dplyr::pull(id) %>% unique()
if (length(id) == 1) {
  a$server.delete(list(id = id[[1]]))
}
a$server.insert(list(Name = "MyServer", Address = "127.0.0.1\\BPSINSTANCE",
                     Database = "BPSSAMPLES", UserID = "bpsrawdata",
                     dbPassword = "mypassword"))
a$server.list()

A description of many methods can be shown using the package's help documentation, as shown for server.insert below. Note that the function server.insert includes an initial argument dMeasure_obj which is not used in the method server.insert.

?dMeasure::server.insert

Modify and delete server descriptions

Current server descriptions can be modified

id <- a$server.list() %>% dplyr::filter(Name == "MyServer") %>% dplyr::pull(id)
a$server.update(list(id = id, Database = "BPSPATIENTS"))

or deleted

id <- a$server.list() %>% dplyr::filter(Name == "MyServer") %>% dplyr::pull(id)
if (length(id) == 1) {
  a$server.delete(list(id = id))
}

Use server descriptions

The server description can be chosen, which will automatically try to use the chosen server description.

a$BPdatabaseChoice <- "None" # set to null choice
a$BPdatabaseChoice # returns the current database description choice
a$BPdatabaseChoice <- "Main" # this will also open the 'Main' database description, if possible

Database connections can be 'manually' closed.

The most recent Best Practice database choice will be 'remembered' in the .sqlite configuration file.

a$configuration_file_path <- "~/.DailyMeasure_cfg.sqlite" # set quietly to default!
a$close() # closes the database connections

Opening the Best Practice database connection

a <- dMeasure::dMeasure$new()
a$open_emr_db() # this will try to open the most recent database description choice, in this case, 'Main'

Best Practice database SQL firewall configuration

Ports to open on te server (according to 'BPS_SQLportsV2' utility)

User configuration

# a$UserConfig
# shows user configuration as stored in dMeasure's configuration file
DT::datatable(a$UserConfig,
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))
# a$UserConfigLicense
# decodes the 'License'/(subscription) to a 'License (Expiry) Date'
DT::datatable(a$UserConfigLicense,
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))
# a$UserFullConfig
# shows user configuration
# information combined from dMeasure's configuration file and the EMR (Best Practice) database
# includes the 'decoded' license date
DT::datatable(a$UserFullConfig,
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))

A 'manual entry' of subscription/license information can be done...

DrIvorCureIdentifier <- 
  a$UserFullConfig %>% dplyr::collect() %>%
  dplyr::filter(Fullname == "Dr Ivor Cure") %>%
  dplyr::pull(Identifier)
?dMeasure::verify_license
dMeasure::verify_license(DrIvorCureIdentifier, License = "not_a_real_license")
?dMeasure::update_subscription
a$update_subscription(Identifier = DrIvorCureIdentifier,
                      License = "not_a_real_license", verify = TRUE)

The correct way to remove a subscription is to set to 'NA'

a$update_subscription(Identifier = DrIvorCureIdentifier,
                      Fullname = "Dr Ivor Cure",
                      License = NA, verify = FALSE)

DT::datatable(a$UserConfigLicense,
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))

Subscription information can be read from the GPstat!/DailyMeasure database.

Note that reading the database will send (encrypted) details of the health care providers over the Internet. Those details are the names of the providers, and either the provider number or the name of the clinic.

?dMeasure::read_subscription_db
DT::datatable(a$read_subscription_db(forcecheck = TRUE),
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))

Appointment list examples

By default, no clinicans are selected, and the date of searches will be the current date (in this case r Sys.Date()).

a$choose_clinicians()
a$choose_date()

The list of available clinicians can be shown...

a$clinician_choice_list

...some clinicians chosen:

a$choose_clinicians(c("Ms Nadine Nurse", "Mrs. Psychology Specialist",
                      "Dr Frederick Findacure", "Dr Ivor Cure"))

...and dates chosen:

a$choose_date(date_from = as.Date("2000-01-01"), date_to = as.Date("2020-01-01"))

Just one of date_from or date_to can be defined.

It is also assumed (if the argument are not 'named'), that the first argument of choose_date will be date_from, and the second argument (if supplied) will be date_to.

Subsequent calls to many methods, such as those named list_* will, by default, assume the chosen clinicians and dates are those defined by the choose_clinicians and choose_date methods above.

a$list_appointments() %>% head() # 'head' just displays the first few appointments

Billed appointments list

Billing methods and fields are provided by the billings module https://github.com/DavidPatShuiFong/dMeasureBillings.

?dMeasureBillings::billed_appointments
billings <- dMeasureBillings::dMeasureBillings$new(a)

billings$billed_appointments() %>% 
  dplyr::mutate(Description = iconv(Description, "latin1", "ASCII", sub = "")) %>%
  # removes an invalid ASCII character from Description
  head()

Billings methods

Billings matched up to appointments and visits.

?dMeasureBillings::list_billings
print(billings$own_billings) # by default is TRUE, and shows only billings attributable to the provider

a$choose_date(date_from = as.Date("2019-05-01"), date_to = as.Date("2019-05-30")) # restrict date range
a$choose_clinicians(a$clinician_choice_list) # choose all clinicians

billings$list_billings() %>% head() # an aggregated version of $appointments_billings_sameday()

Show ALL billings for the patient on that day, whether or not attributable to the provider.

billings$own_billings <- FALSE
billings$list_billings() %>% head()
a$choose_date(as.Date("2001-01-01"), Sys.Date()) # reset dates

Chronic disease management

Chronic disease management methods are contained within the dMeasureCDM module https://github.com/DavidPatShuiFong/dMeasureCDM.

cdm <- dMeasureCDM::dMeasureCDM$new(a, billings)
# the dMeasureCDM object requires access to both the dMeasure ('a') object
# and the dMeasureBillings ('billings') object
cdm$billings_cdm() %>% head() # chronic disease management opportunities based on chronic conditions

Chronic disease management opportunities based on a a large number of condition lists, such diabetes_list_cdm. These active condition lists look at appointments_list (which is set by list_appointments method), and determine if a chronic disease management billing has occurred in a time period prior to the appointment.

intID_list <- a$appointments_list %>%
  dplyr::select(InternalID, AppointmentDate, AppointmentTime, Provider, Age)
cdm$diabetes_list_cdm(intID_list) %>% head()

The diabetes_list_cdm method in turn calls upon the diabetes_list method, which given a dataframe of $InternalID and $Date returns a vector of InternalID which corresponds to the $InternalID which have a history of diabetes.

?dMeasure::diabetes_list
a$diabetes_list()

Immunization methods

?dMeasure::list_vax()
a$list_vax() %>% head()
a$list_influenza() %>% head()
a$list_zostavax() %>% head()
a$list_measlesVax() %>% head()

Cancer screening methods

Breast cancer screening

?dMeasure::list_mammogram
a$list_mammogram() %>% head()

Cervical cancer screening

a$list_cst() %>% tail()

Bowel cancer screening

a$list_fobt() %>% head()

Data Quality methods

Overall

?dMeasure::list_dataQuality()
a$list_dataQuality() %>% head()

Allergy

?dMeasure::list_allergy()
a$list_allergy() %>% head()

Social History

?dMeasure::list_socialHx()
a$list_socialHx() %>% head()

Family history

?dMeasure::list_familyHx()
a$list_familyHx() %>% head()

Conditions

diabetes_list method described in Chronic Disease Management section.

?dMeasure::asthma_list
a$asthma_list()
?dMeasure::atsi_list
?dMeasure::malignancy_list
?dMeasure::hiv_list
?dMeasure::haemoglobinopathy_list
?dMeasure::asplenia_list
?dMeasure::haemoglobinopathy_list
?dMeasure::transplant_list
?dMeasure::cvd_list
?dMeasure::cardiacdisease_list
?dMeasure::trisomy21_list
?dMeasure::bmi30_list
?dMeasure::neurologic_list
?dMeasure::chronicliverdisease_list
?dMeasure::chronicrenaldisease_list
?dMeasure::pregnancy_list
?dMeasure::fifteenplus_list
?dMeasure::sixtyfiveplus_list
?dMeasure::seventyfiveplus_list
?dMeasure::ATSI_35_44_list
?dMeasure::fortyfiveseventyfour_list
?dMeasure::cst_eligible_list
?dMeasure::mammogram_eligible_list
?dMeasure::familialHypercholesterolaemia_list
?dMeasure::LVH_list

Contacts

There are three kinds of contacts : Appointments, Visits and Services.

Appointments are in the Appointment Book, and can be one of several 'Status'

a$appointment_status_types
a$appointment_status # the appointment status type which are seen with 'contact' methods

Visits are records in the patient progress notes. These can be of several types.

a$visit_types
a$visit_type # the visit types which are seen with 'contact' methods

Services are billings.

List contacts

?dMeasure::list_contact_appointments
a$list_contact_appointments() %>>% head()
x <- a$appointment_status # temporary store
a$appointment_status <- "Completed" # choose appointment status "Completed" only
a$list_contact_appointments() %>>% head()
a$appointment_status <- x # restore previous appointment status setting
a$list_contact_visits() %>% head()
a$list_contact_services() %>% head()

Counting contacts

A list of 'contacted' patients can be restricted by contact types, number of contacts within the specified time period (which can be chosen with $choose_date), and the date of the most recent contact.

a$contact_type # current contact types which are counted
a$contact_types # all available contact types
a$contact_min # number of 'minimum' contact within the specified time period
a$contact_minDate # 'minimum' date of most recent contact
# note that 'NA' is actually as.Date(-Inf, origin = "1970-01-01")
# which is infinitely into the past
a$contact_minDate <- as.Date("2019-01-01")
a$contact_minDate
a$contact_minDate <- as.Date(-Inf, origin = "1970-01-01")
a$contact_minDate
a$list_contact_count() %>% head()
a$contact_min <- 5
a$list_contact_count() %>% head()
a$contact_min <- 1

Contact conditions

The list_contact_count list can be further restricted by conditions.

These 'conditions' include those relevant to the Practice Improvement Program Quality Improvement Measures.

?dMeasure::list_contact_diabetes
a$list_contact_diabetes() %>% head()
a$list_contact_15plus() %>% head()
a$list_contact_45_74() %>% head()
a$list_contact_65plus() %>% head()
a$list_contact_75plus() %>% head()
a$list_contact_ATSI_35_44() %>% head()
a$list_contact_chroniclungdisease() %>% head()
a$list_contact_cst() %>% head()

Practice Incentive Program Quality Improvement Measures

Quality Improvement Measures are provided by the dMeasureQIM object.

qim <- dMeasureQIM::dMeasureQIM$new(a)
# the dMeasureQIM object is created
# with 'access' to the dMeasure object, in this case 'a'

These methods assist in reporting and monitoring of Quality Improvement Measures.

One group of methods list patients relevant to the Quality Improvement Measures.

The most basic list is of active patients (as defined by the contact methods, such as list_contact_count).

In the example below, 'all' contact types are counted. This is a very broad definition, and is only used because the 'samples' database used to create this document is very small.

?dMeasureQIM::list_qim_active
a$contact_type <- a$contact_types # includes 'all' contact types as valid (appointment, visit, billing)
qim$list_qim_active() # the list of patients, with Quality Improvement Measure specified groupings

Another group of methods provide aggregated/anonymized report of the relevant patients.

qim$report_qim_active() # an 'anonymized'/aggregated report of the active patients
# 'n' is the number of patients in the category
# 'Proportion' is the proportion of patients in the category

The demographic groupings for report can be changed from the default

qim$qim_demographicGroup # the default setting
qim$qim_demographicGroupings
qim$qim_demographicGroup <- c("Sex", "Ethnicity")
qim$report_qim_active()

Diabetes Quality Improvement Measures

DT::datatable(qim$list_qim_diabetes(),
              extension = "Scroller",
              options = list(scroller = TRUE, scrollX = TRUE))
qim$report_qim_diabetes()

By default, 'old' results (as defined by the Quality Improvement Measures) are ignored. Old results can be included by setting qim_ignoreOld to FALSE.

qim$qim_ignoreOld <- FALSE
DT::datatable(qim$list_qim_diabetes(),
              extension = "Scroller",
              options = list(scroller = TRUE, scrollX = TRUE))
qim$report_qim_diabetes()

Appointment view

Instead of using the contact list it is possible to use the appointment list view, which derives the patient list purely from the appointment book, without regard to the appointment status.

The appointment list view is designed to be used with the list...appointments methods. For example, list_qim_diabetes_appointments method attaches any appointment in the chosen date-range to the patient listing.

This method will usually be most useful when looking at just one day of appointments.

qim$qim_contact <- FALSE # use 'appointment' list, not 'contact' list
a$choose_date(as.Date("2019-01-01"))

DT::datatable(qim$list_qim_diabetes_appointments(),
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))

?dMeasureQIM::list_qim_diabetes_appointments

Cervical screening

qim$qim_contact <- TRUE # return to 'contact' list
a$choose_date(as.Date("2001-01-01")) # expand date list

qim$list_qim_cst()

DT::datatable(qim$list_qim_cst_appointments(),
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))

qim$report_qim_cst()

Fifteen plus

# very wide table! use scroller to see to the right...
DT::datatable(qim$list_qim_15plus(),
              extension = "Scroller",
              options = list(scroller = TRUE, scrollX = TRUE))

DT::datatable(qim$list_qim_15plus_appointments(),
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))


DT::datatable(qim$report_qim_15plus())

Sixty-five plus

qim$list_qim_65plus()

DT::datatable(qim$list_qim_65plus_appointments(),
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))

qim$report_qim_65plus()

Chronic obstructive pulmonary disease

qim$list_qim_copd()

DT::datatable(qim$list_qim_copd_appointments(),
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))

qim$report_qim_copd()

Cardiovascular risk

?dMeasureQIM::list_qim_cvdRisk

# remove some demographics and alcohol recordings because the table is very wide...
# note that the framingham risk equation calculation result 'frisk' is on the
# extreme right hand side
DT::datatable(qim$list_qim_cvdRisk() %>%
                dplyr::select(-c(RecordNo, MaritalStatus, Sexuality)),
              extension = "Scroller",
              options = list(scroller = TRUE, scrollX = TRUE))

DT::datatable(qim$list_qim_cvdRisk_appointments(),
              extension = "Scroller",
              options = list(scroller = TRUE, deferRender = TRUE,
                             scrollX = TRUE, scrollY = 200))

qim$report_qim_cvdRisk()

Cardiovascular risk inclusion/exclusion groups

qim$qim_cvdRisk_measureTypes
qim$qim_cvdRisk_measure # default group settings

Note that current Quality Improvement Measures guidelines appear to exclude ATSI 35-44 age group, which is different to the current default setting.

Framingham Risk Equation used for calculation

This equation is in package framinghamRiskEquation https://github.com/DavidPatShuiFong/framinghamRiskEquation.

?framinghamRiskEquation::framingham_riskequation

The framingham risk equation function is reproduced below. Please report any required corrections to me!


Close the database connections

a$close()


DavidPatShuiFong/dMeasure documentation built on Aug. 2, 2024, 11:45 p.m.