From 3d780611414e065f3c1a6c234ebb718e426d67cd Mon Sep 17 00:00:00 2001 From: Samuel Gratzl Date: Sat, 13 Feb 2021 21:33:22 +0100 Subject: [PATCH] refactor: recursive generation --- r_package/R/data-helpers.R | 126 ++++++++++++++++++++++++------------- r_package/R/data.R | 9 ++- 2 files changed, 90 insertions(+), 45 deletions(-) diff --git a/r_package/R/data-helpers.R b/r_package/R/data-helpers.R index b69dd92..0481fd9 100644 --- a/r_package/R/data-helpers.R +++ b/r_package/R/data-helpers.R @@ -71,61 +71,103 @@ generateCombinationsImpl = function(sets, symbol = "&", store.elems = TRUE) { combinations = list() - set_f = if (c_type == "union") - union - else - intersect distinct = (c_type == 'distinctIntersection') - lsets = length(sets) - all_indices = 1:lsets cc = colorLookup(colors) - max_sets = ifelse(is.null(max), lsets, max) - - for (l in min:max_sets) { - combos = combn(all_indices, l, simplify = FALSE) - for (combo in combos) { - indices = unlist(combo) - set_names = sapply(indices, function(i) - sets[[i]]$name) - if (is.list(set_names)) { - set_names = unlist(set_names) - } - if (length(indices) == 0) { - elems = c() - } else { - elems = sets[[indices[1]]]$elems - for (index in indices) { - elems = set_f(elems, sets[[index]]$elems) + + mergeUnion = function(a, b) { + ab_sets = sort(union(a$setNames, b$setNames)) + ab_name = paste(ab_sets, collapse = symbol) + ab_elems = c() + if (a$cardinality == 0) { + ab_elems = b$elems + } else if (b$cardinality == 0) { + ab_elems = a$elems + } else { + ab_elems = union(a$elems, b$elems) + } + asCombination(ab_name, ab_elems, 'union', ab_sets, color=cc(ab_name)) + } + + mergeIntersect = function(a, b) { + ab_sets = sort(union(a$setNames, b$setNames)) + ab_name = paste(ab_sets, collapse = symbol) + ab_elems = c() + if (a$cardinality > 0 && b$cardinality > 0) { + ab_elems = intersect(a$elems, b$elems) + } + asCombination(ab_name, ab_elems, 'intersect', ab_sets, color=cc(ab_name)) + } + + calc = ifelse(c_type == "union", mergeUnion, mergeIntersect) + + push_combination = function(s) { + if (s$degree < min || (!is.null(max) && s$degree > max) || (s$cardinality == 0 && !empty)) { + return() + } + if (!distinct || s$degree == 1) { + combinations <<- c(combinations, list(s)) + return() + } + otherSets = Filter(function(ss) { + !(ss$name %in% s$setNames) + }, sets) + dElems = Filter(function(e) { + for(o in otherSets) { + if (e %in% o$elems) { + return(FALSE) } } - if (distinct) { - not_indices = setdiff(all_indices, indices) - for (index in not_indices) { - elems = setdiff(elems, sets[[index]]$elems) + TRUE + }, s$elems) + + if (s$cardinality == length(dElems)) { + combinations <<- c(combinations, list(s)) + return() + } + + sDistinct = asCombination(s$name, dElems, 'distinctIntersection', s$setNames, color=s$color) + if (sDistinct$cardinality > 0 || empty) { + combinations <<- c(combinations, list(sDistinct)) + } + } + + generateLevel = function(arr, degree) { + if (!is.null(max) && degree > max) { + return() + } + l = length(arr) + for(i in 1:l) { + a = arr[[i]] + sub = list() + if (i < l) { + for(j in (i+1):l) { + b = arr[[j]] + ab = calc(a,b) + push_combination(ab) + if (c_type == 'union' || ab$cardinality > 0 || empty) { + sub[[length(sub) + 1]] = ab + } } } - if (empty || length(elems) > 0) { - c_name = paste(set_names, collapse = symbol) - combination = structure( - list( - name = c_name, - color = cc(c_name), - type = c_type, - elems = ifelse(store.elems, elems, c()), - cardinality = length(elems), - setNames = set_names - ), - class = "upsetjs_combination" - ) - combinations = c(combinations, list(combination)) + if (length(sub) > 1) { + generateLevel(sub, degree + 1) } } } + + degree1 = lapply(1:length(sets), function(i) { + s = sets[[i]] + s_c = asCombination(s$name, s$elems, c_type, c(s$name), s$cardinality, s$color) + push_combination(s_c) + s_c + }) + generateLevel(degree1, 2) + names(combinations) = NULL sortSets(combinations, order.by, limit) } -extractCombinationsImpl = function(df, +extractCombinationsImpl = function(df, sets, empty, order.by, diff --git a/r_package/R/data.R b/r_package/R/data.R index 45bdf52..e4c548b 100644 --- a/r_package/R/data.R +++ b/r_package/R/data.R @@ -37,7 +37,7 @@ asSet = function(name, elems = c(), cardinality = length(elems), color = NULL) { #' @param color the color of the set #' @return the set object #' @examples -#' asSet('a', c(1,2,3)) +#' asCombination('a', c(1,2,3)) #' #' @export asCombination = function(name, elems = c(), type = 'intersection', sets = strsplit(name, '&'), cardinality = length(elems), color = NULL) { @@ -48,7 +48,8 @@ asCombination = function(name, elems = c(), type = 'intersection', sets = strspl elems = elems, color = color, cardinality = cardinality, - setNames = sets + setNames = sets, + degree = length(sets) ), class = "upsetjs_combination" ) @@ -262,9 +263,11 @@ extractSetsFromDataFrame = function(df, cc = colorLookup(colors) elems = rownames(df) + toSet = function(key) { sub = elems[df[[key]] == TRUE] - asSet(key, ifelse(store.elems, sub, c()), cardinality=length(sub), color=cc(key)) + x = if(store.elems) sub else c() + asSet(key, x, cardinality=length(sub), color=cc(key)) } set_names = setdiff(colnames(df), if (is.character(attributes))