From 3643b2aedd83bfe935730ef4abdcb89887d6e97f Mon Sep 17 00:00:00 2001 From: Travers Date: Tue, 24 Sep 2024 19:29:52 -0700 Subject: [PATCH] . --- ChangeLog | 6 + DESCRIPTION | 8 +- NAMESPACE | 1 + R/{glow_functions.r => glow_pkg_functions.R} | 85 +++++---- R/zz_help_files.R | 32 +++- README.md | 15 +- inst/examples/examples.R | 24 ++- inst/examples/examples_parse_data.R | 12 +- inst/examples/gps_example.R | 4 +- man/light_cool_colors.Rd | 27 +++ man/relxy.Rd | 7 +- vignettes/diamonds_vignette_cool.png | Bin 0 -> 22963 bytes vignettes/vignette.html | 178 ++++++++++++------- vignettes/vignette.rmd | 22 ++- 14 files changed, 285 insertions(+), 136 deletions(-) create mode 100644 ChangeLog rename R/{glow_functions.r => glow_pkg_functions.R} (95%) create mode 100644 man/light_cool_colors.Rd create mode 100755 vignettes/diamonds_vignette_cool.png diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..43c4d3a --- /dev/null +++ b/ChangeLog @@ -0,0 +1,6 @@ +Version 0.13.0 (2024-09-024) + * Add 'mode' parameter to 'relx' and 'rely'. + * Suggest 'qs2' instead of 'qs' + * Add 'light_cool_colors' theme +Version 0.12.0 (2023-04-06) + * Initial tracking diff --git a/DESCRIPTION b/DESCRIPTION index d1c8e63..75487c9 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: glow Title: Make Plots that Glow -Version: 0.12.0 -Date: 2023-4-6 +Version: 0.13.0 +Date: 2024-09-24 Authors@R: c( person("Travers", "Ching", email = "traversc@gmail.com", role = c("aut", "cre", "cph")) ) @@ -17,8 +17,8 @@ Imports: Depends: ggplot2 Suggests: - knitr, rmarkdown, viridisLite, magick, EBImage, qs + knitr, rmarkdown, viridisLite, magick, EBImage, qs2 VignetteBuilder: knitr -RoxygenNote: 7.1.2 +RoxygenNote: 7.3.2 URL: https://github.com/traversc/glow BugReports: https://github.com/traversc/glow/issues diff --git a/NAMESPACE b/NAMESPACE index f73772c..cdb731f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -7,6 +7,7 @@ importFrom(grDevices, col2rgb, rgb, colorRampPalette, rainbow) useDynLib(glow, .registration=TRUE) export("theme_night", "light_heat_colors", + "light_cool_colors", "additive_alpha", "GlowMapper", "GlowMapper4", diff --git a/R/glow_functions.r b/R/glow_pkg_functions.R similarity index 95% rename from R/glow_functions.r rename to R/glow_pkg_functions.R index 113de11..ba6b403 100644 --- a/R/glow_functions.r +++ b/R/glow_pkg_functions.R @@ -18,6 +18,10 @@ light_heat_colors <- function(...) { colorRampPalette(c("red", "darkorange2", "darkgoldenrod1", "gold1", "yellow2"))(...) } +light_cool_colors <- function(...) { + colorRampPalette(c("#1133AA", "#CCFFFF"))(...) +} + additive_alpha <- function(colors) { s <- seq(2, length(colors)) x <- t(col2rgb(colors, alpha=F))/255 @@ -44,14 +48,42 @@ map_colors <- function(colors, x, min_limit=NULL, max_limit=NULL) { colors[findInterval(x, seq(min_limit, max_limit, length.out = length(colors) + 1), all.inside = TRUE)] } -relx <- function(r) { - structure(r, class = "relx") +relx <- function(r, mode = "data") { + structure(r, class = "relx", mode = mode) } -rely <- function(r) { - structure(r, class = "rely") +rely <- function(r, mode = "data") { + structure(r, class = "rely", mode = mode) } +# internal helper function +calculate_radius <- function(radius, xdiff, ydiff, self) { + plot_x_diff <- self$xmax - self$xmin + plot_y_diff <- self$ymax - self$ymin + if(inherits(radius, "relx")) { + rel_mode <- attr(radius, "mode") + attributes(radius) <- NULL + if(rel_mode == "data") { + radius <- xdiff * radius / self$x_aspect_ratio + } else if(rel_mode == "plot") { + radius <- plot_x_diff * radius / self$x_aspect_ratio + } else { + stop("relx mode must be 'data' or 'plot'") + } + } else if(inherits(radius, "rely")) { + rel_mode <- attr(radius, "mode") + attributes(radius) <- NULL + if(rel_mode == "data") { + radius <- ydiff * radius / self$y_aspect_ratio + } else if(rel_mode == "plot") { + radius <- plot_y_diff * radius / self$y_aspect_ratio + } else { + stop("rely mode must be 'data' or 'plot'") + } + } else { + radius + } +} # GlowMapper ################################### GlowMapper <- R6Class("GlowMapper", list( @@ -115,16 +147,7 @@ GlowMapper <- R6Class("GlowMapper", list( self$x_aspect_ratio <- max(xincrement / yincrement,1) self$y_aspect_ratio <- max(yincrement / xincrement,1) - if(inherits(radius, "relx")) { - class(radius) <- NULL - radius <- xdiff * radius / self$x_aspect_ratio - } else if(inherits(radius, "rely")) { - class(radius) <- NULL - radius <- ydiff * radius / self$y_aspect_ratio - } else { - # nothing - } - class(radius) <- NULL + radius <- calculate_radius(radius, xdiff, ydiff, self) self$plot_data <- data.frame(x, y, intensity, radius, distance_exponent) @@ -275,17 +298,7 @@ GlowMapper4 <- R6Class("GlowMapper4", list( self$x_aspect_ratio <- max(xincrement / yincrement,1) self$y_aspect_ratio <- max(yincrement / xincrement,1) - - if(inherits(radius, "relx")) { - class(radius) <- NULL - radius <- xdiff * radius / self$x_aspect_ratio - } else if(inherits(radius, "rely")) { - class(radius) <- NULL - radius <- ydiff * radius / self$y_aspect_ratio - } else { - # nothing - } - class(radius) <- NULL + radius <- calculate_radius(radius, xdiff, ydiff, self) self$plot_data <- data.frame(x, y, r,g,b, radius, distance_exponent) @@ -460,16 +473,7 @@ LightMapper <- R6Class("LightMapper", list( self$x_aspect_ratio <- max(xincrement / yincrement,1) self$y_aspect_ratio <- max(yincrement / xincrement,1) - if(inherits(radius, "relx")) { - class(radius) <- NULL - radius <- xdiff * radius / self$x_aspect_ratio - } else if(inherits(radius, "rely")) { - class(radius) <- NULL - radius <- ydiff * radius / self$y_aspect_ratio - } else { - # nothing - } - class(radius) <- NULL + radius <- calculate_radius(radius, xdiff, ydiff, self) self$plot_data <- data.frame(x, y, intensity, radius, falloff_exponent, distance_exponent) @@ -615,16 +619,7 @@ LightMapper4 <- R6Class("GlowMapper4", list( self$x_aspect_ratio <- max(xincrement / yincrement,1) self$y_aspect_ratio <- max(yincrement / xincrement,1) - if(inherits(radius, "relx")) { - class(radius) <- NULL - radius <- xdiff * radius / self$x_aspect_ratio - } else if(inherits(radius, "rely")) { - class(radius) <- NULL - radius <- ydiff * radius / self$y_aspect_ratio - } else { - # nothing - } - class(radius) <- NULL + radius <- calculate_radius(radius, xdiff, ydiff, self) self$plot_data <- data.frame(x, y, r,g,b, radius, distance_exponent, falloff_exponent) diff --git a/R/zz_help_files.R b/R/zz_help_files.R index 56b9be9..50a7f6f 100644 --- a/R/zz_help_files.R +++ b/R/zz_help_files.R @@ -35,6 +35,25 @@ NULL #' @name light_heat_colors NULL +# light_cool_colors ################################################### + +#' light_cool_colors +#' +#' A light color palette. +#' +#' @usage light_cool_colors(...) +#' @param ... Arguments passed to the function returned by `colorRampPalette` +#' @return A light color palette function +#' @details A simple light color palette gradient from dark blue to light blue +#' intended for a heatmap with a white or light color background. +#' +#' Equivalent to `colorRampPalette(c("#1133AA", "#CCFFFF"))(...)`. +#' @examples +#' light_colors <- light_cool_colors(144) +#' plot(1:144, 1:144, col = light_colors, pch = 19) +#' @name light_cool_colors +NULL + # circular_palette ################################################### #' circular_palette @@ -94,9 +113,11 @@ NULL #' #' Helper functions for specifying the `radius` parameter in `GlowMapper$map` and similar. #' -#' @usage relx(r) -#' @aliases relx -#' @param r Radius of point data relative to X or Y range of the plot, a value between 0 and 1. +#' @usage relx(r, mode = "data") +#' @usage rely(r, mode = "data") +#' @param r Radius of point data relative to X or Y range of the plot, a value between 0 and 1. +#' @param mode One of "data" (default) or "plot". Whether to use a radius relative to the extent +#' of the data range or the plot range (which could have been adjusted manually). #' @return A class structure for input to `GlowMapper$map` #' @details #' Helper functions for specifying the `radius` parameter relative to the range of the plot as a proportion. @@ -126,7 +147,10 @@ NULL #' @name relxy NULL -#' @usage rely(r) +#' @aliases relx +#' @name relxy +NULL + #' @aliases rely #' @name relxy NULL diff --git a/README.md b/README.md index 0e05097..b94eb58 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ ggplot() + ![](vignettes/diamonds_vignette_dark.png "diamonds_vignette_dark.png") ``` r -# light color theme +# light "heat" color theme light_colors <- light_heat_colors(144) ggplot() + geom_raster(data = pd, aes(x = pd$x, y = pd$y, fill = pd$value), show.legend = FALSE) + @@ -107,6 +107,19 @@ ggplot() + ![](vignettes/diamonds_vignette_light.png "diamonds_vignette_light.png") +``` r +# light "cool" color theme +light_colors <- light_cool_colors(144) +ggplot() + + geom_raster(data = pd, aes(x = pd$x, y = pd$y, fill = pd$value), show.legend = FALSE) + + scale_fill_gradientn(colors = additive_alpha(light_colors)) + + coord_fixed(gm$aspect(), xlim = gm$xlim(), ylim = gm$ylim()) + + labs(x = "carat", y = "price") + + theme_bw(base_size = 14) +``` + +![](vignettes/diamonds_vignette_cool.png "diamonds_vignette_cool.png") + ### Writing a raster image directly Instead of using ggplot, you can also output a raster image directly diff --git a/inst/examples/examples.R b/inst/examples/examples.R index 0bb7286..18c6f6f 100755 --- a/inst/examples/examples.R +++ b/inst/examples/examples.R @@ -13,7 +13,7 @@ library(dplyr) library(data.table) -library(qs) +library(qs2) library(glow) library(ggplot2) @@ -59,7 +59,7 @@ output_width = 1920*4 output_height = 1080*4 outfile <- "plots/GAIA_galaxy_pseudocolor.png" -stars <- qread("plot_data/gaia_stars.qs") +stars <- qs_read("plot_data/gaia_stars.qs2") # Transform to galactic coordinates # https://gea.esac.esa.int/archive/documentation/GDR2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html @@ -116,7 +116,7 @@ writeImage(img, "plots/GAIA_galaxy_pseudocolor.png") outfile <- "plots/US_coronavirus_2021.png" -cov_cases <- qread("plot_data/covid_confirmed_usafacts.qs") +cov_cases <- qs_read("plot_data/covid_confirmed_usafacts.qs2") centroids <- cov_cases$centroids state <- cov_cases$state county <- cov_cases$county @@ -280,9 +280,23 @@ outfile <- "plots/diamonds_vignette_light.png" ggsave(g, file=outfile, width=10, height=4, dpi=96) trim_image(outfile, "white") +# light color theme with cool colors +light_colors <- colorRampPalette(c("#1133AA", "#CCFFFF"))(144) +g <- ggplot() + + geom_raster(data = pd, aes(x = pd$x, y = pd$y, fill = pd$value), show.legend = F) + + scale_fill_gradientn(colors = additive_alpha(light_colors)) + + coord_fixed(gm$aspect(), xlim = gm$xlim(), ylim = gm$ylim()) + + labs(x = "carat", y = "price") + + theme_bw(base_size = 14) + +outfile <- "plots/diamonds_vignette_cool.png" +ggsave(g, file=outfile, width=10, height=4, dpi=96) +trim_image(outfile, "white") + + # Volcano ########################################## -DMPs <- qread("plot_data/methylation_data.qs") +DMPs <- qs_read("plot_data/methylation_data.qs2") adj_pval_threshold <- DMPs %>% filter(adj.P.Val < 0.05) %>% pull(P.Value) %>% max @@ -308,7 +322,7 @@ trim_image(outfile, "white") # https://www.r-bloggers.com/visualize-large-data-sets-with-the-bigvis-package/ ## wget https://packages.revolutionanalytics.com/datasets/AirOnTime87to12/AirOnTimeCSV.zip . -air <- qread("plot_data/AirOnTime.qs", nthreads=nt) +air <- qs_read("plot_data/AirOnTime.qs2", nthreads=nt) temp <- rbindlist(air) qlo1 <- temp$ARR_DELAY %>% quantile(0.0025) diff --git a/inst/examples/examples_parse_data.R b/inst/examples/examples_parse_data.R index b547d38..9e04efd 100755 --- a/inst/examples/examples_parse_data.R +++ b/inst/examples/examples_parse_data.R @@ -4,7 +4,7 @@ library(glow) library(dplyr) library(data.table) library(arrow) -library(qs) +library(qs2) library(stringr) # COVID example @@ -41,7 +41,7 @@ stars <- lapply(files, function(f) { stars2 <- stars[complete.cases(stars),] stars2 <- stars2 %>% arrange_all -qsave(stars2, "plot_data/gaia_stars.qs", preset = "custom", algorithm = "zstd", compress_level = 22, nthreads = 8) +qs_save(stars2, "plot_data/gaia_stars.qs2", preset = "custom", algorithm = "zstd", compress_level = 22, nthreads = 8) # COVID ####################################################################### @@ -61,7 +61,7 @@ centroids <- left_join(centroids, cov_cases, by = c("name", "state_abbr")) centroids$total[is.na(centroids$total)] <- 0 centroids <- filter(centroids, total > 0) -qsave(list(centroids=centroids, county=county, state=state), "plot_data/covid_confirmed_usafacts.qs", preset = "custom", algorithm = "zstd", compress_level = 22) +qs_save(list(centroids=centroids, county=county, state=state), "plot_data/covid_confirmed_usafacts.qs2", preset = "custom", algorithm = "zstd", compress_level = 22) # Volcano ########################################## @@ -102,7 +102,7 @@ DMPs <- topTable(fit2, num=Inf, coef=1, genelist=ann450kSub) DMPs <- DMPs %>% dplyr::select(logFC, P.Value, adj.P.Val) rownames(DMPs) <- NULL -qsave(DMPs, file = "plot_data/methylation_data.qs", preset = "custom", algorithm = "zstd", compress_level = 22) +qs_save(DMPs, file = "plot_data/methylation_data.qs2", preset = "custom", algorithm = "zstd", compress_level = 22) # Airline ###################################################################### # https://www.r-bloggers.com/visualize-large-data-sets-with-the-bigvis-package/ @@ -119,7 +119,7 @@ air <- lapply(1:length(files), function(i) { filter(complete.cases(.)) return(z) }) -qsave(air, file="plot_data/AirOnTime.qs", preset = "custom", algorithm = "zstd", compress_level = 22, nthreads=nt) +qs_save(air, file="plot_data/AirOnTime.qs2", preset = "custom", algorithm = "zstd", compress_level = 22, nthreads=nt) # GPS traces ###################################################################### # https://planet.osm.org/gps/ @@ -130,6 +130,6 @@ system(sprintf("unxz %s/simple-gps-points-120312.txt.xz", tempdir)) gps <- data.table::fread(sprintf("%s/simple-gps-points-120312.txt", tempdir), header=FALSE, data.table=FALSE) gps <- list(latitude = gps[[1]], longitude = gps[[2]]) # Long dataframes not supported in R as of 4.2.3 -qsave(gps, file="plot_data/simple-gps-points.qs", preset = "custom", algorithm = "zstd", compress_level = 22, nthreads=nt) +qs_save(gps, file="plot_data/simple-gps-points.qs2", preset = "custom", algorithm = "zstd", compress_level = 22, nthreads=nt) diff --git a/inst/examples/gps_example.R b/inst/examples/gps_example.R index b4dc220..3023483 100644 --- a/inst/examples/gps_example.R +++ b/inst/examples/gps_example.R @@ -1,4 +1,4 @@ -library(qs) +library(qs2) library(glow) library(EBImage) @@ -10,7 +10,7 @@ output_height = 1080*4 radius <- 0.2 # Increase this value if plotting fewer points intensity <- 0.6 # Increase this value if plotting fewer points -gps <- qread("plot_data/simple-gps-points.qs", nthreads=32) +gps <- qs_read("plot_data/simple-gps-points.qs2", nthreads=32) length(gps$latitude) # 2770233904 diff --git a/man/light_cool_colors.Rd b/man/light_cool_colors.Rd new file mode 100644 index 0000000..e818a8b --- /dev/null +++ b/man/light_cool_colors.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zz_help_files.R +\name{light_cool_colors} +\alias{light_cool_colors} +\title{light_cool_colors} +\usage{ +light_cool_colors(...) +} +\arguments{ +\item{...}{Arguments passed to the function returned by `colorRampPalette`} +} +\value{ +A light color palette function +} +\description{ +A light color palette. +} +\details{ +A simple light color palette gradient from dark blue to light blue +intended for a heatmap with a white or light color background. + + Equivalent to `colorRampPalette(c("#1133AA", "#CCFFFF"))(...)`. +} +\examples{ +light_colors <- light_cool_colors(144) +plot(1:144, 1:144, col = light_colors, pch = 19) +} diff --git a/man/relxy.Rd b/man/relxy.Rd index 3f6564d..2910ec8 100644 --- a/man/relxy.Rd +++ b/man/relxy.Rd @@ -6,12 +6,15 @@ \alias{rely} \title{relxy} \usage{ -relx(r) +relx(r, mode = "data") -rely(r) +rely(r, mode = "data") } \arguments{ \item{r}{Radius of point data relative to X or Y range of the plot, a value between 0 and 1.} + +\item{mode}{One of "data" (default) or "plot". Whether to use a radius relative to the extent +of the data range or the plot range (which could have been adjusted manually).} } \value{ A class structure for input to `GlowMapper$map` diff --git a/vignettes/diamonds_vignette_cool.png b/vignettes/diamonds_vignette_cool.png new file mode 100755 index 0000000000000000000000000000000000000000..621cb84840bfc66c9fd097c3cb0183ca9e6a62e1 GIT binary patch literal 22963 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 + +