knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
library(ROhdsiWebApi) library(dplyr) baseUrl <- 'http://api.ohdsi.org:8080/WebAPI'
ROhdsiWebApi is part of HADES.
From Package Readme
ROhdsiWebApi is a R based interface to 'WebApi' (OHDSI RESTful services), and performs GET/PULL/POST/DELETE calls via the WebApi. All objects starting from R or output to R - are analysis ready R-objects like list and data.frame. The package handles the intermediary steps by converting R-objects to JSON and vice versa. To ensure r-objects are analysis ready, the objects are type converted where possible, e.g. date/date time are converted from string to POSIXct.
This package makes reproducible research easier, by offering ability to retrieve detailed study specifications, transport study specifications from one instance to another, programmatically invoke the generation of a sequence of steps that are part of a study, manage running studies in batch mode.
This document will attempt to explain how ROhdsiWebApi maybe used to achieve reproducible research.
To successfully use ROhdsiWebApi, it is necessary to have an active 'WebApi' endpoint with a known baseUrl such as "http://server.org:80/WebAPI". 'WebApi' has many functional categories.
To ensure reproducibility of work it is best to know the version of the WebApi (i.e. Atlas backend) being used. An easy way to do that is (and output maybe included in your study results)
version <- ROhdsiWebApi:::getWebApiVersion(baseUrl = baseUrl) message1 <- paste0('This Vignette was created using WebApi version: ', version, ' on baseUrl: ', baseUrl, ". The CDM had the following source data configured: ") cdmSources <- ROhdsiWebApi::getCdmSources(baseUrl = baseUrl) priorityVocabulary <- ROhdsiWebApi::getPriorityVocabularyKey(baseUrl = baseUrl)
The object version
will show your webApi version. Example: r message1
.
cdmSources
The priority vocabulary for the WebApi is r priorityVocabulary
.
We can also perform checks on the WebApi, example - we may want to see if the 'HCUP' & 'SYNPUF1K' is a valid SourceKey in the current webApi.
ROhdsiWebApi::isValidSourceKey(sourceKeys = c('HCUP', 'SYNPUF1K'), baseUrl = baseUrl)
WebApi maybe considered to have certain modular analytic categories. ROhdsiWebApi supports the following categories:
output <- ROhdsiWebApi:::.getStandardCategories() %>% select(.data$categoryFirstUpper) %>% rename(Category = .data$categoryFirstUpper) %>% arrange() %>% mutate(features = paste0("Functions for interfacing with ", .data$Category, " in WebApi")) colnames(output) <- SqlRender::camelCaseToTitleCase(colnames(output)) knitr::kable(output)
ROhdsiWebApi maybe better understood by having atleast a high level understanding of CRUD framework for WebApi, i.e. the GET, PUT, DELETE, POST calls to the API. See the documentation of the WebApi.
For each supported category, ROhdsiWebAPi performs GET, PUT, DELETE, POST calls to WebApi in background. The details of what calls are actually performed is less important to an analyst, but it is useful to understand the naming conventions of ROhdsiWebApi.
Most functions in ROhdsiWebApi start with an action oriented 'verb' - such as
output <- tidyr::tibble(functionName = library(help = "ROhdsiWebApi" )$info[[2]]) %>% mutate(functionName = stringr::str_replace(string = functionName, pattern = 'isValid', replacement = 'isvalid')) %>% mutate(functionName = stringr::str_replace(string = functionName, pattern = 'CdmSources', replacement = 'Cdmsources')) %>% mutate(functionName = stringr::str_replace(string = functionName, pattern = 'MetaData', replacement = 'Metadata')) %>% mutate(functionName = stringr::str_replace(string = functionName, pattern = 'PersonProfile', replacement = 'PersonProfile')) %>% mutate(functionName = stringr::str_replace(string = functionName, pattern = 'PriorityVocabularyKey', replacement = 'Priorityvocabularykey')) %>% mutate(functionName = stringr::str_replace(string = functionName, pattern = 'InclusionRulesAndCounts', replacement = 'Inclusionrulesandcounts')) %>% mutate(functionName = stringr::str_replace(string = functionName, pattern = 'GenerationInformation', replacement = 'Generationinformation')) %>% mutate(functionName = stringr::str_replace(string = functionName, pattern = 'SourceConcepts', replacement = 'Sourceconcepts')) %>% mutate(functionName = stringr::word(string = .data$functionName, 1)) %>% mutate(functionNameTitle = SqlRender::camelCaseToTitleCase(.data$functionName)) %>% mutate(functionNameFirst = stringr::word(string = .data$functionNameTitle, start = 1 , end = 1), functionNameLast = stringr::word(string = .data$functionNameTitle,start = -1)) %>% filter(!functionNameFirst == '') %>% mutate(functionNameMiddle = case_when(functionNameTitle == paste(functionNameFirst, functionNameLast) ~ '', TRUE ~ stringr::str_replace(string = .data$functionNameTitle, pattern = .data$functionNameFirst, replacement = '' ) %>% stringr::str_replace(pattern = .data$functionNameLast, replacement = '' ) %>% stringr::str_squish() ) ) %>% mutate(functionsWithPattern = case_when(.data$functionNameFirst %in% c('Cancel','Create','Delete','Detect','Exists', 'Get','Invoke', 'IsValid', 'Post','Resolve') ~ TRUE, TRUE ~ FALSE ) ) knitr::kable(output %>% select('Function Name' = functionName, 'Description' = functionNameTitle))
Most of the functions start with the following verbs:
verb <- output %>% filter(functionsWithPattern = TRUE) %>% group_by(.data$functionNameFirst) %>% summarise(numberOfFunctions = n(), .groups = 'keep') %>% arrange() %>% ungroup() %>% arrange(desc(numberOfFunctions)) %>% distinct() %>% rename(functionVerb = functionNameFirst) %>% rename_all(SqlRender::camelCaseToTitleCase) knitr::kable(verb)
A function to get Definition
is getDefinitionMetaData
function. This is a general function that is able to get the Metadata for all specifications within a category.
ROhdsiWebApi::getDefinitionsMetadata(baseUrl = baseUrl, category = 'cohort') %>% arrange(.data$id) %>% rename_all(.funs = SqlRender::camelCaseToTitleCase) %>% head()
The same output may be achieved using
ROhdsiWebApi::getCohortDefinitionsMetaData(baseUrl = baseUrl) %>% arrange(.data$id) %>% rename_all(.funs = SqlRender::camelCaseToTitleCase) %>% head()
Similar approach may be used for all categories as follows:
ROhdsiWebApi::getDefinitionsMetadata(baseUrl = baseUrl, category = 'estimation') %>% arrange(.data$id) %>% rename_all(.funs = SqlRender::camelCaseToTitleCase) %>% head()
ROhdsiWebApi::getEstimationDefinitionsMetaData(baseUrl = baseUrl) %>% arrange(.data$id) %>% rename_all(.funs = SqlRender::camelCaseToTitleCase) %>% head()
This is a generic framework that applies to most WebApi categories, and supports different types of CRUD functionalities like deleteConceptSetDefinition() vs deleteDefinition(category = 'conceptSet').
Please review 'Concept sets - The Book of OHDSI'
We commonly post concept set expression into WebApi/Atlas, or try get an expression from Atlas/WebApi based on a conceptSetDefinitionId.
Example: lets say we have concept set expression as follows, that is being used for a Rheumatoid Arthritis study.
jsonExpression <- '{ "items": [ { "concept": { "CONCEPT_ID": 81097, "CONCEPT_NAME": "Feltys syndrome", "STANDARD_CONCEPT": "S", "STANDARD_CONCEPT_CAPTION": "Standard", "INVALID_REASON": "V", "INVALID_REASON_CAPTION": "Valid", "CONCEPT_CODE": "57160007", "DOMAIN_ID": "Condition", "VOCABULARY_ID": "SNOMED", "CONCEPT_CLASS_ID": "Clinical Finding" }, "isExcluded": true, "includeDescendants": false, "includeMapped": false }, { "concept": { "CONCEPT_ID": 80809, "CONCEPT_NAME": "Rheumatoid arthritis", "STANDARD_CONCEPT": "S", "STANDARD_CONCEPT_CAPTION": "Standard", "INVALID_REASON": "V", "INVALID_REASON_CAPTION": "Valid", "CONCEPT_CODE": "69896004", "DOMAIN_ID": "Condition", "VOCABULARY_ID": "SNOMED", "CONCEPT_CLASS_ID": "Clinical Finding" }, "isExcluded": false, "includeDescendants": true, "includeMapped": false }, { "concept": { "CONCEPT_ID": 4035611, "CONCEPT_NAME": "Seropositive rheumatoid arthritis", "STANDARD_CONCEPT": "S", "STANDARD_CONCEPT_CAPTION": "Standard", "INVALID_REASON": "V", "INVALID_REASON_CAPTION": "Valid", "CONCEPT_CODE": "239791005", "DOMAIN_ID": "Condition", "VOCABULARY_ID": "SNOMED", "CONCEPT_CLASS_ID": "Clinical Finding" }, "isExcluded": false, "includeDescendants": true, "includeMapped": false } ] }'
Lets call this concept set expression - '[ROhdsiWebApi Vignette] Rheumatoid Arthritis concept set'.
r conceptSetName = '[ROhdsiWebApi Vignette] Rheumatoid Arthritis concept set'
We will need to check if there is a concept set by this name.
# check if there is a concept set by this name, if yes, delete it exists <- ROhdsiWebApi::existsConceptSetName(conceptSetName = conceptSetName, baseUrl = baseUrl) exists
If there is a concept set with this name, then we could either choose another name - or delete the old concept set. For this vignette we have chosen to delete any matching concept set as follows:
if (!isFALSE(exists)) { ROhdsiWebApi::deleteConceptSetDefinition(conceptSetId = exists$id, baseUrl = baseUrl) }
Now we need to ensure the JSON expression above is converted to R-data object. Note: By design, ROhdsiWebAPi does not accept JSON. It needs to be converted to R (list) expression
rExpression <- RJSONIO::fromJSON(jsonExpression)
We can now post this R-object into WebApi as follows:
returnFromPostRequest <- ROhdsiWebApi::postConceptSetDefinition(baseUrl = baseUrl, conceptSetDefinition = rExpression, name = conceptSetName)
If successful, we will get a return object as follows into R.
returnFromPostRequest
The id of the newly posted concept-set definition is returnFromPostRequest$id
. We can now use this concept-set for many concept set queries eg.,
conceptSetDefinition = getConceptSetDefinition(conceptSetId = returnFromPostRequest$id, baseUrl = baseUrl) conceptTbl <- convertConceptSetDefinitionToTable(conceptSetDefinition) names(conceptTbl) <- SqlRender::camelCaseToTitleCase(names(conceptTbl)) conceptTbl
createConceptSetWorkbook
maybe used to create an Excel workbook of the concept set.
If we want a list of all conceptId's (including descendants) from the concept set expression
resolvedConcepts = resolveConceptSet(conceptSetDefinition = conceptSetDefinition, baseUrl = baseUrl) print("Note: Showing only the first 10 concept id's") resolvedConcepts[1:10]
The concept set expression json expression can be recaptured from WebApi as follows
json <- getConceptSetDefinition(baseUrl = baseUrl, conceptSetId = returnFromPostRequest$id )$expression %>% RJSONIO::toJSON(pretty = TRUE)
Similar framework maybe used with other WebApi categories such as Cohorts/Characterization/Incidence Rate.
A valuable feature of ROhdsiWebApi is that it is able to get full result set into R, as a data frame object. Results of Cohort, Characterization, Incidence Rate, Pathway maybe obtained. This data frame may then be converted to publication ready material by using packages like Officer, flextable. The functions in ROhdsiWebAPi maybe used to create dynamic R-shiny apps that allow user to interact with WebApi and select cohort definitions, concept sets for review or modifications. ROhdsiWebApi may be used to build 'mini versions' of Atlas that is project specific - by directly interacting with WebApi using R.
Please review 'What is a cohort - The Book of OHDSI'.
We define a cohort as a set of persons who satisfy one or more inclusion criteria for a duration of time. The term cohort is often interchanged with the term phenotype. Cohorts are used throughout OHDSI analytical tools and network studies as the primary building blocks for executing a research question.
A cohort is defined as the set of persons satisfying one or more inclusion criteria for a duration of time. One person may qualify for one cohort multiple times during non-overlapping time intervals. Cohorts are constructed in ATLAS by specifying cohort entry criteria and cohort exit criteria. Cohort entry criteria involve selecting one or more initial events, which determine the start date for cohort entry, and optionally specifying additional inclusion criteria which filter to the qualifying events. Cohort exit criteria are applied to each cohort entry record to determine the end date when the person’s episode no longer qualifies for the cohort.
Cohorts/Characterization/Incidence Rate are WebApi categories, where WebApi manages the execution of generations.
Example: We may want to know if a certain cohort specification has been generated by checking cohort generation status getCohortGenerationInformation(baseUrl = baseUrl, cohortId= 4234)
. If a cohort is not previously generated, it may be generated using invokeCohortSetGeneration(baseUrl = baseUrl, cohortId = 4234, sourceKey = 'HCUP')
. If it is already generated, we can extract its output of cohort generation using getCohortResults(baseUrl, cohortId = 4234)
.
Please review 'Characterization - The Book of OHDSI'.
Please review 'Population Level Effect Estimation - The Book of OHDSI'.
Please review 'Patient Level Prediction - The Book of OHDSI'.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.