knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
library(printr)
library(dMeasure) packageVersion("dMeasure") # creates a dMeasure object named 'a'. Could be named something else. a <- dMeasure::dMeasure$new()
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
a$open_configuration_db() a$read_configuration_db()
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
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)) }
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
a <- dMeasure::dMeasure$new() a$open_emr_db() # this will try to open the most recent database description choice, in this case, 'Main'
Ports to open on te server (according to 'BPS_SQLportsV2' utility)
# 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))
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
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 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 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()
?dMeasure::list_vax() a$list_vax() %>% head() a$list_influenza() %>% head() a$list_zostavax() %>% head() a$list_measlesVax() %>% head()
?dMeasure::list_mammogram a$list_mammogram() %>% head()
a$list_cst() %>% tail()
a$list_fobt() %>% head()
?dMeasure::list_dataQuality() a$list_dataQuality() %>% head()
?dMeasure::list_allergy() a$list_allergy() %>% head()
?dMeasure::list_socialHx() a$list_socialHx() %>% head()
?dMeasure::list_familyHx() a$list_familyHx() %>% head()
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
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.
?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()
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
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()
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()
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()
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
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()
# 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())
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()
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()
?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()
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.
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!
a$close()
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.