Skip to content

Commit

Permalink
Merge pull request #14 from RinteRface/date-filters
Browse files Browse the repository at this point in the history
Date filters, add shiny app …
  • Loading branch information
DivadNojnarg authored Jan 22, 2024
2 parents 5ed6dd0 + 62b0e12 commit 7fd35b9
Show file tree
Hide file tree
Showing 14 changed files with 592 additions and 78 deletions.
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Generated by roxygen2: do not edit by hand

export("%>%")
export(create_app_daily_session_chart)
export(create_app_daily_usage_chart)
export(create_app_ranking)
export(create_app_ranking_table)
Expand Down Expand Up @@ -34,6 +35,7 @@ export(sort_users_by_role)
import(apexcharter)
import(dplyr)
import(echarts4r)
import(lubridate)
import(purrr)
import(toastui)
import(visNetwork)
Expand Down
109 changes: 88 additions & 21 deletions R/helpers-charts.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@
#' @import echarts4r
#' @importFrom shiny validate need is.reactive
create_calendar_chart <- function(
calendar_data,
title,
subtitle = NULL,
start_date = NULL,
end_date = NULL,
callback = NULL
calendar_data,
title,
subtitle = NULL,
start_date = NULL,
end_date = NULL,
callback = NULL
) {

Date <- Freq <- NULL

tryCatch({
session <- get("session", parent.frame(2))
ns <- session$ns
}, error = function(e) {
ns <- identity
})

renderEcharts4r({
validate(need(nrow(calendar_data()) > 0, "No calendar data found ..."))
if (is.reactive(calendar_data)) calendar_data <- calendar_data()
Expand All @@ -51,7 +58,16 @@ create_calendar_chart <- function(
) %>%
e_title(title, subtitle) %>%
e_tooltip() %>%
e_legend(show = FALSE)
e_legend(show = FALSE) %>%
e_on(
list(),
sprintf(
"function(e) {
Shiny.setInputValue('%s', e.data.value[0], {priority: 'event'});
}",
ns("selected_date")
)
)

if (!is.null(callback)) {
calendar_chart %>% htmlwidgets::onRender(callback)
Expand All @@ -70,13 +86,64 @@ create_calendar_chart <- function(
#' See \url{https://echarts4r.john-coene.com/articles/chart_types.html#calendar-1}.
#'.
#' @param app_usage Returned by \link{get_app_daily_usage}.
#' @param ... Pass down any param to \link{create_calendar_chart}.
#' @return A calendar chart displaying daily app usage.
#' @export
create_app_daily_usage_chart <- function(app_usage) {
create_calendar_chart(app_usage, "Overall app usage")
create_app_daily_usage_chart <- function(app_usage, ...) {
create_calendar_chart(app_usage, "Overall app usage", "units: user sessions/day", ...)
}


#' Generic calendar chart generator
#'
#' @param calendar_data Calendar chart data.
#' @param title Chart title.
#' @param subtitle Chart subtitle.
#' @param start_date Default to minimum calendar_data date. Could also be
#' an input value with Shiny.
#' @param end_date Default to maximum calendar_data date. Could also be
#' an input value with Shiny.
#' @param callback JS function to pass to \link[htmlwidgets]{onRender}. This is
#' useful to access the widget API on the R side at render time
#' and add events on the fly.
#'
#' @return An echarts4r line chart
#' @export
create_app_daily_session_chart <- function(
calendar_data,
title = "Cumulated daily usage",
subtitle = "time units: minutes",
start_date = NULL,
end_date = NULL,
callback = NULL
) {

cum_dur <- NULL

renderEcharts4r({
validate(need(nrow(calendar_data()) > 0, "No calendar data found ..."))
if (is.reactive(calendar_data)) calendar_data <- calendar_data()
if (is.null(start_date)) start_date <- min(calendar_data$Date)
if (is.null(end_date)) end_date <- max(calendar_data$Date)
if (is.reactive(start_date)) start_date <- start_date()
if (is.reactive(end_date)) end_date <- end_date()
if (is.reactive(title)) title <- title()

usage_chart <- calendar_data %>%
filter(.data$Date >= start_date & .data$Date <= end_date) %>%
e_charts(Date) %>%
e_line(cum_dur) %>%
e_title(title, subtitle) %>%
e_tooltip() %>%
e_legend()

if (!is.null(callback)) {
usage_chart %>% htmlwidgets::onRender(callback)
} else {
usage_chart
}
})
}


#' Daily app consumption for selected user
Expand Down Expand Up @@ -111,10 +178,10 @@ create_user_daily_consumption_chart <- function(usage) {
#' @importFrom rlang .data
#' @importFrom shiny req is.reactive
create_cumulated_duration_per_user <- function(
apps_usage,
start_date = NULL,
end_date = NULL,
selected_app) {
apps_usage,
start_date = NULL,
end_date = NULL,
selected_app) {

username <- cum_duration <- NULL

Expand All @@ -128,8 +195,8 @@ create_cumulated_duration_per_user <- function(
apps_usage %>%
filter(
.data$started >= start_date &
.data$started <= end_date &
.data$app_name == !!selected_app()
.data$started <= end_date &
.data$app_name == !!selected_app()
) %>%
group_by(.data$username) %>%
summarise(cum_duration = as.numeric(round(sum(.data$duration) / 3600, 1))) %>%
Expand Down Expand Up @@ -165,10 +232,10 @@ create_cumulated_duration_per_user <- function(
#' @importFrom rlang .data
#' @importFrom shiny req is.reactive
create_cumulated_hits_per_user <- function(
apps_usage,
start_date = NULL,
end_date = NULL,
selected_app
apps_usage,
start_date = NULL,
end_date = NULL,
selected_app
) {

username <- NULL
Expand All @@ -183,8 +250,8 @@ create_cumulated_hits_per_user <- function(
apps_usage %>%
filter(
.data$started >= start_date &
.data$started <= end_date &
.data$app_name == !!selected_app()
.data$started <= end_date &
.data$app_name == !!selected_app()
) %>%
group_by(.data$username) %>%
summarise(n = n()) %>% # prefer summarize over sort to remove grouping
Expand Down
87 changes: 69 additions & 18 deletions R/helpers-data.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
#' @param app app_name to filter.
#' @param logs Given by RSC database.
#'
#' @return A vector containing dates of usage for
#' the given app.
#' @return A tibble containing dates of usage for
#' the given app as well as the correponding session duration.
#' @import dplyr
#' @export
#' @importFrom rlang .data
get_rsc_app_dates <- function(app, logs) {
logs %>%
filter(.data$app_name == !!app) %>%
pull(.data$started)
select(.data$started, .data$duration)
}


Expand All @@ -22,7 +22,7 @@ get_rsc_app_dates <- function(app, logs) {
#' @param logs Given by RSC database.
#'
#' @return A 3 columns tibble with app name, usage and date of usage (nested tibble).
#' @import dplyr purrr
#' @import dplyr purrr lubridate
#' @export
#' @importFrom rlang .data
get_rsc_apps_usage <- function(logs) {
Expand All @@ -31,7 +31,6 @@ get_rsc_apps_usage <- function(logs) {
tmp_apps_usage <- logs %>%
group_by(.data$app_name) %>%
count(sort = TRUE)

# handle dates. It's quite heavy but we need for
# each app the dates of usage and a count for each date.
# Reason why we use table(). We also need to nest them
Expand All @@ -44,19 +43,29 @@ get_rsc_apps_usage <- function(logs) {
get_rsc_app_dates,
logs
) %>%
map(tibble::as_tibble) %>%
map(
~ {
tbl <- ..1 %>%
dat_in <- ..1 %>%
# Be careful, RSC provides datetime format but
# this is too specific to count at the scale of a day.
# We must floor to the corresponding day.
mutate(value = lubridate::floor_date(value, "day")) %>%
mutate(started = floor_date(.data$started, "day"))

tbl <- dat_in %>%
select(-.data$duration) %>%
table() %>%
tibble::as_tibble()

names(tbl) <- c("Date", "Freq")
tbl

# Create duration table
cumulated_durations <- do.call(rbind.data.frame, map(tbl$Date, ~ {
dat_in %>%
filter(started == as_datetime(..1)) %>%
summarise(cum_dur = minute(seconds_to_period(sum(.data$duration, na.rm = TRUE))))
}))

cbind(tbl, cumulated_durations)
}
) %>%
map(nest_by, .key = "calendar_data") %>%
Expand Down Expand Up @@ -270,7 +279,7 @@ get_user_daily_consumption <- function(content, users, apps, selected_user) {
grouped_by_date <- reactive({
req(nrow(events()) > 0)
events() %>%
mutate(floored_started = lubridate::floor_date(.data$started, "day")) %>%
mutate(floored_started = floor_date(.data$started, "day")) %>%
group_by(.data$floored_started) %>%
count(sort = TRUE) %>%
select(Date = .data$floored_started, Freq = .data$n)
Expand All @@ -284,16 +293,32 @@ get_user_daily_consumption <- function(content, users, apps, selected_user) {
#' See \link{create_app_ranking_table}.
#'
#' @inheritParams merge_rsc_data
#' @param start_date Default to minimum calendar_data date. Could also be
#' an input value with Shiny.
#' @param end_date Default to maximum calendar_data date. Could also be
#' an input value with Shiny.
#'
#' @return A list containing: `[[1]]` merged data between app usage and users data.
#' `[[2]]`: data to be digested by \link{create_app_ranking_table}.
#' @export
#' @import dplyr
#' @importFrom rlang .data quo eval_tidy
#' @importFrom shiny reactive is.reactive
create_app_ranking <- function(content, users, apps) {
create_app_ranking <- function(content, users, apps, start_date = NULL, end_date = NULL) {
tmp <- quo({
rsc_data_merged <- merge_rsc_data(content, users, apps)
if (is.null(start_date)) start_date <- min(rsc_data_merged$apps_usage_merged$started)
# Note: this might be surprising but some end date are not available in ended so
# we have to take the max of the start date.
if (is.null(end_date)) end_date <- max(rsc_data_merged$apps_usage_merged$started)
if (is.reactive(start_date)) start_date <- start_date()
if (is.reactive(end_date)) end_date <- end_date()

rsc_data_merged[[3]] <- rsc_data_merged[[3]] %>%
filter(
.data$started >= start_date &
.data$started <= end_date
)

processed_rsc_apps_usage <- rsc_data_merged[[3]] %>%
get_rsc_apps_usage() %>%
Expand All @@ -308,7 +333,8 @@ create_app_ranking <- function(content, users, apps) {
list(rsc_data_merged[[3]], processed_rsc_apps_usage)
})

if (is.reactive(users) || is.reactive(content) || is.reactive(apps)) {
if (is.reactive(users) || is.reactive(content) || is.reactive(apps) ||
is.reactive(start_date) || is.reactive(end_date)) {
if (is.reactive(users)) user <- users()
if (is.reactive(content)) content <- content()
if (is.reactive(apps)) apps <- apps()
Expand Down Expand Up @@ -396,15 +422,22 @@ create_dev_ranking <- function(users, content) {
#' Sort RStudio Connect users by role
#'
#' Users are grouped by user_role to check the
#' server role repartition.
#' server role repartition. Using start_date and end_date allows
#' to filter data given a specific time range.
#'
#' @param users Get from \link[connectapi]{get_users}.
#' @param start_date Date filter.
#' @param end_date Date filter.
#'
#' @return A tibble with user grouped by role.
#' @export
#' @importFrom rlang .data
sort_users_by_role <- function(users) {
sort_users_by_role <- function(users, start_date = NULL, end_date = NULL) {
if (is.null(start_date)) start_date <- min(users$created_time)
if (is.null(end_date)) end_date <- max(users$created_time)

users %>%
filter(.data$created_time >= start_date & .data$created_time <= end_date) %>%
group_by(.data$user_role) %>%
summarize(n = n()) %>%
mutate(Percentage = round(n / sum(n) * 100))
Expand All @@ -415,12 +448,17 @@ sort_users_by_role <- function(users) {
#'
#'
#' @param content Get from \link[connectapi]{get_content}.
#' @inheritParams sort_users_by_role
#'
#' @return A tibble with content grouped by access type.
#' @export
#' @importFrom rlang .data
sort_content_by_access <- function(content) {
sort_content_by_access <- function(content, start_date = NULL, end_date = NULL) {
if (is.null(start_date)) start_date <- min(content$created_time)
if (is.null(end_date)) end_date <- max(content$created_time)

content %>%
filter(.data$created_time >= start_date & .data$created_time <= end_date) %>%
group_by(.data$access_type) %>%
summarize(n = n()) %>%
mutate(Percentage = round(n / sum(n) * 100))
Expand All @@ -432,13 +470,21 @@ sort_content_by_access <- function(content) {
#'
#'
#' @param content Get from \link[connectapi]{get_content}.
#' @inheritParams sort_users_by_role
#'
#' @return A tibble with content grouped by R version.
#' @export
#' @importFrom rlang .data
sort_content_by_rversion <- function(content) {
sort_content_by_rversion <- function(content, start_date = NULL, end_date = NULL) {
if (is.null(start_date)) start_date <- min(content$created_time)
if (is.null(end_date)) end_date <- max(content$created_time)

content %>%
filter(!is.na(.data$r_version)) %>%
filter(
!is.na(.data$r_version) &
.data$created_time >= start_date &
.data$created_time <= end_date
) %>%
group_by(.data$r_version) %>%
summarize(n = n()) %>%
mutate(Percentage = round(n / sum(n) * 100, 1))
Expand All @@ -464,12 +510,17 @@ sort_content_by_pyversion <- function(content) {
#'
#'
#' @param content Get from \link[connectapi]{get_content}.
#' @inheritParams sort_users_by_role
#'
#' @return A tibble with content grouped by app mode.
#' @export
#' @importFrom rlang .data
sort_content_by_appmode <- function(content) {
sort_content_by_appmode <- function(content, start_date = NULL, end_date = NULL) {
if (is.null(start_date)) start_date <- min(content$created_time)
if (is.null(end_date)) end_date <- max(content$created_time)

content %>%
filter(.data$created_time >= start_date & .data$created_time <= end_date) %>%
group_by(.data$app_mode) %>%
summarize(n = n()) %>%
mutate(Percentage = round(n / sum(n) * 100, 1))
Expand Down
Loading

0 comments on commit 7fd35b9

Please sign in to comment.