knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.path = "man/figures/README-", out.width = "100%" ) library(eye)
See more with eye
eye is dedicated to facilitate very common tasks in ophthalmic research.
You can install eye from CRAN using install.packages("eye")
Or you can install the development version from github:
# install.packages("devtools") devtools::install_github("tjebo/eye")
I recommend to also get eyedata, a package collating open source ophthalmic data sets.
Pesky visual acuity notations are now a matter of the past. Convert between any of Snellen (meter/ feet/ decimal!), logMAR and ETDRS.
The notation will be detected automatically and converted to the desired notation. For some more details see VA conversion. For entries with mixed notation, use va_mixed
instead.
You can also decide to simply "clean" your VA vector with cleanVA(x)
. This will remove all entries that are certainly no VA.
x <- c(23, 56, 74, 58) ## ETDRS letters to_logmar(x) # wrapper of va(x, to = "logmar") ## ... or convert to snellen to_snellen(x) ## eye knows metric as well to_snellen(x, type = "m") ## And the decimal snellen notation, so much loved in Germany to_snellen(x, type = "dec") ## Remove weird entries and implausible entries depending on the VA choice x <- c("NLP", "0.8", "34", "3/60", "2/200", "20/50", " ", ".", "-", "NULL") to_snellen(x) to_snellen(x, from = "snellendec") to_snellen(x, from = "etdrs") to_snellen(x, from = "logmar") ## "plus/minus" entries are converted to the most probable threshold (any spaces allowed) x <- c("20/200 - 1", "6/6-2", "20/50 + 3", "6/6-4", "20/33 + 4") to_logmar(x) ## or evaluating them as logmar values (each optotype equals 0.02 logmar) to_logmar(x, smallstep = TRUE) ## or you can also decide to completely ignore them (converting them to the nearest snellen value in the VA chart, or if you convert to logMAR, rounding to the first digit) to_snellen(x, noplus = TRUE) # terribly mixed notations x <- c(NA, "nlp", 1:2, 1.1, -1, "20/40", "4/6", "6/1000", 34) va_mixed(x, to = "snellen") # "I only have snellen and snellen decimal notation in my data" va_mixed(x, to = "snellen", possible = c("snellen", "snellendec")) # "I have snellen, logmar and etdrs in my data, and there is no etdrs value less than 4" va_mixed(x, to = "snellen", possible = c("snellen", "logmar", "etdrs"))
This is a massive convenience function to count subjects and eyes. Because this essentially returns a list, the stored data can easily be accessed by subsetting (e.g., with $
). You can get the subject IDs for each subset with details = TRUE
.
library(eyedata) eyes(amd2) eyes(amd2)$right eyes(amd2, details = TRUE) head(eyes(amd2, details = TRUE)$id$right)
eyestr
was designed with the use in rmarkdown in mind, most explicitly for the use inline. You can change the way numbers are converted to english with the english
argument. By default, numbers smaller than or equal to 12 will be real English, all other numbers will be ... numbers. You can capitalise the first number with the caps
argument.
| rmarkdown code | results in |
|----------|---------|
|We analyzed `r knitr::inline_expr("eyestr(amd2)")`
|We analyzed r eyestr(amd2)
|
|We analyzed `r knitr::inline_expr("eyestr(head(amd2, 100))")`
| We analyzed r eyestr(head(amd2, 100))
|
|We analyzed `r knitr::inline_expr('eyestr(amd2, english = "all")')`
|We analyzed r eyestr(amd2, english = "all")
|
|`r knitr::inline_expr("eyestr(head(amd2, 100), caps = TRUE)")`
were analyzed | r eyestr(head(amd2, 100), caps = TRUE)
were analyzed|
|We analyzed `r knitr::inline_expr('eyestr(head(amd2, 100), english = "none")')`
| We analyzed r eyestr(head(amd2, 100), english = "none")
|
Makes recoding eye variables very easy. It deals with weird missing entries like "."
and ""
, or "N/A"
x <- c("r", "re", "od", "right", "l", "le", "os", "left", "both", "ou") recodeye(x) ## chose the resulting codes recodeye(x, to = c("od", "os", "ou")) ## Numeric codes 0:1/ 1:2 are recognized x <- 1:2 recodeye(x) ## with weird missing values x <- c(1:2, ".", NA, "", " ") recodeye(x) ## If you are using different strings to code for eyes, e.g., you are using a different language, you can change this either with the "eyestrings" argument french <- c("OD", "droit", "gauche", "OG") recodeye(french, eyestrings = list(r = c("droit", "od"), l = c("gauche", "og"))) ## or change it more globally with `set_eye_strings` set_eye_strings(right = c("droit", "od"), left = c("gauche", "og")) recodeye(french) # to restore the default, call set_eye_strings empty set_eye_strings()
x <- c("a", " ", ".", "-", "NULL") tidyNA(x) # in addition to the default strings, a new string can be added tidyNA(x, string = "a") # or just remove the strings you want tidyNA(x, string = "a", defaultstrings = FALSE)
Show common statistics for all numeric columns, for the entire cohort or aggregated by group(s):
reveal(iris) reveal(iris, by = "Species") #can be several groups
dob <- c("1984-10-16", "2000-01-01") ## If no second date given, the age today getage(dob) getage(dob, "2000-01-01")
Often enough, there are right eye / left eye columns for more than one variable, e.g., for both IOP and VA. This may be a necessary data formal for specific questions. However, "eye" is also variable (a dimension of your observation), and it can also be stored in a separate column. The data would be "longer".
Indeed, R requires exactly this data shape for many tasks: "eye[r/l]" as a separate column, and each eye-related variable (e.g., IOP or VA) in their own dedicated column.
myop
provides an easy to use API for an automatic reshape of your data to a "myop" format.
## Simple data frame with one column for right eye and left eye. iop_wide <- data.frame(id = letters[1:3], iop_r = 11:13, iop_l = 14:16) iop_wide
myop(iop_wide)
Or another example with many more variables:
Click to unfold code to create
wide_df
wide_df <- data.frame( id = letters[1:4], surgery_right = c("TE", "TE", "SLT", "SLT"), surgery_left = c("TE", "TE", "TE", "SLT"), iop_r_preop = 21:24, iop_r_postop = 11:14, iop_l_preop = 31:34, iop_l_postop = 11:14, va_r_preop = 41:44, va_r_postop = 45:48, va_l_preop = 41:44, va_l_postop = 45:48 )
# library(flextable) # wide_df %>% # flextable() %>% # autofit() %>% # save_as_image("messy.png", zoom = 3, expand = 10, webshot = "webshot")
myop_df <- myop(wide_df) myop_df
If you actually need certain eye-related variables spread over two columns, hyperop()
is your friend:
hyperop(myop(iop_wide), iop) hyperop(myop_df, cols = matches("va|iop"))
See your data in a blink of an eye - wrapper around myop
, eyes
, va
and reveal
. It will look for VA and for IOP columns and provide the summary stats for the entire cohort and for right and left eyes for each variable.
This requires a certain format of your names and codes
blink(wide_df)
eye works smoother with tidy data (any package does, really!)
An important part of tidy data are good names. Learn more about tidy data.
1) Don't be too creative with your names! 2) Use common coding: - eyes: "r", "re", "od", "right" - or numeric coding r:l = 0:1 or 1:2 - Visual acuity: "VA", "BCVA", "Acuity" - Intraocular pressure: "IOP", "GAT", "NCT", "pressure" - Patient identifier: "pat", "patient", "ID" (ideally both: "patientID" or "patID") 3) Column names: - No spaces! - Do not use numeric coding for eyes in column names - Separate eye and VA and IOP codes with underscores ("bcva_l_preop", "VA_r", "left_va", "IOP_re") - Keep names short - Don't use underscores when you don't need to: Consider each section divided by an underscore as a relevant characteristic of your variable. E.g., "preop" instead of "pre_op", or simply "VA" instead of "VA_ETDRS_Letters"
Good names (eye
will work nicely)
## right and left eyes have common codes ## information on the tested dimension is included ("iop") ## VA and eye strings are separated by underscores ## No unnecessary underscores. names(wide_df) names(iop_wide)
OK names (eye
will work)
## Id and Eye are common names, there are no spaces ## VA is separated from the rest with an underscore ## BUT: ## The names are quite long ## There is an unnecessary underscore (etdrs are always letters). Better just "VA" c("Id", "Eye", "FollowupDays", "BaselineAge", "Gender", "VA_ETDRS_Letters", "InjectionNumber") ## All names are commonly used (good!) ## But which dimension of "r"/"l" are we exactly looking at? c("id", "r", "l")
Bad names (eye
will fail)
## VA/IOP not separated with underscore ## `eye` won't be able to recognize IOP and VA columns c("id", "iopr", "iopl", "VAr", "VAl") ## A human may think this is clear ## But `eye` will fail to understand those variable names c("person", "goldmann", "vision") ## Not even clear to humans c("var1", "var2", "var3")
When I started with R, I found it challenging to rename columns and I found the following threads on stackoverflow very helpful:
I find the two following methods straight forward:
# I've got a data frame with unfortunate names: name_mess <- data.frame(name = "a", oculus = "r", eyepressure = 14, vision = 0.2) names(name_mess) ## rename all names names(name_mess) <- c("patID", "eye", "IOP", "VA") names(name_mess)
names(name_mess) <- c("name", "oculus", "eyepressure", "vision")
## To rename only specific columns, even if you are not sure about their exact position: names(name_mess)[names(name_mess) %in% c("name", "vision")] <- c("patID", "VA") names(name_mess)
I do not assume responsability for your data or analysis. Please always keep a critical mind when working with data - if you do get results that seem implausible, there may be a chance that the data is in an unfortunate shape for which eye
may not be suitable.
getage()
tidyverse
packages and the packages roxygen2
, usethis
, testthis
and devtools
, all on which eye
heavily relies.Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.