Skip to content

Commit c355da6

Browse files
author
alex-omophub
committed
Readme updates
1 parent 83d0ef1 commit c355da6

1 file changed

Lines changed: 201 additions & 71 deletions

File tree

README.md

Lines changed: 201 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,250 @@
11
# OMOPHub R SDK
22

3-
<!-- badges: start -->
3+
**Query millions of standardized medical concepts from R**
4+
5+
Access SNOMED CT, ICD-10, RxNorm, LOINC, and 90+ OHDSI ATHENA vocabularies without downloading, installing, or maintaining local databases.
6+
7+
[![CRAN status](https://www.r-pkg.org/badges/version/omophub)](https://CRAN.R-project.org/package=omophub)
8+
[![CRAN downloads](https://cranlogs.r-pkg.org/badges/omophub)](https://cran.r-project.org/package=omophub)
49
[![R-CMD-check](https://github.com/omopHub/omophub-R/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/omopHub/omophub-R/actions/workflows/R-CMD-check.yaml)
5-
[![Codecov test coverage](https://codecov.io/gh/omopHub/omophub-R/branch/main/graph/badge.svg)](https://app.codecov.io/gh/omopHub/omophub-R?branch=main)
10+
[![Codecov](https://codecov.io/gh/omopHub/omophub-R/branch/main/graph/badge.svg)](https://app.codecov.io/gh/omopHub/omophub-R?branch=main)
611
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7-
[![CRAN status](https://www.r-pkg.org/badges/version/omophub)](https://CRAN.R-project.org/package=omophub)
8-
[![CRAN_Status_Badge](https://cranlogs.r-pkg.org/badges/omophub)](https://cran.r-project.org/package=omophub)
912

10-
<!-- badges: end -->
13+
**[Documentation](https://docs.omophub.com/sdks/r/overview)** ·
14+
**[API Reference](https://docs.omophub.com/api-reference)** ·
15+
**[Examples](https://github.com/omopHub/omophub-R/tree/main/inst/examples)**
1116

12-
R client for the [OMOPHub API](https://docs.omophub.com), providing access to OHDSI ATHENA standardized medical vocabularies.
17+
---
1318

14-
## Installation
19+
## Why OMOPHub?
20+
Working with OHDSI ATHENA vocabularies traditionally requires downloading multi-gigabyte files, setting up a database, and writing complex SQL queries. **OMOPHub eliminates this friction.**
21+
22+
| Traditional Approach | With OMOPHub |
23+
|---------------------|--------------|
24+
| Download 5GB+ ATHENA vocabulary files | `install.packages("omophub")` |
25+
| Set up and maintain database instance | One API call |
26+
| Write complex SQL with multiple JOINs | Simple R functions |
27+
| Manually update vocabularies quarterly | Always current data |
28+
| Local infrastructure required | Works anywhere R runs |
1529

16-
You can install the development version of omophub from [GitHub](https://github.com/omopHub/omophub-R):
30+
## Installation
1731

1832
```r
33+
# Install from CRAN
1934
install.packages("omophub")
2035

21-
# OR install from GitHub
22-
36+
# Or install development version from GitHub
2337
# install.packages("pak")
2438
pak::pak("omopHub/omophub-R")
2539
```
2640

2741
## Authentication
2842

29-
Set your API key using one of these methods:
30-
3143
```r
44+
library(omophub)
45+
3246
# Option 1: Environment variable (recommended)
33-
Sys.setenv(OMOPHUB_API_KEY = "your_api_key")
47+
Sys.setenv(OMOPHUB_API_KEY = "oh_xxxxxxxxx")
3448

35-
# Option 2: Use the helper function
36-
library(omophub)
37-
set_api_key("your_api_key")
49+
# Option 2: Use helper function
50+
set_api_key("oh_xxxxxxxxx")
3851

3952
# Option 3: Store securely in system keyring
40-
set_api_key("your_api_key", store = "keyring")
53+
set_api_key("oh_xxxxxxxxx", store = "keyring")
4154
```
4255

56+
Get your API key from the [OMOPHub Dashboard](https://dashboard.omophub.com/api-keys).
57+
4358
## Quick Start
4459

4560
```r
4661
library(omophub)
4762

48-
# Create a client
63+
# Create client
4964
client <- OMOPHubClient$new()
5065

51-
# Search for concepts
52-
results <- client$search$basic("diabetes")
53-
results$data
54-
55-
# Get a specific concept
66+
# Get a concept by ID
5667
concept <- client$concepts$get(201826)
5768
concept$concept_name
5869
# [1] "Type 2 diabetes mellitus"
5970

71+
# Search for concepts
72+
results <- client$search$basic("metformin", vocabulary_ids = "RxNorm")
73+
results$data
74+
6075
# Get concept by vocabulary code
61-
concept <- client$concepts$get_by_code("SNOMED", "44054006")
76+
snomed_concept <- client$concepts$get_by_code("SNOMED", "44054006")
77+
78+
# Map to another vocabulary
79+
mappings <- client$mappings$get(201826, target_vocabularies = "ICD10CM")
80+
81+
# Navigate hierarchy
82+
ancestors <- client$hierarchy$ancestors(201826, max_levels = 3)
83+
```
6284

63-
# Batch lookup multiple concepts
64-
batch <- client$concepts$batch(c(201826, 320128, 4329847))
85+
## Use Cases
6586

66-
# Get concept ancestors (hierarchy)
67-
ancestors <- client$hierarchy$ancestors(201826)
87+
### ETL & Data Pipelines
6888

69-
# Get concept mappings to another vocabulary
70-
mappings <- client$mappings$get(201826, target_vocabularies = "ICD10CM")
89+
Validate and map clinical codes during OMOP CDM transformations:
90+
91+
```r
92+
# Validate source codes and find standard equivalents
93+
validate_and_map <- function(source_vocab, source_code) {
94+
concept <- client$concepts$get_by_code(source_vocab, source_code)
95+
96+
if (concept$standard_concept != "S") {
97+
mappings <- client$mappings$get(
98+
concept$concept_id,
99+
target_vocabularies = "SNOMED"
100+
)
101+
return(mappings$mappings[[1]]$target_concept_id)
102+
}
103+
104+
concept$concept_id
105+
}
106+
107+
# Example: Map ICD-10 to SNOMED
108+
standard_id <- validate_and_map("ICD10CM", "E11.9")
71109
```
72110

73-
## Resources
111+
### Data Quality Checks
74112

75-
The client provides access to these resources:
113+
Verify codes exist and are valid:
76114

77-
| Resource | Description |
78-
|----------|-------------|
79-
| `concepts` | Concept lookup, batch operations, suggestions |
80-
| `search` | Basic and advanced concept search |
81-
| `vocabularies` | Vocabulary listing and details |
82-
| `domains` | Domain listing and concept filtering |
83-
| `hierarchy` | Ancestor and descendant navigation |
84-
| `relationships` | Concept relationships |
85-
| `mappings` | Concept mappings between vocabularies |
115+
```r
116+
# Check if condition codes are valid
117+
condition_codes <- c("E11.9", "I10", "J44.9")
118+
119+
for (code in condition_codes) {
120+
tryCatch({
121+
concept <- client$concepts$get_by_code("ICD10CM", code)
122+
message(sprintf("OK %s: %s", code, concept$concept_name))
123+
}, omophub_api_error = function(e) {
124+
message(sprintf("ERROR %s: Invalid code!", code))
125+
})
126+
}
127+
```
86128

87-
## Pagination
129+
### Phenotype Development
130+
131+
Explore hierarchies to build comprehensive concept sets:
88132

89-
For large result sets, use automatic pagination:
133+
```r
134+
# Get all descendants for phenotype definition
135+
descendants <- client$hierarchy$descendants(
136+
201826, # Type 2 diabetes mellitus
137+
max_levels = 5,
138+
standard_only = TRUE
139+
)
140+
141+
concept_set <- sapply(descendants$concepts, function(x) x$concept_id)
142+
message(sprintf("Found %d concepts for T2DM phenotype", length(concept_set)))
143+
```
144+
145+
### Integration with tidyverse
146+
147+
```r
148+
library(dplyr)
149+
library(purrr)
150+
151+
# Search and convert to tibble
152+
results <- client$search$basic("hypertension", page_size = 100)
153+
154+
concepts_df <- results$data %>%
155+
map_dfr(~ tibble(
156+
concept_id = .x$concept_id,
157+
concept_name = .x$concept_name,
158+
vocabulary_id = .x$vocabulary_id,
159+
domain_id = .x$domain_id
160+
))
161+
162+
# Filter and analyze
163+
concepts_df %>%
164+
filter(vocabulary_id == "SNOMED") %>%
165+
count(domain_id)
166+
```
167+
168+
## API Resources
169+
170+
| Resource | Description | Key Methods |
171+
|----------|-------------|-------------|
172+
| `concepts` | Concept lookup and batch operations | `get()`, `get_by_code()`, `batch()`, `suggest()` |
173+
| `search` | Full-text and semantic search | `basic()`, `advanced()`, `basic_all()` |
174+
| `hierarchy` | Navigate concept relationships | `ancestors()`, `descendants()` |
175+
| `mappings` | Cross-vocabulary mappings | `get()`, `map()` |
176+
| `vocabularies` | Vocabulary metadata | `list()`, `get()`, `stats()` |
177+
| `domains` | Domain information | `list()`, `get()`, `concepts()` |
178+
179+
## Pagination
90180

91181
```r
92-
# Fetch all results automatically
182+
# Automatic pagination - fetch all results
93183
all_results <- client$search$basic_all("diabetes", page_size = 100)
94184

95-
# Or paginate manually
185+
# Manual pagination
96186
page1 <- client$search$basic("diabetes", page = 1, page_size = 20)
97187
page2 <- client$search$basic("diabetes", page = 2, page_size = 20)
98188
```
99189

100-
## Vocabulary Versioning
190+
## Configuration
101191

102-
Specify a vocabulary version when creating the client:
103192
```r
193+
# Specify vocabulary version
104194
client <- OMOPHubClient$new(vocab_version = "2025.2")
195+
196+
# Custom configuration
197+
client <- OMOPHubClient$new(
198+
api_key = "oh_xxx",
199+
base_url = "https://api.omophub.com/v1",
200+
timeout = 30
201+
)
105202
```
106203

107204
## Error Handling
108205

109-
The package uses structured error classes:
110-
111206
```r
112-
tryCatch(
113-
{
114-
result <- client$concepts$get(999999999)
115-
},
116-
omophub_api_error = function(e) {
117-
message("API error: ", conditionMessage(e))
118-
},
119-
omophub_auth_error = function(e) {
120-
message("Authentication failed")
121-
}
122-
)
207+
tryCatch({
208+
result <- client$concepts$get(999999999)
209+
}, omophub_not_found_error = function(e) {
210+
message("Concept not found: ", conditionMessage(e))
211+
}, omophub_auth_error = function(e) {
212+
message("Check your API key")
213+
}, omophub_rate_limit_error = function(e) {
214+
message("Rate limited, please wait")
215+
}, omophub_api_error = function(e) {
216+
message("API error: ", conditionMessage(e))
217+
})
123218
```
124219

220+
## Compared to Alternatives
221+
222+
| Feature | OMOPHub SDK | ATHENA Download | OHDSI WebAPI |
223+
|---------|-------------|-----------------|--------------|
224+
| Setup time | 1 minute | Hours | Hours |
225+
| Infrastructure | None | PostgreSQL required | Full OHDSI stack |
226+
| Updates | Automatic | Manual download | Manual |
227+
| Programmatic access | Native R | SQL/DatabaseConnector | REST API |
228+
| Offline support | No | Yes | Depends |
229+
| Cost | Free tier available | Free | Free (self-hosted) |
230+
231+
**Best for:** R users who need quick, programmatic access to OMOP vocabularies without infrastructure overhead.
232+
125233
## Examples
126234

127235
The package includes comprehensive examples in `inst/examples/`:
128236

129237
| Example | Description |
130238
|---------|-------------|
131-
| [`basic_usage.R`](inst/examples/basic_usage.R) | Getting started - client setup, concept lookup, search |
132-
| [`search_concepts.R`](inst/examples/search_concepts.R) | Search capabilities - filters, autocomplete, pagination |
133-
| [`navigate_hierarchy.R`](inst/examples/navigate_hierarchy.R) | Hierarchy navigation - ancestors, descendants, relationships |
134-
| [`map_between_vocabularies.R`](inst/examples/map_between_vocabularies.R) | Vocabulary mapping - ICD-10, SNOMED, batch mapping |
135-
| [`error_handling.R`](inst/examples/error_handling.R) | Error handling patterns - tryCatch, retry logic |
239+
| `basic_usage.R` | Getting started - client setup, concept lookup, search |
240+
| `search_concepts.R` | Search capabilities - filters, autocomplete, pagination |
241+
| `navigate_hierarchy.R` | Hierarchy navigation - ancestors, descendants |
242+
| `map_between_vocabularies.R` | Cross-vocabulary mapping |
243+
| `error_handling.R` | Error handling patterns |
136244

137245
Run an example:
246+
138247
```r
139-
# After installing the package
140248
example_path <- system.file("examples", "basic_usage.R", package = "omophub")
141249
source(example_path)
142250
```
@@ -145,14 +253,36 @@ source(example_path)
145253

146254
- [Full Documentation](https://docs.omophub.com/sdks/r/overview)
147255
- [API Reference](https://docs.omophub.com/api-reference)
148-
- [Examples](https://github.com/omopHub/omophub-r/tree/main/inst/examples)
256+
- [Examples](https://github.com/omopHub/omophub-R/tree/main/inst/examples)
257+
- [Get API Key](https://dashboard.omophub.com/api-keys)
258+
259+
## Contributing
260+
261+
We welcome contributions!
262+
263+
```r
264+
# Clone and install for development
265+
# install.packages("devtools")
266+
devtools::install_github("omopHub/omophub-R")
267+
268+
# Run tests
269+
devtools::test()
270+
271+
# Check package
272+
devtools::check()
273+
```
274+
275+
## Support
276+
277+
- [GitHub Issues](https://github.com/omopHub/omophub-R/issues)
278+
- [GitHub Discussions](https://github.com/omopHub/omophub-R/discussions)
279+
- Email: support@omophub.com
280+
- Website: [omophub.com](https://omophub.com)
149281

150282
## License
151283

152284
MIT License - see [LICENSE](LICENSE) for details.
153285

154-
## Support
286+
---
155287

156-
- [GitHub Issues](https://github.com/omopHub/omophub-r/issues)
157-
- [Documentation](https://docs.omophub.com)
158-
- [Website](https://omophub.com)
288+
*Built for the OHDSI community*

0 commit comments

Comments
 (0)