diff --git a/.Rbuildignore b/.Rbuildignore index 5fae00b..24f02dc 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -3,3 +3,4 @@ LICENSE.md _pkgdown.yml ^\.github$ +.lintr diff --git a/.lintr b/.lintr new file mode 100644 index 0000000..84cecc3 --- /dev/null +++ b/.lintr @@ -0,0 +1,7 @@ +linters: linters_with_defaults( + line_length_linter(250), + commented_code_linter = NULL, + trailing_whitespace_linter(allow_empty_lines = TRUE), + object_name_linter = NULL + ) +encoding: "UTF-8" diff --git a/R/build_Lifemap.R b/R/build_Lifemap.R index 576ea02..73b9645 100644 --- a/R/build_Lifemap.R +++ b/R/build_Lifemap.R @@ -4,7 +4,7 @@ #' The dataframe can contain any number of additional columns defining traits/characters/values associated to #' each taxid. #' @param basemap The chosen basemap for Lifemap ("fr", "ncbi", "base" or "virus"). -#' @param verbose If TRUE (the default), the function will print detailed information to the console. +#' @param verbose If TRUE (the default), the function will print detailed information to the console. #' If FALSE, it will run silently. #' #' @return A list of class lifemap_obj containing: @@ -16,7 +16,7 @@ #' - A list of its ascendants (ascend) #' - Its type ("requested" or "ancestor") #' - Its direct ancestor -#' - Its type (type), i.e. whether the taxid was +#' - Its type (type), i.e. whether the taxid was #' requested by the user ("requested") or if it is the anecestor of a requested taxid ("ancestor") #' - basemap : the basemap used to get taxa's details #' @@ -34,16 +34,16 @@ #' LM <- build_Lifemap(eukaryotes_80, "fr") #' } build_Lifemap <- function(df, basemap = c("ncbi", "base", "fr", "virus"), verbose = TRUE) { - + basemap <- match.arg(arg = basemap, choices = basemap) if (is.null(df$taxid)) { stop('The dataframe must at least contain a "taxid" column') } # create a new "environment" to store the full data - if (!exists("lifemap_basemap_envir", where = .GlobalEnv)) { + if (!exists("lifemap_basemap_envir", where = .GlobalEnv)) { lifemap_basemap_envir <- new.env() } - + ## SET DATASETS ASDRESSES # getting the right URL depending on the basemap wanted if (basemap == "ncbi") { @@ -59,7 +59,7 @@ build_Lifemap <- function(df, basemap = c("ncbi", "base", "fr", "virus"), verbos else { stop(sprintf('%s is not a working basemap, try c("base", "fr", "ncbi" or "virus")', basemap)) } - + y <- tryCatch({ load(url(basemap_url), envir = lifemap_basemap_envir) }, @@ -72,61 +72,61 @@ build_Lifemap <- function(df, basemap = c("ncbi", "base", "fr", "virus"), verbos return(NA) } ) - + if (!is.na(y)) { # download full data for chosen basemap if (verbose) { cat("Downloading basemap coordinates...\n") } load(url(basemap_url), envir = lifemap_basemap_envir) - + # add LUCA LUCA <- data.frame("taxid" = 0, "lon" = 0, "lat" = -4.226497, "sci_name" = "Luca", "zoom" = 5) lifemap_basemap_envir$DF <- dplyr::bind_rows(lifemap_basemap_envir$DF, LUCA) - + # get info for unique taxids (then we work with df_distinct, not df anymore) df_distinct <- dplyr::distinct(df, .data$taxid, .keep_all = TRUE) if (nrow(df_distinct) != nrow(df)) { - warning(sprintf("%s duplicated TaxIDs were removed \n", nrow(df) - nrow(df_distinct))) + warning(sprintf("%s duplicated TaxIDs were removed \n", nrow(df) - nrow(df_distinct))) } - + # get data if (verbose) { cat("Getting info for requested taxids...\n") } - + # get index of requested taxids indexes <- fastmatch::fmatch(df_distinct$taxid, lifemap_basemap_envir$DF$taxid) if (sum(is.na(indexes)) > 0) { - warning(sprintf("%s TaxID(s) could not be found: %s \n", - sum(is.na(indexes)), - paste(df_distinct$taxid[is.na(indexes)], sep = ","))) + warning(sprintf("%s TaxID(s) could not be found: %s \n", + sum(is.na(indexes)), + paste(df_distinct$taxid[is.na(indexes)], sep = ","))) } - + # create new df with only existing taxids df_exists <- df_distinct[!is.na(indexes), ] DATA0 <- lifemap_basemap_envir$DF[indexes[!is.na(indexes)], ] - + # get ancestors unique_ancestors <- unique(unlist(DATA0$ascend)) real_ancestors <- setdiff(unique_ancestors, df_exists$taxid) ANCESTORS <- lifemap_basemap_envir$DF[fastmatch::fmatch(real_ancestors, lifemap_basemap_envir$DF$taxid), ] - + # add type DATA0$type <- "requested" ANCESTORS$type <- "ancestor" # bind all DATA1 <- rbind(DATA0, ANCESTORS) - - # merge + + # merge DATA2 <- merge(DATA1, df_exists, by = "taxid", all = TRUE) - + # replace the column 'ascend' by simply the direct ancestor DATA2$ancestor <- unlist(lapply(DATA2$ascend, function(x) ifelse(!is.null(x), x[1], NA))) - + lm_obj <- list(df = DATA2, basemap = basemap) class(lm_obj) <- c("lifemap_obj", "list") - + return(lm_obj) } else { return(NA) diff --git a/R/create_matrix.R b/R/create_matrix.R index 50d05f6..3e81a72 100644 --- a/R/create_matrix.R +++ b/R/create_matrix.R @@ -15,10 +15,10 @@ #' #' create_matrix(LM_eukaryotes$df, c("GC.", "Genes")) create_matrix <- function(df, cols) { - a <- sapply(1:nrow(df), - function(x,y) { + a <- sapply(seq_len(nrow(df)), + function(x, y) { cbind(y$taxid[x], c(y$taxid[x], y$ascend[x][[1]])) - }, + }, y = df) a <- a[-length(a)] B <- do.call(rbind, a) @@ -30,7 +30,7 @@ create_matrix <- function(df, cols) { new_df <- dplyr::full_join(new_df, df[, c("taxid", var)], by = dplyr::join_by("descendant" == "taxid")) } } - return (new_df) + return(new_df) } #' Infer numerical values to nodes. @@ -49,9 +49,10 @@ create_matrix <- function(df, cols) { #' #' inferred_values <- pass_infos(M = infos, FUN = mean, value = "GC.") pass_infos <- function(M, FUN, value) { - inferred_values <- tapply(M[[value]], M$ancestor, function(x) { + iv <- tapply(M[[value]], M$ancestor, function(x) { x <- x[!is.na(x)] FUN(x)}) + return(iv) } @@ -74,15 +75,15 @@ pass_infos <- function(M, FUN, value) { #' #' inferred_values <- pass_infos_discret(M = infos, value = "Status") pass_infos_discret <- function(M, value) { - bind_values <- M |> + bind_values <- M |> dplyr::select(.data$ancestor, dplyr::all_of(value)) |> stats::na.omit() |> dplyr::group_by(.data[[value]], .data$ancestor) |> - dplyr::count() |> + dplyr::count() |> tidyr::pivot_wider(names_from = dplyr::all_of(value), values_from = .data$n, values_fill = 0) |> as.data.frame() |> - dplyr::rename("taxid" = "ancestor") |> + dplyr::rename("taxid" = "ancestor") |> dplyr::arrange(.data$taxid) - + return(bind_values) } diff --git a/R/display_map.R b/R/display_map.R index 32ca94c..c38c366 100644 --- a/R/display_map.R +++ b/R/display_map.R @@ -19,17 +19,16 @@ #' display_map() display_map <- function(df = NULL, basemap = c("fr", "ncbi", "base", "virus")) { basemap <- match.arg(basemap) - if (basemap == "fr"){ + if (basemap == "fr") { display <- "http://lifemap-fr.univ-lyon1.fr/osm_tiles/{z}/{x}/{y}.png" - } else if (basemap == "ncbi"){ + } else if (basemap == "ncbi") { display <- "http://lifemap-ncbi.univ-lyon1.fr/osm_tiles/{z}/{x}/{y}.png" - } else if (basemap == "base"){ + } else if (basemap == "base") { display <- "http://lifemap.univ-lyon1.fr/osm_tiles/{z}/{x}/{y}.png" - } else if (basemap == "virus"){ + } else if (basemap == "virus") { display <- "https://virusmap.univ-lyon1.fr/osm_tiles/{z}/{x}/{y}.png" } - url2check <- strsplit(display, "osm_tiles")[[1]][1] - + m <- tryCatch({ leaflet::leaflet(df) |> leaflet::addTiles(display, options = leaflet::providerTileOptions(minZoom = 5, maxZoom = 50)) @@ -43,7 +42,7 @@ display_map <- function(df = NULL, basemap = c("fr", "ncbi", "base", "virus")) { return(NA) } ) - + if (!all(is.na(m))) { return(m) } else { diff --git a/R/draw_Lifemap.R b/R/draw_Lifemap.R index 72d196d..8e64eb8 100644 --- a/R/draw_Lifemap.R +++ b/R/draw_Lifemap.R @@ -9,16 +9,16 @@ #' #' @return A vector of values. create_value_range <- function(value, df, df2, min, max) { - if (value %in% colnames(df)) { - old_min <- min(df[[value]], na.rm = TRUE) - old_max <- max(df[[value]], na.rm = TRUE) - old_range <- old_max - old_min - new_range <- max - min - info <- (((df2[[value]] - old_min) * new_range) / old_range) + min - } else { - info <- value - } - return(info) + if (value %in% colnames(df)) { + old_min <- min(df[[value]], na.rm = TRUE) + old_max <- max(df[[value]], na.rm = TRUE) + old_range <- old_max - old_min + new_range <- max - min + info <- (((df2[[value]] - old_min) * new_range) / old_range) + min + } else { + info <- value + } + return(info) } @@ -34,77 +34,82 @@ create_value_range <- function(value, df, df2, min, max) { #' #' @return An updated map with the new layer added. add_lm_markers <- function(proxy, aes, df, df_visible, group_info) { - - if (!(aes$var_fillColor %in% "default")) { - if (is.numeric(df[[aes$var_fillColor]])) { - make_fillColor <- leaflet::colorNumeric(palette = aes$fillPalette, domain = df[[aes$var_fillColor]], reverse = TRUE) - fillColor_info <- make_fillColor(df_visible[[aes$var_fillColor]]) - } else { - make_fillColor <- leaflet::colorFactor(palette = aes$fillPalette, domain = df[[aes$var_fillColor]], reverse = TRUE) - fillColor_info <- make_fillColor(df_visible[[aes$var_fillColor]]) - } - } else { - fillColor_info <- aes$fillColor} - - if (aes$radius %in% "default") { - radius_info <- create_value_range(aes$value, df, df_visible, aes$min, aes$max) - # radius_info <- aes$value + + if (!(aes$var_fillColor %in% "default")) { + if (is.numeric(df[[aes$var_fillColor]])) { + make_fillColor <- leaflet::colorNumeric(palette = aes$fillPalette, domain = df[[aes$var_fillColor]], reverse = TRUE) + fillColor_info <- make_fillColor(df_visible[[aes$var_fillColor]]) } else { - radius_info <- create_value_range(aes$radius, df, df_visible, aes$min, aes$max) + make_fillColor <- leaflet::colorFactor(palette = aes$fillPalette, domain = df[[aes$var_fillColor]], reverse = TRUE) + fillColor_info <- make_fillColor(df_visible[[aes$var_fillColor]]) } - - # stroke presence - if (isTRUE(aes$stroke)) { - if (!(aes$var_color %in% "default")) { - if (is.numeric(df[[aes$var_color]])){ - make_color <- leaflet::colorNumeric(aes$palette, df[[aes$var_color]], reverse = TRUE) - color_info <- make_color(df_visible[[aes$var_color]]) - } else { - make_color <- leaflet::colorFactor(palette = aes$palette, domain = df[[aes$var_color]], reverse = TRUE) - color_info <- make_color(df_visible[[aes$var_color]]) - } - } else { color_info <- aes$color } - } else {color_info <- aes$color} - - # stroke opacity - opacity_info <- create_value_range(aes$opacity, df, df_visible, 0.1, 1) - - # stroke weight - weight_info <- create_value_range(aes$weight, df, df_visible, 1, 10) - - # fill opacity - fillOpacity_info <- create_value_range(aes$fillOpacity, df, df_visible, 0.1, 1) - - ### to improve ### - if (is.null(aes$label)) { - proxy <- leaflet::addCircleMarkers(proxy, - lng = df_visible$lon, - lat = df_visible$lat, - radius = radius_info, - fillColor = fillColor_info, - fillOpacity = fillOpacity_info, - stroke = aes$stroke, - color = color_info, - opacity = opacity_info, - weight = weight_info, - group = group_info - ) - } else if (length(df_visible[[aes$label]]) > 0) { - proxy <- leaflet::addCircleMarkers(proxy, - lng = df_visible$lon, - lat = df_visible$lat, - radius = radius_info, - fillColor = fillColor_info, - fillOpacity = fillOpacity_info, - stroke = aes$stroke, - color = color_info, - opacity = opacity_info, - weight = weight_info, - group = group_info, - label = df_visible[[aes$label]] - ) + } else { + fillColor_info <- aes$fillColor + } + + if (aes$radius %in% "default") { + radius_info <- create_value_range(aes$value, df, df_visible, aes$min, aes$max) + # radius_info <- aes$value + } else { + radius_info <- create_value_range(aes$radius, df, df_visible, aes$min, aes$max) + } + + # stroke presence + if (isTRUE(aes$stroke)) { + if (!(aes$var_color %in% "default")) { + if (is.numeric(df[[aes$var_color]])) { + make_color <- leaflet::colorNumeric(aes$palette, df[[aes$var_color]], reverse = TRUE) + color_info <- make_color(df_visible[[aes$var_color]]) + } else { + make_color <- leaflet::colorFactor(palette = aes$palette, domain = df[[aes$var_color]], reverse = TRUE) + color_info <- make_color(df_visible[[aes$var_color]]) + } + } else { + color_info <- aes$color } - proxy + } else { + color_info <- aes$color + } + + # stroke opacity + opacity_info <- create_value_range(aes$opacity, df, df_visible, 0.1, 1) + + # stroke weight + weight_info <- create_value_range(aes$weight, df, df_visible, 1, 10) + + # fill opacity + fillOpacity_info <- create_value_range(aes$fillOpacity, df, df_visible, 0.1, 1) + + ### to improve ### + if (is.null(aes$label)) { + proxy <- leaflet::addCircleMarkers(proxy, + lng = df_visible$lon, + lat = df_visible$lat, + radius = radius_info, + fillColor = fillColor_info, + fillOpacity = fillOpacity_info, + stroke = aes$stroke, + color = color_info, + opacity = opacity_info, + weight = weight_info, + group = group_info + ) + } else if (length(df_visible[[aes$label]]) > 0) { + proxy <- leaflet::addCircleMarkers(proxy, + lng = df_visible$lon, + lat = df_visible$lat, + radius = radius_info, + fillColor = fillColor_info, + fillOpacity = fillOpacity_info, + stroke = aes$stroke, + color = color_info, + opacity = opacity_info, + weight = weight_info, + group = group_info, + label = df_visible[[aes$label]] + ) + } + proxy } #' Compute the aesthetics for a subtree visualisation. @@ -121,48 +126,52 @@ add_lm_markers <- function(proxy, aes, df, df_visible, group_info) { #' #' @return An updated map with the new layer added. add_lm_branches <- function(proxy, aes, df, df_visible, df_descendants, group_info, all_taxids) { - if (!(aes$var_color %in% "default")) { - make_col <- leaflet::colorNumeric(palette = aes$palette, domain = df[[aes$var_color]], reverse = TRUE) - } - - if (aes$size %in% colnames(df)) { - old_min <- min(df[[aes$size]], na.rm = TRUE) - old_max <- max(df[[aes$size]], na.rm = TRUE) - old_range <- old_max - old_min - new_range <- aes$max - aes$min - } - - if (!(is.null(aes$taxids))) { - descendants_visible <- df_descendants[df_descendants$taxid %in% all_taxids, ] - } else { descendants_visible = df_descendants } + if (!(aes$var_color %in% "default")) { + make_col <- leaflet::colorNumeric(palette = aes$palette, domain = df[[aes$var_color]], reverse = TRUE) + } + + if (aes$size %in% colnames(df)) { + old_min <- min(df[[aes$size]], na.rm = TRUE) + old_max <- max(df[[aes$size]], na.rm = TRUE) + old_range <- old_max - old_min + new_range <- aes$max - aes$min + } + + if (!(is.null(aes$taxids))) { + descendants_visible <- df_descendants[df_descendants$taxid %in% all_taxids, ] + } else { + descendants_visible <- df_descendants + } + + for (id in df_visible$taxid) { + # for each descendant of each taxid + + for (desc in descendants_visible[descendants_visible$ancestor == id, ]$taxid) { + if (!(aes$var_color %in% "default")) { + col_info <- make_col(descendants_visible[descendants_visible$taxid == desc, aes$var_color]) + } else { + col_info <- aes$color + } - for (id in df_visible$taxid) { - # for each descendant of each taxid - - for (desc in descendants_visible[descendants_visible$ancestor == id, ]$taxid) { - if (!(aes$var_color %in% "default")) { - col_info <- make_col(descendants_visible[descendants_visible$taxid == desc, aes$var_color]) - } else { - col_info <- aes$color - } - - if (aes$size %in% colnames(df)) { - size_info <- (((descendants_visible[descendants_visible$taxid == desc, aes$size] - old_min) * new_range) / old_range) + aes$min - } else {size_info <- aes$value} - - proxy <- leaflet::addPolylines(proxy, - lng = c(df_visible[df_visible$taxid == id, "lon"], - descendants_visible[descendants_visible$taxid == desc, "lon"]), - lat = c(df_visible[df_visible$taxid == id, "lat"], - descendants_visible[descendants_visible$taxid == desc, "lat"]), - color = col_info, - opacity = aes$opacity, - fillOpacity = 0.5, - group = group_info, - weight = size_info) - } + if (aes$size %in% colnames(df)) { + size_info <- (((descendants_visible[descendants_visible$taxid == desc, aes$size] - old_min) * new_range) / old_range) + aes$min + } else { + size_info <- aes$value + } + + proxy <- leaflet::addPolylines(proxy, + lng = c(df_visible[df_visible$taxid == id, "lon"], + descendants_visible[descendants_visible$taxid == desc, "lon"]), + lat = c(df_visible[df_visible$taxid == id, "lat"], + descendants_visible[descendants_visible$taxid == desc, "lat"]), + color = col_info, + opacity = aes$opacity, + fillOpacity = 0.5, + group = group_info, + weight = size_info) } - proxy + } + proxy } #' Compute the aesthetics for discret values visualisation. #' @@ -177,26 +186,26 @@ add_lm_branches <- function(proxy, aes, df, df_visible, df_descendants, group_in #' #' @return An updated map with the new layer added. add_lm_piecharts <- function(proxy, aes, df, df_visible, layer) { - values <- unique(df[df$type == "requested", aes$param]) - layerId_info <- sapply(X = 1:nrow(df_visible), FUN = function(x){paste(layer,x,collapse="", sep = "")}) - make_col <- leaflet::colorFactor(aes$pal, values) - proxy <- proxy |> - leaflet.minicharts::addMinicharts( - lng = df_visible$lon, - lat = df_visible$lat, - chartdata = df_visible[, values], - type = aes$type, - colorPalette = make_col(values), - width = aes$width, - height = aes$height, - opacity = aes$opacity, - showLabels = aes$showLabels, - transitionTime = 0, - legend = aes$legend, - legendPosition = aes$legendPosition, - layerId = layerId_info - ) - proxy + values <- unique(df[df$type == "requested", aes$param]) + layerId_info <- sapply(X = seq_len(nrow(df_visible)), FUN = function(x) {paste(layer, x, collapse = "", sep = "")}) + make_col <- leaflet::colorFactor(aes$pal, values) + proxy <- proxy |> + leaflet.minicharts::addMinicharts( + lng = df_visible$lon, + lat = df_visible$lat, + chartdata = df_visible[, values], + type = aes$type, + colorPalette = make_col(values), + width = aes$width, + height = aes$height, + opacity = aes$opacity, + showLabels = aes$showLabels, + transitionTime = 0, + legend = aes$legend, + legendPosition = aes$legendPosition, + layerId = layerId_info + ) + proxy } @@ -211,36 +220,36 @@ add_lm_piecharts <- function(proxy, aes, df, df_visible, layer) { #' #' @return An updated map. display_option <- function(m, aes, df, type, leaves, i) { - - if (aes$display == "requested") { - df_visible <- df[df$type == "requested",] - } else if (aes$display == "all") { - df_visible <- df - } else if (aes$display == "leaves") { - df_visible <- df[df$taxid %in% leaves,] - } - ancestors <- unique(unlist(df[df$taxid %in% aes$taxids[[1]], "ascend"])) - all_taxids <- c(df[df$taxid %in% aes$taxids[[1]],"taxid"], ancestors) - if (!(is.null(aes$taxids))) { - df_visible = df_visible[df_visible$taxid %in% all_taxids, ] - } - if (nrow(df_visible) < 5000) { - - if (type == "markers") { - m <- m |> - add_lm_markers(aes = aes, df = df, - df_visible = df_visible, - group_info = as.character(i)) - } else if (type == "discret") { - m <- m |> - add_lm_piecharts(aes = aes, df = df, - df_visible = df_visible, - layer = as.character(i)) - } - } else { - stop("you are trying to draw to many points at a time, maybe you shoud try another options") + + if (aes$display == "requested") { + df_visible <- df[df$type == "requested", ] + } else if (aes$display == "all") { + df_visible <- df + } else if (aes$display == "leaves") { + df_visible <- df[df$taxid %in% leaves, ] + } + ancestors <- unique(unlist(df[df$taxid %in% aes$taxids[[1]], "ascend"])) + all_taxids <- c(df[df$taxid %in% aes$taxids[[1]], "taxid"], ancestors) + if (!(is.null(aes$taxids))) { + df_visible <- df_visible[df_visible$taxid %in% all_taxids, ] + } + if (nrow(df_visible) < 5000) { + + if (type == "markers") { + m <- m |> + add_lm_markers(aes = aes, df = df, + df_visible = df_visible, + group_info = as.character(i)) + } else if (type == "discret") { + m <- m |> + add_lm_piecharts(aes = aes, df = df, + df_visible = df_visible, + layer = as.character(i)) } - return(m) + } else { + stop("you are trying to draw to many points at a time, maybe you shoud try another options") + } + return(m) } @@ -267,71 +276,71 @@ display_option <- function(m, aes, df, type, leaves, i) { #' lifemap(LM_eukaryotes) + lm_markers() + lm_branches() #' } draw_Lifemap <- function(lm_obj) { - - df <- lm_obj$df - basemap <- lm_obj$basemap - aes <- lm_obj$aes - zoom_level <- lm_obj$options$zoom - - all_ancestors <- unique(unlist(df$ascend)) - leaves <- df[!(df$taxid %in% all_ancestors), "taxid"] - - variables <- c() - for (i in 1:length(aes)) { - for (param in aes[[i]]){ - if ((is.character(param)) && param %in% colnames(df)){ - variables <- append(variables, param) - } - } - } - variables <- unique(variables) - - if (length(variables) > 0) { - M <- create_matrix(df, variables) + + df <- lm_obj$df + basemap <- lm_obj$basemap + aes <- lm_obj$aes + zoom_level <- lm_obj$options$zoom + + all_ancestors <- unique(unlist(df$ascend)) + leaves <- df[!(df$taxid %in% all_ancestors), "taxid"] + + variables <- c() + for (i in seq_along(aes)) { + for (param in aes[[i]]){ + if ((is.character(param)) && param %in% colnames(df)) { + variables <- append(variables, param) + } } - - cat("passing the information to the nodes \n") - #pass the information to the nodes or not - for (i in 1:length(aes)) { - # passing information if the function is given - if (is.lm_markers(aes[[i]]) && !(is.null(aes[[i]]$FUN))) { - for (parameter in aes[[i]]) { - - if (!(is.null(parameter)) && is.character(parameter) && parameter %in% colnames(df)) { - new_df <- pass_infos(M = M, - FUN = aes[[i]]$FUN, - value = parameter) - for (id in names(new_df)) { - if (is.na(df[df$taxid == id, parameter])) { - df[df$taxid == id, parameter] <- new_df[id] - } - } - } + } + variables <- unique(variables) + + if (length(variables) > 0) { + M <- create_matrix(df, variables) + } + + cat("passing the information to the nodes \n") + #pass the information to the nodes or not + for (i in seq_along(aes)) { + # passing information if the function is given + if (is.lm_markers(aes[[i]]) && !(is.null(aes[[i]]$FUN))) { + for (parameter in aes[[i]]) { + + if (!(is.null(parameter)) && is.character(parameter) && parameter %in% colnames(df)) { + new_df <- pass_infos(M = M, + FUN = aes[[i]]$FUN, + value = parameter) + for (id in names(new_df)) { + if (is.na(df[df$taxid == id, parameter])) { + df[df$taxid == id, parameter] <- new_df[id] } - } else if (is.lm_branches(aes[[i]]) && !(is.null(aes[[i]]$FUN))) { - for (parameter in aes[[i]]) { - if (!(is.null(parameter)) && is.character(parameter) && parameter %in% colnames(df)) { - new_df <- pass_infos(M = M, - FUN = aes[[i]]$FUN, - value = parameter) - for (id in names(new_df)) { - if (is.na(df[df$taxid == id, parameter])) { - df[df$taxid == id, parameter] <- new_df[id] - } - } - } + } + } + } + } else if (is.lm_branches(aes[[i]]) && !(is.null(aes[[i]]$FUN))) { + for (parameter in aes[[i]]) { + if (!(is.null(parameter)) && is.character(parameter) && parameter %in% colnames(df)) { + new_df <- pass_infos(M = M, + FUN = aes[[i]]$FUN, + value = parameter) + for (id in names(new_df)) { + if (is.na(df[df$taxid == id, parameter])) { + df[df$taxid == id, parameter] <- new_df[id] } - } else if (is.lm_piecharts(aes[[i]])) { - new_df <- pass_infos_discret(M = M, - value = aes[[i]]$param) - df <- merge(df, new_df, by.x = "taxid", by.y = "taxid") + } } + } + } else if (is.lm_piecharts(aes[[i]])) { + new_df <- pass_infos_discret(M = M, + value = aes[[i]]$param) + df <- merge(df, new_df, by.x = "taxid", by.y = "taxid") } - - ui <- shiny::fluidPage( - htmltools::tags$head( - htmltools::tags$style( - htmltools::HTML(" + } + + ui <- shiny::fluidPage( + htmltools::tags$head( + htmltools::tags$style( + htmltools::HTML(" .leaflet-container { background: #000000; outline: 0; @@ -345,200 +354,200 @@ draw_Lifemap <- function(lm_obj) { position:fixed !important; } ") - )), - - # htmltools::tags$style(type = "text/css", "#mymap {height: calc(100vh) !important; }"), - leaflet::leafletOutput("mymap"), - htmltools::p() + )), + + # htmltools::tags$style(type = "text/css", "#mymap {height: calc(100vh) !important; }"), + leaflet::leafletOutput("mymap"), + htmltools::p() + ) + + server <- function(input, output, session) { + + # define the zone visible by the users + df_zoom_bounds <- shiny::reactive( + df[df$zoom <= (input$mymap_zoom + zoom_level) & + df$lat > input$mymap_bounds$south & + df$lat < input$mymap_bounds$north & + df$lon > input$mymap_bounds$west & + df$lon < input$mymap_bounds$east, ] ) + + # define the descendants of df_zoom_bounds' taxids + df_descendants <- shiny::reactive({ + visibles <- df_zoom_bounds()$taxid + df[df$ancestor %in% visibles, ] + }) + + addLegendCustom <- function(map, colors, labels, sizes, shapes, borders, opacity = 0.5, title, position) { - server <- function(input, output, session) { - - # define the zone visible by the users - df_zoom_bounds <- shiny::reactive( - df[df$zoom <= (input$mymap_zoom + zoom_level) & - df$lat > input$mymap_bounds$south & - df$lat < input$mymap_bounds$north & - df$lon > input$mymap_bounds$west & - df$lon < input$mymap_bounds$east,] - ) + make_shapes <- function(colors, sizes, borders, shapes) { + shapes <- gsub("circle", "50%", shapes) + shapes <- gsub("square", "0%", shapes) + paste0(colors, "; width:", sizes, "px; height:", sizes, "px; border:3px solid ", borders, "; border-radius:", shapes) + } + make_labels <- function(sizes, labels) { + paste0("
", labels, "
") + } + + legend_colors <- make_shapes(colors, sizes, borders, shapes) + legend_labels <- make_labels(sizes, labels) + + return(addLegend(map, colors = legend_colors, labels = legend_labels, opacity = opacity, title = title, position = position)) + } + + # output of the map + output$mymap <- leaflet::renderLeaflet({ + m <- display_map(df, basemap = basemap) |> leaflet::fitBounds(~min(lon), ~min(lat), ~max(lon), ~max(lat)) + + for (i in seq_along(aes)) { + + if (is.lm_markers(aes[[i]])) { - # define the descendants of df_zoom_bounds' taxids - df_descendants <- shiny::reactive({ - visibles <- df_zoom_bounds()$taxid - df[df$ancestor %in% visibles, ] - }) + # if particular display option, it is drawn now + if (!(aes[[i]]$display %in% "auto")) { + m <- display_option(m = m, aes = aes[[i]], df = df, type = "markers", leaves = leaves, i = i) + } - addLegendCustom <- function(map, colors, labels, sizes, shapes, borders, opacity = 0.5, title, position) { - - make_shapes <- function(colors, sizes, borders, shapes) { - shapes <- gsub("circle", "50%", shapes) - shapes <- gsub("square", "0%", shapes) - paste0(colors, "; width:", sizes, "px; height:", sizes, "px; border:3px solid ", borders, "; border-radius:", shapes) - } - make_labels <- function(sizes, labels) { - paste0("
", labels, "
") + # ading legend if necessary + if (aes[[i]]$legend == TRUE) { + + if (aes[[i]]$radius %in% colnames(df)) { + part <- (max(df[[aes[[i]]$radius]], na.rm = TRUE) - min(df[[aes[[i]]$radius]], na.rm = TRUE)) / 4 + part_vector <- c(min(df[[aes[[i]]$radius]], na.rm = TRUE), + min(df[[aes[[i]]$radius]], na.rm = TRUE) + part, + min(df[[aes[[i]]$radius]], na.rm = TRUE) + part * 2, + min(df[[aes[[i]]$radius]], na.rm = TRUE) + part * 3, + max(df[[aes[[i]]$radius]], na.rm = TRUE)) + + old_min <- min(df[[aes[[i]]$radius]], na.rm = TRUE) + old_max <- max(df[[aes[[i]]$radius]], na.rm = TRUE) + old_range <- old_max - old_min + new_range <- aes[[i]]$max - aes[[i]]$min + + colors <- c("white", "white", "white", "white", "white") + labels <- as.character(round(part_vector)) + sizes <- sapply(part_vector, FUN = function(x) {(((x - old_min) * new_range) / old_range) + aes[[i]]$min}) + sizes <- sizes * 2 + shapes <- c("circle", "circle", "circle", "circle", "circle") + borders <- c("black", "black", "black", "black", "black") + + m <- m |> addLegendCustom(colors, labels, sizes, shapes, borders, + title = as.character(aes[[i]]$radius), + position = aes[[i]]$legendPosition) } - - legend_colors <- make_shapes(colors, sizes, borders, shapes) - legend_labels <- make_labels(sizes, labels) - - return(addLegend(map, colors = legend_colors, labels = legend_labels, opacity = opacity, title = title, position = position)) - } - - # output of the map - output$mymap <- leaflet::renderLeaflet({ - m <- display_map(df, basemap = basemap) |> leaflet::fitBounds(~min(lon), ~min(lat), ~max(lon), ~max(lat)) - - for (i in 1:length(aes)) { - - if (is.lm_markers(aes[[i]])) { - - # if particular display option, it is drawn now - if (!(aes[[i]]$display %in% "auto")) { - m <- display_option(m = m, aes = aes[[i]], df = df, type = "markers", leaves = leaves, i = i) - } - - # ading legend if necessary - if (aes[[i]]$legend == TRUE) { - - if (aes[[i]]$radius %in% colnames(df)) { - part = (max(df[[aes[[i]]$radius]], na.rm = TRUE) - min(df[[aes[[i]]$radius]], na.rm = TRUE)) / 4 - part_vector <- c(min(df[[aes[[i]]$radius]], na.rm = TRUE), - min(df[[aes[[i]]$radius]], na.rm = TRUE) + part, - min(df[[aes[[i]]$radius]], na.rm = TRUE) + part * 2, - min(df[[aes[[i]]$radius]], na.rm = TRUE) + part * 3, - max(df[[aes[[i]]$radius]], na.rm = TRUE)) - - old_min <- min(df[[aes[[i]]$radius]], na.rm = TRUE) - old_max <- max(df[[aes[[i]]$radius]], na.rm = TRUE) - old_range <- old_max - old_min - new_range <- aes[[i]]$max - aes[[i]]$min - - colors <- c("white", "white", "white", "white", "white") - labels <- as.character(round(part_vector)) - sizes <- sapply(part_vector, FUN = function(x){(((x - old_min) * new_range) / old_range) + aes[[i]]$min}) - sizes <- sizes * 2 - shapes <- c("circle", "circle", "circle", "circle", "circle") - borders <- c("black", "black", "black", "black", "black") - - m <- m |> addLegendCustom(colors, labels, sizes, shapes, borders, - title = as.character(aes[[i]]$radius), - position = aes[[i]]$legendPosition) - } - if ((!is.null(aes[[i]]$var_fillColor)) && aes[[i]]$var_fillColor %in% colnames(df)) { - if (is.numeric(df[[aes[[i]]$var_fillColor]])){ - make_fillColor <- leaflet::colorNumeric(palette = aes[[i]]$fillPalette, domain = df[[aes[[i]]$var_fillColor]], reverse = TRUE) - } else { - make_fillColor <- leaflet::colorFactor(palette = aes[[i]]$fillPalette, domain = df[[aes[[i]]$var_fillColor]], reverse = TRUE) - } - - m <- m |> leaflet::addLegend(position = "bottomright", - title = aes[[i]]$var_fillColor, - pal = make_fillColor, - values = df[[aes[[i]]$var_fillColor]]) - } - if ((!is.null(aes[[i]]$var_color)) && aes[[i]]$var_color %in% colnames(df)) { - if (is.numeric(df[[aes[[i]]$var_color]])){ - make_color <- leaflet::colorNumeric(aes[[i]]$palette, df[[aes[[i]]$var_color]], reverse = TRUE) - } else { - make_color <- leaflet::colorFactor(aes[[i]]$palette, df[[aes[[i]]$var_color]], reverse = TRUE) - } - - m <- m |> leaflet::addLegend(position = "bottomright", - title = aes[[i]]$var_color, - pal = make_color, - values = df[[aes[[i]]$var_color]]) - } - } - } else if (is.lm_branches(aes[[i]])) { - if (aes[[i]]$legend == TRUE) { - if (!(aes[[i]]$var_color %in% "default")) { - make_color <- leaflet::colorNumeric(aes[[i]]$palette, df[[aes[[i]]$var_color]], reverse = TRUE) - - m <- m |> leaflet::addLegend(position = aes[[i]]$legendPosition, - title = paste("subtree : ", aes[[i]]$var_color, sep = "", collapse = ""), - pal = make_color, - values = df[[aes[[i]]$var_color]]) - } - } - } else if (is.lm_piecharts(aes[[i]])){ - if (!(aes[[i]]$display %in% "auto")) { - m <- display_option(m = m, aes = aes[[i]], df = df, type = "discret", leaves = leaves, i = i) - } - } + if ((!is.null(aes[[i]]$var_fillColor)) && aes[[i]]$var_fillColor %in% colnames(df)) { + if (is.numeric(df[[aes[[i]]$var_fillColor]])) { + make_fillColor <- leaflet::colorNumeric(palette = aes[[i]]$fillPalette, domain = df[[aes[[i]]$var_fillColor]], reverse = TRUE) + } else { + make_fillColor <- leaflet::colorFactor(palette = aes[[i]]$fillPalette, domain = df[[aes[[i]]$var_fillColor]], reverse = TRUE) + } + + m <- m |> leaflet::addLegend(position = "bottomright", + title = aes[[i]]$var_fillColor, + pal = make_fillColor, + values = df[[aes[[i]]$var_fillColor]]) } - m - }) - - # modification of the map to display the rights markers - shiny::observe({ - - # clearing all the already existing shapes/markers/controls - proxy <- leaflet::leafletProxy("mymap", session = session) - - # adding the visible shapes - for (i in 1:length(aes)) { - - # for each aesthetic, if a sub dataset is given, compute the right taxids to be used - ancestors <- unique(unlist(df[df$taxid %in% aes[[i]]$taxids[[1]], "ascend"])) - all_taxids <- c(df[df$taxid %in% aes[[i]]$taxids[[1]], "taxid"], ancestors) - if (!(is.null(aes[[i]]$taxids))) { - df_visible <- df_zoom_bounds()[df_zoom_bounds()$taxid %in% all_taxids,] - } else { - df_visible = df_zoom_bounds() - } - - # adding markers if aes[[i]] is an lm_markers object - if (is.lm_markers(aes[[i]]) && aes[[i]]$display == "auto") { - proxy <- leaflet::clearGroup(proxy, group = as.character(i)) |> - add_lm_markers(aes = aes[[i]], df = df, - df_visible = df_visible, - group_info = as.character(i)) - - # adding a subtree if aes[[i]] is an lm_branches object - } else if (is.lm_branches(aes[[i]])) { - proxy <- leaflet::clearGroup(proxy, group = as.character(i)) |> - add_lm_branches(aes = aes[[i]], df = df, - df_visible = df_visible, - df_descendants = df_descendants(), - group_info = as.character(i), - all_taxids = all_taxids) - - # adding charts if aes[[i]] is an lm_piecharts object - } else if(is.lm_piecharts(aes[[i]]) && nrow(df_visible) > 0 && aes[[i]]$display %in% "auto") { - proxy <- leaflet.minicharts::clearMinicharts(proxy) |> - add_lm_piecharts(aes = aes[[i]], df = df, - df_visible = df_visible, - layer = as.character(i)) - } + if ((!is.null(aes[[i]]$var_color)) && aes[[i]]$var_color %in% colnames(df)) { + if (is.numeric(df[[aes[[i]]$var_color]])) { + make_color <- leaflet::colorNumeric(aes[[i]]$palette, df[[aes[[i]]$var_color]], reverse = TRUE) + } else { + make_color <- leaflet::colorFactor(aes[[i]]$palette, df[[aes[[i]]$var_color]], reverse = TRUE) + } + + m <- m |> leaflet::addLegend(position = "bottomright", + title = aes[[i]]$var_color, + pal = make_color, + values = df[[aes[[i]]$var_color]]) } - proxy - }) - - # functions to add popups - showSciName_popup <- function(group, lng, lat) { - if(!is.null(aes[[as.numeric(group)]]$popup)) { - selectedId <- df[round(df$lon, digits = 6) == round(lng, digits = 6) & round(df$lat, digits = 6) == round(lat, digits = 6), ] - content <- as.character(selectedId$taxid) - content <- paste(content, ",", aes[[as.numeric(group)]]$popup, ":", selectedId[[aes[[as.numeric(group)]]$popup]]) - leafletProxy("mymap") |> leaflet::addPopups(lng, lat, content) + } + } else if (is.lm_branches(aes[[i]])) { + if (aes[[i]]$legend == TRUE) { + if (!(aes[[i]]$var_color %in% "default")) { + make_color <- leaflet::colorNumeric(aes[[i]]$palette, df[[aes[[i]]$var_color]], reverse = TRUE) + + m <- m |> leaflet::addLegend(position = aes[[i]]$legendPosition, + title = paste("subtree : ", aes[[i]]$var_color, sep = "", collapse = ""), + pal = make_color, + values = df[[aes[[i]]$var_color]]) } + } + } else if (is.lm_piecharts(aes[[i]])) { + if (!(aes[[i]]$display %in% "auto")) { + m <- display_option(m = m, aes = aes[[i]], df = df, type = "discret", leaves = leaves, i = i) + } } - - # when clicking on a marker, show a popup - shiny::observe({ - leafletProxy("mymap") |> leaflet::clearPopups() - event <- input$mymap_marker_click - if (is.null(event)) - return() - - shiny::isolate({ - showSciName_popup(event$group, event$lng, event$lat) - }) - }) + } + m + }) + + # modification of the map to display the rights markers + shiny::observe({ + + # clearing all the already existing shapes/markers/controls + proxy <- leaflet::leafletProxy("mymap", session = session) + + # adding the visible shapes + for (i in seq_along(aes)) { + + # for each aesthetic, if a sub dataset is given, compute the right taxids to be used + ancestors <- unique(unlist(df[df$taxid %in% aes[[i]]$taxids[[1]], "ascend"])) + all_taxids <- c(df[df$taxid %in% aes[[i]]$taxids[[1]], "taxid"], ancestors) + if (!(is.null(aes[[i]]$taxids))) { + df_visible <- df_zoom_bounds()[df_zoom_bounds()$taxid %in% all_taxids, ] + } else { + df_visible <- df_zoom_bounds() + } + + # adding markers if aes[[i]] is an lm_markers object + if (is.lm_markers(aes[[i]]) && aes[[i]]$display == "auto") { + proxy <- leaflet::clearGroup(proxy, group = as.character(i)) |> + add_lm_markers(aes = aes[[i]], df = df, + df_visible = df_visible, + group_info = as.character(i)) + + # adding a subtree if aes[[i]] is an lm_branches object + } else if (is.lm_branches(aes[[i]])) { + proxy <- leaflet::clearGroup(proxy, group = as.character(i)) |> + add_lm_branches(aes = aes[[i]], df = df, + df_visible = df_visible, + df_descendants = df_descendants(), + group_info = as.character(i), + all_taxids = all_taxids) + + # adding charts if aes[[i]] is an lm_piecharts object + } else if (is.lm_piecharts(aes[[i]]) && nrow(df_visible) > 0 && aes[[i]]$display %in% "auto") { + proxy <- leaflet.minicharts::clearMinicharts(proxy) |> + add_lm_piecharts(aes = aes[[i]], df = df, + df_visible = df_visible, + layer = as.character(i)) + } + } + proxy + }) + + # functions to add popups + showSciName_popup <- function(group, lng, lat) { + if (!is.null(aes[[as.numeric(group)]]$popup)) { + selectedId <- df[round(df$lon, digits = 6) == round(lng, digits = 6) & round(df$lat, digits = 6) == round(lat, digits = 6), ] + content <- as.character(selectedId$taxid) + content <- paste(content, ",", aes[[as.numeric(group)]]$popup, ":", selectedId[[aes[[as.numeric(group)]]$popup]]) + leafletProxy("mymap") |> leaflet::addPopups(lng, lat, content) + } } - shiny::shinyApp(ui, server) + + # when clicking on a marker, show a popup + shiny::observe({ + leafletProxy("mymap") |> leaflet::clearPopups() + event <- input$mymap_marker_click + if (is.null(event)) + return() + + shiny::isolate({ + showSciName_popup(event$group, event$lng, event$lat) + }) + }) + } + shiny::shinyApp(ui, server) } diff --git a/R/lifemap_obj.R b/R/lifemap_obj.R index ff5ddf4..ba452bd 100644 --- a/R/lifemap_obj.R +++ b/R/lifemap_obj.R @@ -12,10 +12,10 @@ #' data(LM_eukaryotes) #' print(LM_eukaryotes) #' } -print.lifemap_obj <- function(x,...) { +print.lifemap_obj <- function(x, ...) { if (is.null(x$aes) && !is.null(x$df)) { - cat('The dataframe contains', nrow(x$df),'rows and', ncol(x$df), 'columns. \n') - cat('The basemap used is :', x$basemap, '\n') + cat("The dataframe contains", nrow(x$df), "rows and", ncol(x$df), "columns. \n") + cat("The basemap used is :", x$basemap, "\n") } else if (is.null(x$df)) { class(x) <- "list" print(x) @@ -37,7 +37,9 @@ print.lifemap_obj <- function(x,...) { #' is.lifemap_obj(LM_eukaryotes) #' } #' -is.lifemap_obj <- function(x) inherits(x, "lifemap_obj") +is.lifemap_obj <- function(x) { + inherits(x, "lifemap_obj") +} #' Add a graphical element to a tree visualisation. #' @param e1 An object of class lifemap_obj that contains at least $df, a dataframe, and $basemap, the map used to get the coordinates. @@ -52,8 +54,8 @@ is.lifemap_obj <- function(x) inherits(x, "lifemap_obj") #' LM_obj <- lifemap(LM_eukaryotes) + lm_markers() + lm_branches() #' } #' -"+.lifemap_obj" <- function(e1,e2) { - if (is.lm_markers(e2)){ +"+.lifemap_obj" <- function(e1, e2) { + if (is.lm_markers(e2)) { for (aes in c("radius", "var_fillColor", "var_color", "fillOpacity")){ if (is.character(e2[[aes]]) && !(e2[[aes]] %in% "default")) { e2[[aes]] <- match.arg(arg = e2[[aes]], choices = colnames(e1$df)) @@ -70,7 +72,7 @@ is.lifemap_obj <- function(x) inherits(x, "lifemap_obj") e2$param <- match.arg(arg = e2$param, choices = colnames(e1$df)) } - if(is.null(e1$aes)) { + if (is.null(e1$aes)) { e1$aes <- list(e2) } else { e1$aes <- append(e1$aes, list(e2)) diff --git a/R/lm_branches.R b/R/lm_branches.R index bc1845f..06c73d7 100644 --- a/R/lm_branches.R +++ b/R/lm_branches.R @@ -29,7 +29,7 @@ lm_branches <- function(data = NULL, max = 20, opacity = 0.5, FUN = NULL, - legend=TRUE, + legend = TRUE, legendPosition = c("topright", "bottomright", "bottomleft", "topleft")) { legendPosition <- match.arg(arg = legendPosition, choices = legendPosition) @@ -40,7 +40,7 @@ lm_branches <- function(data = NULL, taxids <- NULL } - if (is.null(var_color)){ + if (is.null(var_color)) { var_color <- "default" } palette <- NULL @@ -66,7 +66,7 @@ lm_branches <- function(data = NULL, FUN = FUN, var_color = var_color, value = value, size = size, min = min, max = max, opacity = opacity, legend = legend, legendPosition = legendPosition) - class(res)=c("lifemap_obj", "lm_branches", "list") + class(res) <- c("lifemap_obj", "lm_branches", "list") return(res) } diff --git a/R/lm_piecharts.R b/R/lm_piecharts.R index cbbc4a8..6b5f9c9 100644 --- a/R/lm_piecharts.R +++ b/R/lm_piecharts.R @@ -17,7 +17,6 @@ #' - "leaves" : displays only the latest (most recent) taxa #' #' (WARNING : "requested", "leaves" and "auto" shouldn't be used to display more than 2000 charts as it may result in long computing time) -#' #' @return An lm_piecharts object containing all aesthetics details for one layer of charts #' @export #' diff --git a/R/make_newick.R b/R/make_newick.R index 4a41aed..2b4a0af 100644 --- a/R/make_newick.R +++ b/R/make_newick.R @@ -20,10 +20,10 @@ make_newick <- function(df) { mat <- rbind(mat[whereroot, ], mat[-whereroot, ]) i <- length(whereroot) + 1 while (i < nrow(mat)) { - while(!(mat[i, 1] %in% mat[1:(i - 1), 2])) { + while (!(mat[i, 1] %in% mat[1:(i - 1), 2])) { mat <- rbind(mat[-i, ], mat[i, ]) } - i <- i+1 + i <- i + 1 } ## Put secial characters ("-") before and after each name @@ -32,7 +32,7 @@ make_newick <- function(df) { nodes <- unique(matok[, 1]) nwk <- paste(matok[1, 2], ";", sep = "") for (n in nodes[-1]) { - desc <- paste("(", paste(matok[which(matok[, 1]%in% n), 2], collapse = ","),")", n, sep = "") + desc <- paste("(", paste(matok[which(matok[, 1] %in% n), 2], collapse = ","), ")", n, sep = "") nwk <- gsub(n, desc, nwk) } # remove the special character