Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

234 range selection with plotly #289

Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
7dfaa98
add plotly graph
May 17, 2023
b307feb
add plotly dependency
May 17, 2023
5798d54
move histogram creation to server
May 17, 2023
10f6cc2
modify plot creation
May 18, 2023
b50eb3a
make plot static on disable
May 18, 2023
83f2208
add mask do disabled plot
May 18, 2023
898bad3
adjust colors
May 18, 2023
b55aeec
prevent plot resizing
May 18, 2023
68662d7
update fixed server
May 18, 2023
6e29ba5
clean up
May 18, 2023
cac8483
simplify
May 18, 2023
73fc589
clean up
May 18, 2023
9f78919
Merge branch 'filter_panel_refactor@main' into 234_range_selector@fil…
May 22, 2023
4fe4f7a
remove excess
May 22, 2023
35067c4
reduce code duplication for histogram creation
May 22, 2023
f08864f
minor edits
May 22, 2023
d208903
remove adjusting values to former slider ticks
May 22, 2023
db4317b
round selection to 4 significant digits
May 22, 2023
7f193b7
add function to determine bootstrap colors
May 23, 2023
1b3ba5d
specify plot colors better(?)
May 23, 2023
ae70252
amend documentation
May 23, 2023
3d486df
update dependencies
May 23, 2023
1f62853
temporarily suspend unit tests
May 23, 2023
bfde124
modify step for numeric input
May 24, 2023
2ad448f
Merge branch 'filter_panel_refactor@main' into 234_range_selector@fil…
May 29, 2023
7d6cf74
adjust out of bounds selection
May 29, 2023
11fe5a3
elongate border lines
May 29, 2023
61757ca
some comments
May 29, 2023
a98e41c
refine dependencies
May 29, 2023
c1383a6
block hyperreactivity
May 30, 2023
8cc7a7a
simplify plotting
Jun 1, 2023
e18bf85
add plto action help
Jun 1, 2023
6955c69
make shapes even longer
Jun 1, 2023
5eec397
add spinners
Jun 1, 2023
75d3a03
add shinycssloaders dependency
Jun 1, 2023
2dfc5f3
change icon
Jun 2, 2023
a94fb12
move icon onto plot
Jun 2, 2023
c6c6483
add plot margins
Jun 2, 2023
e676f3a
upgrade axis ticks
Jun 2, 2023
d2c4843
modify spinner behavior
Jun 2, 2023
4c8831d
increase bin number
Jun 5, 2023
ac9429e
update css
Jun 5, 2023
8a010da
remove unused functions
Jun 5, 2023
2a7ef46
Merge branch 'filter_panel_refactor@main' into 234_range_selector@fil…
Jun 5, 2023
61173bf
refine selection validation
Jun 5, 2023
c4ce362
remove more unused funcitons
Jun 5, 2023
4591054
adjust unit tests
Jun 5, 2023
d0d4d4e
Merge branch 'filter_panel_refactor@main' into 234_range_selector@fil…
gogonzo Jun 7, 2023
bb2628e
Merge d0d4d4eda91bf0eb55bbb1db13f7e07025891cb8 into dfd95a50be0c964d4…
chlebowa Jun 7, 2023
d098a31
[skip actions] Restyle files
github-actions[bot] Jun 7, 2023
d6f5fa4
fix double-click behavior
Jun 12, 2023
045f22b
simplify
Jun 12, 2023
f2e7e33
change content summary format
Jun 13, 2023
84b5242
update help link stylie
Jun 13, 2023
fc59f12
linter
Jun 13, 2023
e9347b4
clean up namespace
Jun 13, 2023
06fa62c
fix dependencies check
Jun 13, 2023
77b43bb
234 range selector modified by adding debounce and popover (#334)
kartikeyakirar Jun 13, 2023
8cf081d
Merge 77b43bb7168a4a009f59071c23289503a5bc25bd into 64a1ea083e980ea8c…
chlebowa Jun 13, 2023
9832277
[skip actions] Restyle files
github-actions[bot] Jun 13, 2023
b3b0214
Merge branch '234_range_selector@filter_panel_refactor@main' of githu…
Jun 13, 2023
f0dbd3a
linter
Jun 13, 2023
3e7bdf2
add logger to observer
Jun 13, 2023
c3e64e3
clean up
Jun 13, 2023
2d3e99d
Merge c3e64e3824415bb7f48283112a2c070847c661bb into 64a1ea083e980ea8c…
chlebowa Jun 13, 2023
c176ea0
[skip actions] Restyle files
github-actions[bot] Jun 13, 2023
885e377
fix NAMESPACE
Jun 13, 2023
b2f327f
add comment explaining .rectify_dependencies_check function
Jun 13, 2023
fedd0bf
modify step for manual selection
Jun 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@ Depends:
R (>= 4.0),
shiny
Imports:
bslib (>= 0.4.0),
checkmate,
dplyr,
ggplot2,
grDevices,
lifecycle,
logger (>= 0.2.0),
methods,
plotly,
R6,
rlang,
shinycssloaders,
shinyjs,
shinyWidgets (>= 0.5.0),
stats,
shinyWidgets (>= 0.6.2),
teal.data (>= 0.1.2.9011),
teal.logger (>= 0.1.1),
teal.widgets (>= 0.2.0)
Suggests:
bslib,
formatters (>= 0.3.1),
knitr,
MultiAssayExperiment,
Expand Down
10 changes: 0 additions & 10 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,4 @@ export(remove_filter_state)
export(set_filter_state)
import(R6)
import(shiny)
importFrom(dplyr,filter)
importFrom(ggplot2,ggplot)
importFrom(grDevices,rgb)
importFrom(lifecycle,badge)
importFrom(logger,log_trace)
importFrom(methods,is)
importFrom(shinyWidgets,pickerOptions)
importFrom(shinyjs,hide)
importFrom(stats,setNames)
importFrom(teal.data,dataset)
importFrom(teal.widgets,optionalSelectInput)
198 changes: 49 additions & 149 deletions R/FilterState-utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -536,163 +536,63 @@ check_in_subset <- function(subset, choices, pre_msg = "") {
return(invisible(NULL))
}

#' Find containing limits for interval.
#'
#' Given an interval and a numeric vector,
#' find the smallest interval within the numeric vector that contains the interval.
#'
#' This is a helper function for `RangeFilterState` that modifies slider selection
#' so that the _subsetting call_ includes the value specified by the filter API call.

#' Get hex code of the current Bootstrap theme color.
#'
#' Regardless of the underlying numeric data, the slider always presents 100 steps.
#' The ticks on the slider do not represent actual observations but rather borders between virtual bins.
#' Since the value selected on the slider is passed to `private$selected` and that in turn
#' updates the slider selection, programmatic selection of arbitrary values may inadvertently shift
#' the selection to the closest tick, thereby dropping the actual value set (if it exists in the data).
#' Determines the color specification for the currently active Bootstrap color theme and returns one queried color.
#'
#' This function purposely shifts the selection to the closest ticks whose values form an interval
#' that will contain the interval defined by the filter API call.
#' @param color `character(1)` naming one of the available theme colors
#' @param alpha either a `numeric(1)` or `character(1)` specifying transparency
#' in the range of `0-1` or a hexadecimal value `00-ff`, respectively;
#' set to NULL to omit adding the alpha channel
#'
#' @param x `numeric(2)` interval to contain
#' @param range `numeric(>=2)` vector of values to contain `x` in
#' @return Named `character(1)` containing a hexadecimal color representation.
#'
#' @return Numeric vector of length 2 that lies within `range`.
#' @examples
#' teal.slice:::fetch_bs_color("primary")
#' teal.slice:::fetch_bs_color("danger", 0.35)
#' teal.slice:::fetch_bs_color("danger", "80")
#'
#' @keywords internal
#'
#' @examples
#' \donttest{
#' ticks <- 1:10
#' values1 <- c(3, 5)
#' teal.slice:::contain_interval(values1, ticks)
#' values2 <- c(3.1, 5.7)
#' teal.slice:::contain_interval(values2, ticks)
#' values3 <- c(0, 20)
#' teal.slice:::contain_interval(values3, ticks)
#'}
contain_interval <- function(x, range) {
checkmate::assert_numeric(x, len = 2L, any.missing = FALSE, sorted = TRUE)
checkmate::assert_numeric(range, min.len = 2L, any.missing = FALSE, sorted = TRUE)

x[1] <- Find(function(i) i <= x[1], range, nomatch = min(range), right = TRUE)
x[2] <- Find(function(i) i >= x[2], range, nomatch = max(range))
x
}
fetch_bs_color <- function(color, alpha = NULL) {
checkmate::assert_string(color)
checkmate::assert(
checkmate::check_number(alpha, lower = 0, upper = 1, null.ok = TRUE),
checkmate::check_string(alpha, pattern = "[0-9a-f]{2}", null.ok = TRUE)
)

# locate file that describes the current theme
## TODO this is not ideal
sass_file <- bslib::bs_theme()[["layers"]][[2]][["defaults"]][[1]]
sass_file <- attr(sass_file, "sass_file_path")

#' Formats selected values of a RangeFilterState for display in the header summary.
#'
#' If a number has more significant digits than the threshhold, it will be
#' formatted in scientific notation. The resulting number will have 'threshold'
#' significant digits. If any `NA`s are present, they will be converted to the
#' character "NA". Similarly `Inf` and `-Inf` will be converted to the strings
#' "Inf" and "-Inf" respectively.
#'
#'
#' @param values Vector of values to format. Can contain `NA`, `Inf`, `-Inf`.
#' @param threshold Number of significant digits above which the number will be
#' formatted in scientific notation.
#'
#' @return Vector of `length(values)` as a string suitable for display.
#' @keywords internal
#' @noRd
format_range_for_summary <- function(values, threshold = 4) {
checkmate::assert_numeric(values, min.len = 1)
checkmate::assert_number(threshold, lower = 1, finite = TRUE)

ops <- options(scipen = 9999)
on.exit(options(ops))

# convert to a string representation
values_str <- vapply(
values,
FUN.VALUE = character(1),
USE.NAMES = FALSE,
FUN = function(value) {
if (is.na(value) || is.finite(value)) {
format(value)
} else {
as.character(value)
}
})

n_digits <- n_sig_digits(values_str)

mapply(
values_str,
n_digits,
USE.NAMES = FALSE,
MoreArgs = list(threshold = threshold),
FUN = function(value, digits, threshold) {
if (digits == -1) { # special case for Inf, -Inf, NA
value
} else if (digits > threshold) {
val <- format(as.numeric(value), digits = threshold, scientific = TRUE)
val <- sub("e", "E", val)
val
} else {
value
}
}
)
}
# load scss file that encodes variables
variables_file <- readLines(sass_file)
# locate theme color variables
ind <- grep("// scss-docs-(start|end) theme-color-variables", variables_file)
color_definitions <- variables_file[(ind[1] + 1L):(ind[2] - 1L)]

#' Count the number of significant digits in a number.
#'
#' Adapted from https://www.r-bloggers.com/2010/04/significant-figures-in-r-and-info-zeros/
#' The supplied vector should be numbers represented as a character. `NA`, `Inf`,
#' and `-Inf` should be coded as the strings "NA", "Inf", and "-Inf". In these
#' cases, a count of -1 is returned.
#'
#' @param nums A vector of numbers that have been converted to character.
#'
#' @return Vector of `length(nums)` with counts of significant digits.
#' @keywords internal
#' @noRd
n_sig_digits <- function(nums) {
checkmate::assert_character(nums, any.missing = FALSE)

vapply(nums, FUN.VALUE = numeric(1), USE.NAMES = FALSE, FUN = function(num) {

if (grepl("e", num)) return(-1)
if (num == "NA") return(-1)
if (num == "Inf" || num == "-Inf") return(-1)

sig_digits <- 1
i <- 0

if (grepl("\\.", num)) {

num_split <- unlist(strsplit(num, "\\."))
num_str <- paste(num_split[1], num_split[2], sep = "")
current_n_digits <- nchar(num_str)

while (i < current_n_digits) {

if (substr(num_str, i + 1, i + 1) == "0") {
i <- i + 1
next
} else {
sig_digits <- current_n_digits - i
break
}
}
} else {

num_str <- num
current_n_digits <- nchar(num_str)

while (i < current_n_digits) {
if (substr(num_str, current_n_digits - i, current_n_digits - i) == "0") {
i <- i + 1
next
} else {
sig_digits <- current_n_digits - i
break
}
}
}

return(sig_digits)
})
# extract colors names
color_names <- sub("(\\$)(\\w.+)(:.+)", "\\2", color_definitions)

# verify that an available color was requested
checkmate::assert_choice(color, color_names)

# extract color references
color_references <- sub("(\\$)(\\w.+)(:\\s.+\\$)(\\w.+)(\\s.+)", "\\4", color_definitions)

# translate references to color codes
color_specification <- structure(color_references, names = color_names)
color_specification <- vapply(color_specification, function(x) {
line <- grep(sprintf("^\\$%s:\\s+#\\w{6}\\s+!default", x), variables_file, value = TRUE)
code <- sub("(.+)(#\\w{6})(\\s+.+)", "\\2", line)
code
}, character(1L))

if (!is.null(alpha)) {
if (is.numeric(alpha)) alpha <- as.hexmode(ceiling(255 * alpha))
}

paste0(color_specification[color], alpha)
}
Loading