Skip to content
This repository was archived by the owner on Jun 9, 2023. It is now read-only.

Commit 57bf0d3

Browse files
committed
v 9.1.0
1 parent 4a01d5e commit 57bf0d3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1869
-3280
lines changed

DESCRIPTION

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ Maintainer: Matt Piekenbrock <[email protected]>
99
Description: An efficient implementation of the Mapper algorithm, and other related algorithms and tools used in Topological Data Analysis.
1010
Imports: R6, Rcpp, stats, methods
1111
LinkingTo: Rcpp, simplextree
12-
RcppModules: segment_tree_module, union_find_module
1312
License: file LICENSE
1413
BugReports: https://github.com/peekxc/mapper
1514
Suggests:

NAMESPACE

-6
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ export(AdaptiveCover)
77
export(BallCover)
88
export(CoverRef)
99
export(FixedIntervalCover)
10-
export(MapperDataInput)
11-
export(MapperFilterInput)
1210
export(MapperRef)
13-
export(MapperVis)
1411
export(RestrainedIntervalCover)
1512
export(SubspaceCover)
1613
export(bin_color)
@@ -21,14 +18,11 @@ export(gromov_hausdorff)
2118
export(hausdorff_distance)
2219
export(landmarks)
2320
export(mapper)
24-
export(multiscale)
2521
export(segment_tree)
26-
export(thd)
2722
export(union_find)
2823
import(Rcpp)
2924
import(methods)
3025
import(modules)
31-
import(shiny)
3226
import(simplextree)
3327
importFrom(Rcpp,Module)
3428
importFrom(Rcpp,cpp_object_initializer)

NEWS.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11

2+
# Mapper 0.9.1
3+
- Moved filter aspect from cover to MapperRef class, added 9 popular filter functions and a 'use_filter' API
4+
- Nerve computation can now construct arbitrary dimensional simplicial complexes
5+
- Removed grapher visualization method, added pixiplex as a replacement
6+
27
# Mapper 0.9.0
38
- Added many API-breaking changes, including:
4-
- (1) Changed field name 'ls_vertex_map' to pullback
9+
- (1) Changed field name 'ls\_vertex\_map' to pullback to match theory more correctly
510
- (2) Changed name of 'rectangular'-type covers to 'interval'
611
- (3) Added ability to construct individual subsets of the cover via 'pullback' method
712
- Added first vignette describing application of Mapper for Shape Comparison

R/CoverRef.R

+7-18
Original file line numberDiff line numberDiff line change
@@ -14,47 +14,36 @@
1414
#' \itemize{
1515
#' \item{\emph{.level_sets}}{ named list, indexed by \code{.index_set}, whose values represent indices in the original data set to cluster over.}
1616
#' \item{\emph{.index_set}}{ character vector of keys that uniquely index the level sets.}
17-
#' \item{\emph{.filter_dim}}{ constant representing the filter dimension.}
18-
#' \item{\emph{.filter_size}}{ constant representing the number of points in the filter space.}
1917
#' \item{\emph{.typename}}{ unique string identifier of the covering method.}
2018
#' }
21-
#'
2219
#'
2320
#' @docType class
24-
#' @field filter_values (n x d) matrix of filter values
2521
#' @field typename Unique string identifier for the covering.
2622
#' @field index_set character vector used to index the 'level_sets' list
27-
#' @field level_sets list of the
23+
#' @field level_sets list of the point in the preimages of the sets comprising the cover, indexed by the index set
2824
#' @format An \code{\link{R6Class}} generator object
2925
#'
3026
#' @method level_sets_to_compare testing
3127
#'
3228
#' @author Matt Piekenbrock
3329
#' @export CoverRef
3430
CoverRef <- R6::R6Class("CoverRef",
35-
public = list(filter_values=NA),
3631
private = list(
3732
.level_sets = NA,
38-
.index_set = NA,
39-
.filter_size = NA,
40-
.filter_dim = NA,
33+
.index_set = NA,
4134
.typename = character(0)
4235
),
4336
lock_class = FALSE, ## Feel free to add your own members
4437
lock_objects = FALSE ## Or change existing ones
4538
)
4639

4740
## Cover initialization
48-
CoverRef$set("public", "initialize", function(filter_values, typename){
49-
if (is.null(dim(filter_values))) { filter_values <- array(filter_values, dim = c(length(filter_values), 1)) }
50-
self$filter_values <- filter_values
51-
private$.filter_size <- dim(filter_values)[[1]]
52-
private$.filter_dim <- dim(filter_values)[[2]]
41+
CoverRef$set("public", "initialize", function(typename){
5342
private$.typename <- typename
5443
})
5544

5645
CoverRef$set("public", "format", function(...){
57-
message <- c(sprintf("Open cover for %d objects (d = %d)", nrow(self$filter_values), private$.filter_dim))
46+
# message <- c(sprintf("Open cover for %d objects (d = %d)", nrow(self$filter_values), private$.filter_dim))
5847
return(message)
5948
})
6049

@@ -124,9 +113,9 @@ CoverRef$set("public", "validate", function(){
124113
stop("Cover invalid: Not all the level sets have a corresponding index in the index set.")
125114
}
126115
idx <- unique(unlist(private$.level_sets))
127-
if ( length(idx) != private$.filter_size ){
128-
stop("Cover invalid: Not all point indices account for in the open sets!")
129-
}
116+
# if ( length(idx) != private$.filter_size ){
117+
# stop("Cover invalid: Not all point indices account for in the open sets!")
118+
# }
130119
})
131120

132121
# TODO

R/FixedIntervalCover.R

+51-25
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,20 @@ FixedIntervalCover <- R6::R6Class("FixedIntervalCover",
2020
)
2121

2222
#' @export
23-
FixedIntervalCover$set("public", "initialize", function(filter_values, ...){
24-
super$initialize(filter_values, typename="Fixed Interval")
23+
FixedIntervalCover$set("public", "initialize", function(...){
24+
super$initialize(typename="Fixed Interval")
2525
params <- list(...)
2626
if ("number_intervals" %in% names(params)){ self$number_intervals <- params[["number_intervals"]] }
2727
if ("percent_overlap" %in% names(params)){ self$percent_overlap <- params[["percent_overlap"]] }
2828
})
2929

3030
## Set overlap/gain threshold
31+
## percent_overlap ----
3132
FixedIntervalCover$set("active", "percent_overlap",
3233
function(value){
3334
if (missing(value)){ private$.percent_overlap }
3435
else {
3536
if (any(value < 0) || any(value >= 100)){ stop("The percent overlap must be a percentage between [0, 100).") }
36-
if (length(value) != private$.filter_dim && length(value) != 1){ stop("The percent overlap must be a single scalar or a vector of scalars with length equal to the dimensionality of the filter space.") }
37-
if (length(value) == 1 && private$.filter_dim > 1){ value <- rep(value, private$.filter_dim) } ## create a vector
3837
private$.percent_overlap <- value
3938
self
4039
}
@@ -44,19 +43,36 @@ FixedIntervalCover$set("active", "percent_overlap",
4443
## Active binding to set the number of intervals to distribute along each dimension.
4544
## By default, if a scalar is given and the filter dimensionality is > 1, the scalar is
4645
## repeated along each dimension.
46+
## number_intervals ----
4747
FixedIntervalCover$set("active", "number_intervals",
4848
function(value){
4949
if (missing(value)){ private$.number_intervals }
5050
else {
51-
if (length(value) == 1 && private$.filter_dim > 1){ value <- rep(value, private$.filter_dim) } ## create a vector
5251
stopifnot(all(value > 0))
53-
stopifnot(length(value) == private$.filter_dim)
5452
private$.number_intervals <- value
5553
self
5654
}
5755
}
5856
)
5957

58+
## Validates the parameter settings
59+
## validate ----
60+
FixedIntervalCover$set("public", "validate", function(filter){
61+
stopifnot(!is.na(private$.percent_overlap))
62+
stopifnot(!is.na(private$.number_intervals))
63+
stopifnot(all(self$number_intervals > 0))
64+
stopifnot(all(self$percent_overlap >= 0), all(self$percent_overlap < 100))
65+
fv <- filter()
66+
f_dim <- ncol(fv)
67+
if (length(self$number_intervals) == 1 && f_dim > 1){
68+
self$number_intervals <- rep(self$number_intervals[1], f_dim)
69+
}
70+
if (length(self$percent_overlap) == 1 && f_dim > 1){
71+
self$percent_overlap <- rep(self$percent_overlap[1], f_dim)
72+
}
73+
})
74+
75+
## format ----
6076
FixedIntervalCover$set("public", "format", function(...){
6177
# type_pretty <- paste0(toupper(substr(self$typename, start = 1, stop = 1)), tolower(substr(self$typename, start = 2, stop = nchar(self$typename))))
6278
sprintf("Cover: (typename = %s, number intervals = [%s], percent overlap = [%s]%%)",
@@ -66,12 +82,13 @@ FixedIntervalCover$set("public", "format", function(...){
6682
})
6783

6884
## This function is specific to the interval-type covers
69-
FixedIntervalCover$set("public", "interval_bounds", function(index=NULL){
70-
stopifnot(!is.na(private$.percent_overlap))
71-
stopifnot(!is.na(private$.number_intervals))
72-
85+
## interval_bounds ----
86+
FixedIntervalCover$set("public", "interval_bounds", function(filter, index=NULL){
87+
self$validate(filter)
88+
7389
## Get filter min and max ranges
74-
filter_rng <- apply(self$filter_values, 2, range)
90+
fv <- filter()
91+
filter_rng <- apply(fv, 2, range)
7592
{ filter_min <- filter_rng[1,]; filter_max <- filter_rng[2,] }
7693
filter_len <- diff(filter_rng)
7794

@@ -98,15 +115,20 @@ FixedIntervalCover$set("public", "interval_bounds", function(index=NULL){
98115
})
99116

100117
## Setup a valid index set (via cartesian product)
118+
## construct_index_set ----
101119
FixedIntervalCover$set("public", "construct_index_set", function(...){
102120
cart_prod <- arrayInd(seq(prod(self$number_intervals)), .dim = self$number_intervals)
103121
self$index_set <- apply(cart_prod, 1, function(x){ sprintf("(%s)", paste0(x, collapse = " ")) })
104122
})
105123

106124
## Given the current set of parameter values, construct the level sets whose union covers the filter space
107-
FixedIntervalCover$set("public", "construct_cover", function(index=NULL){
108-
stopifnot(!is.na(private$.percent_overlap))
109-
stopifnot(!is.na(private$.number_intervals))
125+
## construct_cover ----
126+
FixedIntervalCover$set("public", "construct_cover", function(filter, index=NULL){
127+
self$validate(filter)
128+
129+
## Get filter values
130+
fv <- filter()
131+
f_dim <- ncol(fv)
110132

111133
## If the index set hasn't been made yet, construct it.
112134
if (any(is.na(self$index_set))){ self$construct_index_set() }
@@ -115,34 +137,36 @@ FixedIntervalCover$set("public", "construct_cover", function(index=NULL){
115137
## If no index specified, return the level sets either by construction
116138
if (missing(index) || is.null(index)){
117139
stopifnot(!index %in% self$index_set)
118-
set_bnds <- self$interval_bounds()
119-
self$level_sets <- constructIsoAlignedLevelSets(self$filter_values, as.matrix(set_bnds))
140+
set_bnds <- self$interval_bounds(filter)
141+
self$level_sets <- constructIsoAlignedLevelSets(fv, as.matrix(set_bnds))
120142
return(invisible(self)) ## return invisibly
121143
} else {
122144
if (!is.na(self$level_sets) && index %in% names(self$level_sets)){
123145
return(self$level_sets[[index]])
124146
} else {
125147
p_idx <- which(index == self$index_set)
126-
set_bnds <- self$interval_bounds(index)
127-
level_set <- constructIsoAlignedLevelSets(self$filter_values, set_bnds)
148+
set_bnds <- self$interval_bounds(filter, index)
149+
level_set <- constructIsoAlignedLevelSets(fv, set_bnds)
128150
return(level_set)
129151
}
130152
}
131153
})
132154

133155
## Constructs a 'neighborhood', which is an (n x k+1) subset of pullback ids representing
134156
## the set of n unique (k+1)-fold intersections are required to construct the nerve.
135-
FixedIntervalCover$set("public", "neighborhood", function(k){
157+
## neighborhood ----
158+
FixedIntervalCover$set("public", "neighborhood", function(filter, k){
136159
stopifnot(!is.na(private$.index_set))
160+
fv <- filter()
137161
if (k == 1){
138162
all_pairs <- t(combn(1L:length(private$.index_set), 2))
139163
multi_index <- arrayInd(seq(prod(self$number_intervals)), .dim = self$number_intervals)
140164

141165
## Get filter min and max ranges
142-
filter_rng <- apply(self$filter_values, 2, range)
166+
filter_rng <- apply(fv, 2, range)
143167
{ filter_min <- filter_rng[1,]; filter_max <- filter_rng[2,] }
144168
filter_len <- diff(filter_rng)
145-
d_rng <- 1:ncol(self$filter_values)
169+
d_rng <- 1:ncol(fv)
146170

147171
## Compute the critical distances that determine which pairwise combinations to compare
148172
base_interval_length <- filter_len/self$number_intervals
@@ -169,9 +193,10 @@ FixedIntervalCover$set("public", "neighborhood", function(k){
169193
})
170194

171195
## Converts percent overlap to interval length for a fixed number of intervals
172-
FixedIntervalCover$set("public", "overlap_to_interval_len", function(percent_overlap){
196+
FixedIntervalCover$set("public", "overlap_to_interval_len", function(filter, percent_overlap){
173197
stopifnot(all(is.numeric(self$number_intervals)))
174-
filter_rng <- apply(self$filter_values, 2, range)
198+
fv <- filter()
199+
filter_rng <- apply(fv, 2, range)
175200
{ filter_min <- filter_rng[1,]; filter_max <- filter_rng[2,] }
176201
filter_len <- diff(filter_rng)
177202
base_interval_length <- filter_len/self$number_intervals
@@ -180,9 +205,10 @@ FixedIntervalCover$set("public", "overlap_to_interval_len", function(percent_ove
180205
})
181206

182207
## Converts interval length to percent overlap for a fixed number of intervals
183-
FixedIntervalCover$set("public", "interval_len_to_percent_overlap", function(interval_len){
208+
FixedIntervalCover$set("public", "interval_len_to_percent_overlap", function(filter, interval_len){
184209
stopifnot(all(is.numeric(self$number_intervals)))
185-
filter_rng <- apply(self$filter_values, 2, range)
210+
fv <- filter()
211+
filter_rng <- apply(fv, 2, range)
186212
{ filter_min <- filter_rng[1,]; filter_max <- filter_rng[2,] }
187213
filter_len <- diff(filter_rng)
188214
base_interval_length <- filter_len/self$number_intervals

R/Mapper-package.r

+5-9
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,7 @@
1010
#' @docType package
1111
NULL
1212

13-
#' MapperVis
14-
#' @description 'MapperVis' is a \code{\link[modules]{module}} containing \code{\link[shiny::callModule]{shiny modules}}
15-
#' that simplify making shiny applications with Mapper.
16-
#' @import modules
17-
#' @export
18-
MapperVis <- modules::use(file.path("R", "shiny_modules.R"))
13+
# <- modules::use(file.path("R", "shiny_modules.R"))
1914

2015
#' bin_color
2116
#' @param x A numeric vector whose magnitudes should be binned onto the color palette.
@@ -25,13 +20,14 @@ MapperVis <- modules::use(file.path("R", "shiny_modules.R"))
2520
#' @details Given a numeric vector \code{x}, bins the values from low to high on a given color gradient.
2621
#' Defaults to the reversed rainbow gradient, where blue == low, red == high.
2722
#' @export
28-
bin_color <- function(x, col_pal = "rainbow",
29-
output_format = c("hex9", "hex7")){
23+
bin_color <- function(x, col_pal = "rainbow", output_format = c("hex9", "hex7")){
3024
if (missing(col_pal) || col_pal == "rainbow"){ col_pal <- rev(grDevices::rainbow(100L, start = 0, end = 4/6)) }
3125
col_res <- length(col_pal)
3226
binned_idx <- cut(x, breaks = col_res, labels = FALSE)
3327
binned_colors <- col_pal[binned_idx]
3428
if (missing(output_format) || output_format == "hex9"){ return(binned_colors) }
3529
else if (output_format == "hex7"){ return(substr(binned_colors, start = 0L, stop = 7L)) }
3630
else { stop("'output_format' must be one of 'hex9' or 'hex7'.") }
37-
}
31+
}
32+
33+
.filters_available <- c("PC", "IC", "ECC", "KDE", "DTM", "MDS", "ISOMAP", "LE", "UMAP")

0 commit comments

Comments
 (0)