Sections:
Visualizations – list totals, bar chart of when created by year/month last 12 months, bar chart of top 20 users creating
Interpretations – Total+comments, total users, count for top 20 users, visualizations with an interpretation/comment
Dashboards – Comparison (views, users, visualizations), over time, average views by hour of each day, distinct user-days viewing each dashboard, interpretations left on dashboard objects
Viz Profile – Views for the image (total views and total users), interpretations+comments
To do:
Set up and login
# baseurl<-"https://play.dhis2.org/2.37dev/"
# username<-"admin"
# password<-"district"
#
# startdate<-"2015-01-01"
# enddate<-"2021-12-01"
# If set by parameters
baseurl<-params$baseurl
username<-params$username
password<-params$password
startdate<-params$startdate
enddate<-params$enddate
####Load required packages
packages<-c("httr","assertthat","tidyverse","jsonlite","knitr","lubridate","here")
install_or_load_pack <- function(pack){
create.pkg <- pack[!(pack %in% installed.packages()[, "Package"])]
if (length(create.pkg))
install.packages(create.pkg, dependencies = TRUE, quiet=TRUE)
sapply(pack, require, character.only = TRUE)
}
install_or_load_pack(packages)
## httr assertthat tidyverse jsonlite knitr lubridate here
## TRUE TRUE TRUE TRUE TRUE TRUE TRUE
# Set theme for charts etc
theme_set(theme_minimal())
# Extract login info from directory
# if (!file.exists("auth.json")){
# stop("Please add auth.json to directory")
# } else {
# baseurl<-chuck(fromJSON("auth.json"), "dhis","baseurl")
# username<-chuck(fromJSON("auth.json"), "dhis","username")
# }
##test login
loginDHIS2<-function(baseurl,username,password){
url<-paste0(baseurl,"api/me")
r<-GET(url,authenticate(username,password))
assert_that(r$status_code == 200L)}
if(loginDHIS2(baseurl,username,password)){
print("successfully logged in")
}else{
stop("could not log in! Please check url, username and password in auth.json")
}
## [1] "successfully logged in"
Extract visualizations and their interpretations
#extract viz types
#might wittle down the fields we want in request, later
fetch_viz_obj<-function(obj_name){
url<-paste0(baseurl,"api/",obj_name,".json?fields=:all&paging=false")
fromJSON(content(GET(url),type="text", encoding="UTF-8")) %>%
pluck(obj_name) %>%
select(any_of(c("name","id","createdBy","created", "interpretations","type"))) %>%
jsonlite::flatten() %>%
as_tibble() %>%
complete() %>%
mutate(int_count = map_int(interpretations, n_distinct),
obj_name = obj_name) %>%
select(any_of(c("name","id", "type","int_count","obj_name","created",
"createdBy.name","createdBy.id")))
}
# ev_viz<-fetch_viz_obj("eventReports")
viz_list<-list("eventReports","maps","eventCharts","visualizations")
viz_users<-viz_list %>%
map_dfr(~fetch_viz_obj(.)) %>%
mutate(type=if_else(is.na(type),toupper(obj_name),type))
#
# viz_users %>%
# filter(is.na(creator_id) & !is.na(creator_name))
viz_users %>% select(name,type,int_count) %>% slice_sample(n=6) %>%
kable(caption="A selection of visualizations and their interpretation count")
| name | type | int_count |
|---|---|---|
| HIV: HIV testing by gender | COLUMN | 0 |
| Inpatient: Mode of discharge last 12 months (stacked) | STACKED_COLUMN | 1 |
| Immunization: Measles Cov Facilities this year | MAPS | 0 |
| Immunization: Std dev doses given last 12 months | COLUMN | 0 |
| Commodities: Maternal Health districts last 4 quarters | PIVOT_TABLE | 0 |
| Child Health: Diarrhoea <5 | LINE | 1 |
419 visualizations created by 7 users.
“Interpretations” here does not include user comments on interpretations.
# viz_users %>%
# count(type,sort=T)
viz_users %>%
group_by(type) %>%
summarize(total_saved=n(),
total_interpretations=sum(int_count)) %>%
arrange(-total_saved) %>%
knitr::kable(caption="Visualizations saved in time window")
| type | total_saved | total_interpretations |
|---|---|---|
| PIVOT_TABLE | 130 | 9 |
| COLUMN | 96 | 12 |
| MAPS | 93 | 2 |
| EVENTREPORTS | 31 | 2 |
| LINE | 18 | 5 |
| PIE | 15 | 3 |
| STACKED_COLUMN | 12 | 1 |
| GAUGE | 6 | 0 |
| BAR | 4 | 2 |
| RADAR | 3 | 0 |
| AREA | 2 | 0 |
| SCATTER | 2 | 0 |
| STACKED_BAR | 2 | 0 |
| YEAR_OVER_YEAR_LINE | 2 | 0 |
| SINGLE_VALUE | 1 | 0 |
| STACKED_AREA | 1 | 0 |
| YEAR_OVER_YEAR_COLUMN | 1 | 0 |
“Viz” include event charts, event reports, pivot tables, and maps.
viz_users %>%
mutate(year=year(created)) %>%
count(year) %>%
complete(year=seq(min(year),max(year)), fill=list(n=0)) %>%
ggplot(aes(x=year,y=n)) +
geom_col() +
labs(title="Visualizations Created By Year")
viz_users %>%
mutate(month=month(created,label=TRUE),
year=year(created)) %>%
filter(year==year(Sys.Date())) %>%
count(month) %>%
complete(month, fill=list(n=0)) %>%
ggplot(aes(x=month,y=n)) +
geom_col() +
labs(title="Visualizations Created This Year By Month")
Top 10 users creating visualizations
viz_users %>%
count(createdBy.name, sort=T) %>%
head(10) %>%
kable(caption="Total visualizations created, top 10 users")
| createdBy.name | n |
|---|---|
| Tom Wakiki | 343 |
| John Traore | 47 |
| NA | 21 |
| Didier Konan | 5 |
| Ali Nana | 1 |
| John Kamara | 1 |
| Kevin Boateng | 1 |
Extract objects within dashboards
#Get a list of all objects in dashboards
url<-paste0(baseurl,"api/dashboards.json?fields=name,id,dashboardItems&paging=false")
dash<-fromJSON(content(GET(url),type="text", encoding="UTF-8"))
dash_stats<-dash %>%
pluck("dashboards") %>%
unnest_longer(dashboardItems) %>%
jsonlite::flatten() %>%
as_tibble() %>%
complete() %>%
select("dash_name"=name,"dash_id"=id, dashboardItems.created,dashboardItems.lastUpdated,
dashboardItems.eventChart.id, dashboardItems.eventReport.id,
dashboardItems.map.id, dashboardItems.visualization.id) %>%
unite(col="dashItem_viz_id",dashboardItems.visualization.id:dashboardItems.eventReport.id, na.rm=T)
# we can also measure if a dashboard object has been updated or created recently
# dash_stats %>%
# mutate(updated=if_else(ymd_hms(dashboardItems.created)==ymd_hms(dashboardItems.lastUpdated), 0, 1)) %>% View()
# count(updated)
viz_users_dash<-left_join(viz_users,dash_stats %>% select(dash_name,dash_id,dashItem_viz_id),
by=c("id"="dashItem_viz_id"))
#Now we can see which dashboards each viz is a part of (considering dashboards the login user can access)
viz_users_dash_merged<-viz_users_dash %>%
complete() %>%
group_by(across(.cols=name:int_count)) %>%
mutate(dash=if_else(is.na(dash_name),0,1)) %>%
summarize(dash_count=sum(dash),
dash_list=paste(dash_name,collapse=" | ")) %>%
ungroup()
There are 22 total dashboards containing 419 total visualization objects.
#post the datastatisticsevent sql view and fetch data
view_name<-"dataStatisticEvent_"
view_id<-"R6iWYMIDiUt"
sqlView<-list(
sqlViews=list(
list(name= view_name,
id= view_id,
sqlQuery= "select * from datastatisticsevent",
type= "MATERIALIZED_VIEW",
cacheStrategy= "NO_CACHE"
)))
payload<-jsonlite::toJSON(sqlView, auto_unbox = TRUE, pretty=TRUE)
url<-paste0(baseurl,"api/metadata.json")
r<-POST(url, body=payload, content_type_json())
#check
# content(r)
## Update sharing settings
url<-paste0(baseurl,"api/sharing?type=sqlView&id=",view_id)
view_sharing<-list(object=
list(publicAccess="rwr------",
externalAccess=FALSE,
user=list(),
userGroupAccesses=list()
) )
r<-POST(url, body=payload, content_type_json())
#check
#content(r)
#Execute it
url<-paste0(baseurl,"api/sqlViews/",view_id,"/execute")
r<-POST(url)
#finally extract datastat event table between dates
url<-paste0(baseurl,"api/sqlViews/",view_id,"/data.csv?filter=timestamp:ge:",startdate,"&filter=timestamp:le:",enddate)
r<-httr::GET(url, httr::authenticate(username,password),httr::timeout(60))
output<-content(r)
views_dta<-read_csv(output)
# views_dta %>%
# filter(!is.na(favoriteuid)) %>%
# left_join(viz_users_dash %>% select(dash_name,dash_id), by=c("favoriteuid"="dash_id")) %>%
# left_join(viz_users_dash, by=c("favoriteuid"="dash_id"))
# interpretations
# views_dta
Now analyze the dashboard view data
dashboards<-dash_stats %>%
filter(!is.na(dashItem_viz_id)) %>%
count(dash_id, dash_name, na.rm=T, name="dash_viz_objects") %>%
select(dash_id, dash_name, dash_viz_objects) %>%
na.omit() %>%
distinct()
dash_views<-views_dta %>%
filter(str_detect(eventtype,"DASH") & !is.na(favoriteuid)) %>%
left_join(dashboards, by=c("favoriteuid"="dash_id")) %>%
mutate(dash_name=if_else(is.na(dash_name),paste0("unnamed_uid_",favoriteuid),dash_name)) %>%
mutate(date=as.Date(ymd_hms((timestamp))),
day=wday(date, label=TRUE, abbr=FALSE))
In total, there are 342 dashboard views across 27 existing dashboards, by 4 users.
dash_views %>%
mutate(timestamp=as.Date(timestamp)) %>%
group_by(dash_name, dash_viz_objects) %>%
summarize(views=n(),
distinct_users=n_distinct(username,na.rm=T),
days_viewed=n_distinct(timestamp,na.rm=T),
distinct_user_days=n_distinct(paste0(username,timestamp))) %>%
kable(caption="Comparison of dashboards by user views")
| dash_name | dash_viz_objects | views | distinct_users | days_viewed | distinct_user_days |
|---|---|---|---|---|---|
| Antenatal Care | 11 | 95 | 4 | 29 | 35 |
| Cases Malaria | 8 | 22 | 2 | 13 | 16 |
| Delivery | 11 | 17 | 2 | 10 | 12 |
| Disease Surveillance | 4 | 10 | 2 | 6 | 7 |
| EE maps | 5 | 26 | 2 | 9 | 10 |
| Immunization | 17 | 23 | 2 | 13 | 16 |
| Immunization data | 10 | 15 | 2 | 11 | 12 |
| Info Videos | 5 | 15 | 2 | 6 | 6 |
| Inpatient BMI, Weight and Height | 8 | 11 | 2 | 7 | 8 |
| Inpatient Discharge | 9 | 13 | 2 | 7 | 8 |
| Inpatient Morbidity Mortality | 14 | 15 | 2 | 9 | 9 |
| Inpatient Visit Overview | 3 | 10 | 2 | 5 | 5 |
| Key Indicators | 6 | 8 | 2 | 4 | 4 |
| Malnutrition | 7 | 2 | 1 | 1 | 1 |
| Measles (user org unit) | 6 | 4 | 2 | 3 | 3 |
| Mother and Child Health | 17 | 3 | 1 | 1 | 1 |
| Nutrition | 6 | 3 | 2 | 3 | 3 |
| Reporting Rates | 8 | 6 | 1 | 2 | 2 |
| Reporting Reproductive Health | 11 | 9 | 2 | 4 | 4 |
| Staffing | 2 | 6 | 2 | 3 | 3 |
| Top Contacts | 3 | 6 | 2 | 4 | 4 |
| unnamed_uid_cgck9Fa3uZn | NA | 1 | 1 | 1 | 1 |
| unnamed_uid_fJ0q2N36IE1 | NA | 1 | 1 | 1 | 1 |
| unnamed_uid_hSS0wt6gbUK | NA | 3 | 1 | 2 | 2 |
| unnamed_uid_rmPiJIPFL4U | NA | 9 | 1 | 2 | 2 |
| unnamed_uid_Tvro10HbSUp | NA | 3 | 1 | 3 | 3 |
| Visits ANC | 3 | 6 | 2 | 3 | 3 |
Over time, average views by hour of each day
Might be helpful to know how patterns of dashboard views have changed over time.
dash_views %>%
filter(date>floor_date(as.Date(Sys.Date()-months(12)), unit="month")) %>%
mutate(year=year(date),
week=as.integer(week(date))) %>%
count(year,week) %>%
group_by(year) %>%
complete(week=seq(from=1,to=52), fill=list(n=0)) %>%
ggplot() +
geom_col(aes(x=week,y=n)) +
facet_wrap(~year, nrow=1) +
labs(title="Dashboard Views by Week, last 12 months")
# Dashboard viewers by time of day
dash_tod<-dash_views %>%
mutate(hour=hour(timestamp)) %>%
group_by(date, hour) %>%
summarize(views_date_hour=n()) %>%
ungroup() %>%
complete(date=seq.Date(from=min(date), to=max(date),by="days")) %>%
group_by(date) %>%
complete(hour=seq(from=0,to=23),fill=list(views_date_hour=0)) %>%
mutate(day=wday(date, label=TRUE, abbr=FALSE)) %>%
group_by(day,hour) %>%
summarize(mean_views=mean(views_date_hour))
dash_tod %>%
ggplot(aes(x=hour,y=mean_views,color=day)) +
geom_line() +
facet_grid(~day) +
labs(title="Mean Dashboard Views By Day-Hour") +
theme(legend.position = "none")
dash_views %>%
distinct(username,date) %>%
count(username, sort=T) %>%
head(10) %>%
kable(caption="Most days viewing dashboard(s), by user")
| username | n |
|---|---|
| system | 32 |
| admin | 14 |
| analytics | 2 |
| analyticstest | 1 |
#fetch all interpretations within start/end date
#total interpretations by user
#total visualizations with an interpretation
#average char. length of interpretations
#Get a list of all interpretations and comments
url<-paste0(baseurl,
"api/interpretations?fields=id,created,text,likes,type,user[id]",
",visualization,eventReport,map,eventChart,comments[text,user,created]",
"&paging=false")
ints<-fromJSON(content(GET(url),type="text", encoding="UTF-8"))
# Skip this if there are no interpretations
if (!is_null(ints$interpretations)){
interpretations<-ints %>%
pluck("interpretations") %>%
unnest_longer(comments) %>%
jsonlite::flatten() %>%
# select(name,id,type,createdBy,interpretations) %>%
as_tibble() %>%
complete() %>%
select("int_id"=id,type,likes,text,user.id,created,
comments.text,comments.user.id,comments.created,
ends_with(".id")) %>%
unite(col="viz_item_id",visualization.id:eventReport.id,na.rm=T) %>%
pivot_longer(cols=c(text,comments.text),names_to="text_type",values_to="text") %>%
filter(!is.na(text)) %>%
mutate(user=if_else(text_type=="text",user.id,comments.user.id),
created=if_else(text_type=="text",created,comments.created),
length=str_length(text)) %>%
select(everything(),-comments.created,-comments.user.id,-user.id) %>% distinct()
## Selectively fetch the users who have written interpretations
int_users<-paste0(unique(interpretations$user),collapse=",")
url<-paste0(baseurl,"api/users.csv?paging=false&fields=id,name&filter=id:in:[",int_users,"]")
int_users<-read_csv(content(GET(url),type="text", encoding="UTF-8"))
int_table<-interpretations %>%
mutate(date=as.Date(created)) %>%
left_join(int_users, by=c("user"="id")) %>%
group_by(name, user) %>%
summarize("total interpretations"=n(),
"unique items with interpretation"=n_distinct(viz_item_id),
"mean length in characters"=round(mean(length),1),
"total days with interpretation "=n_distinct(date)) %>%
arrange(desc(`total interpretations`)) %>%
head(10) %>%
kable(caption="Total Interpretations and Comments, Top 10 users")
total_int_comments<-nrow(interpretations)
total_int_users<-length(unique(interpretations$user))
}else{
print("No Interpretations found")
total_int_comments<-0
total_int_users<-0
int_table<-NULL %>% as_tibble()
interpretations<-NULL
}
int_table
| name | user | total interpretations | unique items with interpretation | mean length in characters | total days with interpretation |
|---|---|---|---|---|---|
| Tom Wakiki | GOLswS44mh8 | 30 | 19 | 73.4 | 23 |
| John Traore | xE7jOejl9FI | 10 | 4 | 54.6 | 7 |
| John Kamara | N3PZBUlN8vq | 8 | 5 | 210.1 | 5 |
| Didier Konan | I9fMsY4pRKk | 5 | 5 | 142.8 | 3 |
| NA | gEnZri18JsV | 5 | 3 | 221.8 | 2 |
| NA | EZtxytGsq8F | 3 | 2 | 429.7 | 2 |
| Kevin Boateng | OYLGMiazHtW | 1 | 1 | 129.0 | 1 |
| Seydou Keita | Onf73mPD6sL | 1 | 1 | 201.0 | 1 |
| Suleimane Diawara | awtnYWiVEd5 | 1 | 1 | 123.0 | 1 |
Overall, 64 total interpretations and comments were left by 9 users.
Print out the visualization with stats about it.
A usage report for each visualization could look like this, with one page per visualization in the system.
viz_focus<-params$viz_focus
url<-paste0(baseurl, "api/visualizations/",viz_focus,"/data.png")
# resp<-GET(url)
r<-suppressWarnings(GET(url,
write_disk("test.png", overwrite = TRUE)))
knitr::include_graphics('./test.png')
viz_users %>%
filter(id==viz_focus) %>%
select(name,type,createdBy.name,created) %>%
t() %>%
kable(caption="Visualization Details")
| name | ANC: 1st and 3rd trends Monthly |
| type | LINE |
| createdBy.name | Tom Wakiki |
| created | 2012-11-05T09:00:29.592 |
viz_users_dash %>%
filter(id==viz_focus) %>% select(dash_id) %>%
left_join(dash_views, by=c("dash_id"="favoriteuid")) %>%
count(dash_name, sort=T) %>%
kable(caption="Total Views of dashboards with this Visualization")
| dash_name | n |
|---|---|
| Mother and Child Health | 3 |
interpretations %>%
filter(viz_item_id==viz_focus) %>%
count(text_type) %>%
kable(caption="Total interpretations and comments on Viz")
| text_type | n |
|---|---|
| comments.text | 1 |
| text | 1 |
# url<-paste0(baseurl,"api/svg.png")
# resp<-POST(url, body=upload_file("pic_request.txt"), type="application/x-www-form-urlencoded;charset=UTF-8")
#
# httr::content(resp)
# obj<-read_file("pic_request.txt")
# class(obj)
CSV files written to the project’s “outputs” directory
outputs<-list(
"interpretations"=interpretations,
"dashboard_views"=dash_views,
"all_viz_dash_views"=views_dta,
"visualizations"=viz_users_dash
)
## If folder for outputs doesnt exist create one
if (!dir.exists(here("outputs"))){
dir.create("outputs")
}
outputs %>%
names(.) %>%
map(~ write_csv(outputs[[.]], here("outputs", paste0(., ".csv"))))
## [[1]]
## # A tibble: 64 × 9
## int_id type likes created viz_item_id text_type text user length
## <chr> <chr> <int> <chr> <chr> <chr> <chr> <chr> <int>
## 1 A9Gztnu9n3l VISUA… 0 2020-04… pRBQ77mhEJ8 text We can … N3PZ… 365
## 2 A9Gztnu9n3l VISUA… 0 2012-07… pRBQ77mhEJ8 comments… Yes it … N3PZ… 86
## 3 AfuXQZm3ybv VISUA… 0 2020-03… Kt3GsRHXkaU text This ch… I9fM… 226
## 4 Ax6kLh6VZOy VISUA… 0 2021-03… OAeeTRB4Y9E text A large… GOLs… 65
## 5 BR11Oy1Q4yR VISUA… 0 2021-10… R9A0rvAydpn text This ch… xE7j… 61
## 6 BR11Oy1Q4yR VISUA… 0 2014-10… R9A0rvAydpn comments… It migh… xE7j… 46
## 7 BR11Oy1Q4yR VISUA… 0 2014-10… R9A0rvAydpn comments… Yes I b… xE7j… 16
## 8 br7V5OdxEmI VISUA… 0 2020-11… nRtApqye0HW text This pi… GOLs… 189
## 9 c4IU6PJf1Eb EVENT… 0 2021-05… qd2jBEvoRPx text This ch… GOLs… 81
## 10 cjG99uolq7c VISUA… 0 2020-03… Emq3LEyWb15 text We can … N3PZ… 206
## # … with 54 more rows
##
## [[2]]
## # A tibble: 342 × 9
## eventid eventtype timestamp username favoriteuid dash_name
## <dbl> <chr> <dttm> <chr> <chr> <chr>
## 1 858844 DASHBOARD_VIEW 2016-06-22 18:00:42 system nghVC4wtyzi Antenatal Ca…
## 2 858845 DASHBOARD_VIEW 2016-06-22 18:00:55 system iMnYyBfSxmM Delivery
## 3 858846 DASHBOARD_VIEW 2016-06-22 18:01:04 system nghVC4wtyzi Antenatal Ca…
## 4 858847 DASHBOARD_VIEW 2016-06-22 18:01:13 system nghVC4wtyzi Antenatal Ca…
## 5 858848 DASHBOARD_VIEW 2016-06-22 18:01:19 system nTTLMwiwoys Inpatient Vi…
## 6 858849 DASHBOARD_VIEW 2016-06-22 18:01:38 system eZSIccgeq94 Inpatient Di…
## 7 858850 DASHBOARD_VIEW 2016-06-22 18:01:40 system JW7RlN5xafN Cases Malaria
## 8 858851 DASHBOARD_VIEW 2016-06-22 18:01:43 system eZSIccgeq94 Inpatient Di…
## 9 858852 DASHBOARD_VIEW 2016-06-22 18:01:44 system uGSg3NSw6TZ Inpatient BM…
## 10 858853 DASHBOARD_VIEW 2016-06-22 18:01:46 system MBUMbG6zJIj Reporting Re…
## # … with 332 more rows, and 3 more variables: dash_viz_objects <int>,
## # date <date>, day <ord>
##
## [[3]]
## # A tibble: 2,625 × 5
## eventid eventtype timestamp username favoriteuid
## <dbl> <chr> <dttm> <chr> <chr>
## 1 624539 DASHBOARD_VIEW 2016-04-18 13:11:54 system <NA>
## 2 624540 DASHBOARD_VIEW 2016-04-18 13:19:28 system <NA>
## 3 624541 DASHBOARD_VIEW 2016-04-18 14:13:49 system <NA>
## 4 624542 DASHBOARD_VIEW 2016-04-18 14:14:25 system <NA>
## 5 624543 DASHBOARD_VIEW 2016-04-18 14:46:09 system <NA>
## 6 624544 DASHBOARD_VIEW 2016-04-18 14:47:19 system <NA>
## 7 624545 DASHBOARD_VIEW 2016-04-18 15:02:07 system <NA>
## 8 624546 DASHBOARD_VIEW 2016-04-18 15:02:59 system <NA>
## 9 624547 DASHBOARD_VIEW 2016-04-18 15:03:00 system <NA>
## 10 624548 DASHBOARD_VIEW 2016-04-18 15:30:26 system <NA>
## # … with 2,615 more rows
##
## [[4]]
## # A tibble: 427 × 10
## name id int_count obj_name created createdBy.name createdBy.id type
## <chr> <chr> <int> <chr> <chr> <chr> <chr> <chr>
## 1 Child he… YZzuV… 0 eventRe… 2017-0… Tom Wakiki GOLswS44mh8 EVEN…
## 2 Child he… sAqSL… 0 eventRe… 2019-0… Tom Wakiki GOLswS44mh8 EVEN…
## 3 Child he… NTOUv… 0 eventRe… 2017-0… Tom Wakiki GOLswS44mh8 EVEN…
## 4 Inpatien… aDrb9… 0 eventRe… 2015-0… Tom Wakiki GOLswS44mh8 EVEN…
## 5 Inpatien… TIuOz… 0 eventRe… 2014-0… John Traore xE7jOejl9FI EVEN…
## 6 Inpatien… p8tmW… 0 eventRe… 2017-0… Tom Wakiki GOLswS44mh8 EVEN…
## 7 Inpatien… fmvL1… 0 eventRe… 2017-0… Tom Wakiki GOLswS44mh8 EVEN…
## 8 Inpatien… itNBw… 0 eventRe… 2014-0… John Traore xE7jOejl9FI EVEN…
## 9 Inpatien… R4wAb… 0 eventRe… 2014-0… John Traore xE7jOejl9FI EVEN…
## 10 Inpatien… pLJAn… 0 eventRe… 2014-0… John Traore xE7jOejl9FI EVEN…
## # … with 417 more rows, and 2 more variables: dash_name <chr>, dash_id <chr>