How to use the raw string (such as len/s) in the colnames in ggpubr::ggboxplot in R? It seems due to purrr::map
library(ggpubr)
data("ToothGrowth")
df <- ToothGrowth
colnames(df) <- c("len/s", "supp", "dose%sd")
ggboxplot(df, x = "dose%sd", y = 'len/s',
color = "dose%sd", palette =c("#00AFBB", "#E7B800", "#FC4E07"),
add = "jitter", shape = "dose%sd")
with error
Error in `purrr::pmap()`:
ℹ In index: 1.
ℹ With name: len/s.
Caused by error in `purrr::map()`:
ℹ In index: 1.
ℹ With name: x.
Caused by error in `parse()`:
! <text>:1:5: unexpected input
1: dose%sd
---
Backtrace:
1. ggpubr::ggboxplot(...)
15. purrr::map(., function(x) parse_expression(x))
16. purrr:::map_("list", .x, .f, ..., .progress = .progress)
20. ggpubr (local) .f(.x[[i]], ...)
21. ggpubr:::parse_expression(x)
22. base::parse(text = x)
By default, the parse_aes option is set to TRUE.
> ggpubr_options()
$ggpubr.parse_aes
[1] TRUE
We could set the parse_aes options to FALSE and reset after the plotting
library(ggpubr)
op <- options(ggpubr.parse_aes = FALSE)
colnames(df) <- c("len/s", "supp", "dose%sd")
ggboxplot(df, x = "dose%sd", y = 'len/s',
color = "dose%sd", palette =c("#00AFBB", "#E7B800", "#FC4E07"),
add = "jitter", shape = "dose%sd")
options(op)
-output
ggboxplot calls ggboxplot_core internal function, which calls the ggplot with create_aes where parse = TRUE
> ggpubr:::ggboxplot_core
...
p <- ggplot(data, create_aes(list(x = x, y = y)))
...
> create_aes
function (.list, parse = TRUE)
{
if (missing(parse)) {
parse <- base::getOption("ggpubr.parse_aes", default = TRUE)
}
if (parse) {
return(create_aes.parse(.list))
}
else {
return(create_aes.name(.list))
}
}
The create_aes.parse calls the parse_expression whereas the create_aes.name converts to symbol
> ggpubr:::create_aes.parse
function (.list)
{
.list <- .list %>% purrr::map(function(x) parse_expression(x))
do.call(ggplot2::aes, .list)
}
> ggpubr:::create_aes.name
function (.list)
{
.list <- .list %>% purrr::map(function(x) to_name(x))
do.call(ggplot2::aes, .list)
}
Therefore, it is easier to set the parse_aes to FALSE
Related
I am trying to pass unquoted arguments to plotly(). If I call the column as-is (just the name), it works fine but if I try to pass the column name within a function like paste() it fails. It also works with negative numbers but not positive ones. In dplyr, I'd use curly-curly {{x}} without a problem but plotly() wants formulas to be passed so I'm a bit at a loss.
library(plotly)
library(tidyverse)
fn <- function(text, at_y) {
mpg |>
count(class) |>
plot_ly(x = ~class, y = ~n, type = "bar", color = I("grey")) |>
add_annotations(
text = enquo(text), # <---
y = enquo(at_y), # <---
showarrow = FALSE
)
}
# ok ----
fn(text = n, at_y = n)
fn(text = n, at_y = -1)
fn(text = -123, at_y = n)
# not ok ----
# positive integer
fn(text = n, at_y = 30)
#> Error in parent.env(x) : the empty environment has no parent
# used in a function
fn(text = paste("N=", n), at_y = n)
#> Error in paste("N=", n) :
#> cannot coerce type 'closure' to vector of type 'character'
As #MrFlick said in a comment, the rlang constructs used in tidyverse won't necessarily work in non-tidyverse packages. Here's a version of your function that does work, since it uses base methods to do the non-standard evaluation:
fn <- function(text, at_y) {
data <- mpg |> count(class)
at_y <- eval(substitute(at_y), data)
text <- eval(substitute(text), data)
data |>
plot_ly(x = ~class, y = ~n, type = "bar", color = I("grey")) |>
add_annotations(
text = text, # <---
y = at_y, # <---
showarrow = FALSE
)
}
You want to evaluate the expressions passed as text and at_y in the context of the tibble mpg |> count(class), and that's something that is done by the two lines calling substitute. This isn't identical to the rlang evaluation, but it's close enough.
I used plot_heatmap many times, but this is really unusual case.
https://rdrr.io/cran/RVA/man/plot_heatmap.cpm.html
I have two data frames:
annotation file = fact https://i.stack.imgur.com/CBQYZ.png
count data = dda_pca https://i.stack.imgur.com/67U9x.png
I run:
plot_heatmap.cpm(dda_pca, fact, ct.table.id.type="UNIPROT",title="DDA heatmap for PCA TOP-20",annot.flags = c("day","Treatment"),gene.count=20)
I have an error:
Error in dimnames(x) <- dn :
length of 'dimnames' [1] not equal to array extent
I checked traceback():
7: `rownames<-`(`*tmp*`, value = gene.display[, 2])
6: withCallingHandlers(expr, message = function(c) if (inherits(c,
classes)) tryInvokeRestart("muffleMessage"))
5: suppressMessages({
validate.geneid.flag(ct.table.id.type, "ct.table.id.type")
validate.geneid.flag(gene.id.type, "gene.id.type")
validate.flag(fill, "fill", c("CFB", "CPM"))
validate.flag(input.type, "input.type", c("count", "cpm"))
validate.annot(data, annot, annot.flags, sample.id, fill,
baseline.flag, baseline.val)
validate.data(data)
validate.data.annot(data, annot, sample.id)
user.title = title
if (input.type == "count") {
data <- cpm(data, log = TRUE) %>% as_tibble(rownames = "geneid")
}
else {
data <- data %>% as_tibble(rownames = "geneid")
}
data <- reformat.ensembl(data, ct.table.id.type)
if (!is.null(gene.names)) {
gene.names <- transform.geneid(gene.names, from = gene.id.type,
to = ct.table.id.type)
...
4: withCallingHandlers(expr, warning = function(w) if (inherits(w,
classes)) tryInvokeRestart("muffleWarning"))
3: suppressWarnings({
suppressMessages({
validate.geneid.flag(ct.table.id.type, "ct.table.id.type")
validate.geneid.flag(gene.id.type, "gene.id.type")
validate.flag(fill, "fill", c("CFB", "CPM"))
validate.flag(input.type, "input.type", c("count", "cpm"))
validate.annot(data, annot, annot.flags, sample.id, fill,
baseline.flag, baseline.val)
validate.data(data)
validate.data.annot(data, annot, sample.id)
user.title = title
if (input.type == "count") {
data <- cpm(data, log = TRUE) %>% as_tibble(rownames = "geneid")
}
else {
data <- data %>% as_tibble(rownames = "geneid")
}
data <- reformat.ensembl(data, ct.table.id.type)
if (!is.null(gene.names)) {
gene.names <- transform.geneid(gene.names, from = gene.id.type,
...
2: plot_heatmap.expr(cpm, annot, fill = "CPM", title = title, ...)
1: plot_heatmap.cpm(dda_pca, fact, ct.table.id.type = "UNIPROT",
title = "DDA heatmap for PCA TOP-20", annot.flags = c("day",
"Treatment"), gene.count = 20)
**I checked the correct
dimnames(dda_pca)[1]:
[1] "O15460" "P02511" "P08123" "P17096" "P17301" "P17931" "P21397" "P27658" "P35580" "P54289" "P62306" "P98179" "Q10472" "Q14315" "Q6UVK1" "Q92743"
[17] "Q96CX2" "Q9Y3Z3" "A2A3R5" "Q5JXI8"
I checked
> dim(dda_pca)
[1] 20 20
> dim(fact)
[1] 20 6
I don't understand what could be wrong with these dimnames as I used the same file structure and format before and see no difference. Please help me.
Thanks,
Ivan
P.S. The final result should look like this: https://i.stack.imgur.com/wyutb.png
files used: https://github.com/THERMOSTATS/RVA/issues/5
library(sjPlot)
I am using sjPlot to create quick xtabs:
sjPlot::tab_xtab(var.row = mtcars$mpg ,var.col =mtcars$wt ,show.row.prc = TRUE)
But since I am running it over many cols, I want to set up a loop:
cols <- names(mtcars)
for (i in cols) {
sjPlot::tab_xtab(
var.row = mtcars$mpg,
var.col = mtcars$i,
show.row.prc = TRUE
)
}
But this throws an error:
Error in table(x_full, grp_full) :
all arguments must have the same length
Why is this happening, and can someone please explain subsetting through iteration, or point me to a good resource?
FYI ---
This does not return anything.
for (i in cols) {
i <- 'cyl'
sjPlot::tab_xtab(
var.row = mtcars$mpg,
var.col = mtcars[[i]],
show.row.prc = TRUE
)
}
But this does return the chart for mpg - cyl:
for (i in cols) {
sjPlot::tab_xtab(
var.row = mtcars$mpg,
var.col = mtcars$cyl,
show.row.prc = TRUE
)
}
Thanks for the comments, this is the solution, but still looking for some understanding. Why mtcars[[i]] instead of mtars[i]? Why doesn't mrcars$i work?
for (i in cols) {
plt <- sjPlot::tab_xtab(
var.row = mtcars$mpg,
var.col = mtcars[[i]],
show.row.prc = TRUE
)
print(plt)
}
I would like to create a gt table where I display numeric values from two columns together in a single cell, but color the cells based on just one of the column's values.
For example using the ToothGrowth example data I'd like to put the len and dose columns together in a single cell but color the cell backgrounds by the value of dose.
I tried to manually create a vector of colors to color the len_dose column but this does not work because it seems like it is reapplying the color vector to each different level of len_dose, not dose. I guess you could manually format the cells with tab_style() but that seems inefficient and does not give you the nice feature where the text color changes to maximize contrast with background. I don't know an efficient way to do this.
What I tried:
library(gt)
library(dplyr)
library(scales)
library(glue)
# Manually map dose to color
dose_colors <- col_numeric(palette = 'Reds', domain = range(ToothGrowth$dose))(ToothGrowth$dose)
ToothGrowth %>%
mutate(len_dose = glue('{len}: ({dose})')) %>%
gt(rowname_col = 'supp') %>%
cols_hide(c(len, dose)) %>%
data_color(len_dose, colors = dose_colors)
Output (not good because not colored by dose):
Not sure if you found a solution to this yet but here is what I did:
If you use tab_style() you don't need to try and create the vector of colors and can instead set the background color you want based on the dose column. If you want to color values differently based on dose, in addition to what I've colored here, then create another tab_style() for the desired value.
library(gt)
library(dplyr)
library(scales)
library(glue)
ToothGrowth %>%
mutate(len_dose = glue('{len}: ({dose})')) %>%
gt(rowname_col = 'supp') %>%
tab_style(
style = cell_fill(color = "palegreen"),
location = cells_body(
columns = len_dose,
rows = dose >= 1.0
)
) %>%
cols_hide(c(len, dose))
I faced the same issue and adjusted the gt::data_color function to accept separate source and target columns - with that, the following should work to produce your desired output.
# Distinguish SOURCE_columns and TARGET_columns
my_data_color <- function (data, SOURCE_columns, TARGET_columns, colors, alpha = NULL, apply_to = c("fill",
"text"), autocolor_text = TRUE)
{
stop_if_not_gt(data = data)
apply_to <- match.arg(apply_to)
colors <- rlang::enquo(colors)
data_tbl <- dt_data_get(data = data)
colors <- rlang::eval_tidy(colors, data_tbl)
resolved_source_columns <- resolve_cols_c(expr = {
{
SOURCE_columns
}
}, data = data)
resolved_target_columns <- resolve_cols_c(expr = {
{
TARGET_columns
}
}, data = data)
rows <- seq_len(nrow(data_tbl))
data_color_styles_tbl <- dplyr::tibble(locname = character(0),
grpname = character(0), colname = character(0), locnum = numeric(0),
rownum = integer(0), colnum = integer(0), styles = list())
for (i in seq_along(resolved_source_columns)) {
data_vals <- data_tbl[[resolved_source_columns[i]]][rows]
if (inherits(colors, "character")) {
if (is.numeric(data_vals)) {
color_fn <- scales::col_numeric(palette = colors,
domain = data_vals, alpha = TRUE)
}
else if (is.character(data_vals) || is.factor(data_vals)) {
if (length(colors) > 1) {
nlvl <- if (is.factor(data_vals)) {
nlevels(data_vals)
}
else {
nlevels(factor(data_vals))
}
if (length(colors) > nlvl) {
colors <- colors[seq_len(nlvl)]
}
}
color_fn <- scales::col_factor(palette = colors,
domain = data_vals, alpha = TRUE)
}
else {
cli::cli_abort("Don't know how to map colors to a column of class {class(data_vals)[1]}.")
}
}
else if (inherits(colors, "function")) {
color_fn <- colors
}
else {
cli::cli_abort("The `colors` arg must be either a character vector of colors or a function.")
}
color_fn <- rlang::eval_tidy(color_fn, data_tbl)
color_vals <- color_fn(data_vals)
color_vals <- html_color(colors = color_vals, alpha = alpha)
color_styles <- switch(apply_to, fill = lapply(color_vals,
FUN = function(x) cell_fill(color = x)), text = lapply(color_vals,
FUN = function(x) cell_text(color = x)))
data_color_styles_tbl <- dplyr::bind_rows(data_color_styles_tbl,
generate_data_color_styles_tbl(column = resolved_target_columns[i], rows = rows,
color_styles = color_styles))
if (apply_to == "fill" && autocolor_text) {
color_vals <- ideal_fgnd_color(bgnd_color = color_vals)
color_styles <- lapply(color_vals, FUN = function(x) cell_text(color = x))
data_color_styles_tbl <- dplyr::bind_rows(data_color_styles_tbl,
generate_data_color_styles_tbl(column = resolved_target_columns[i],
rows = rows, color_styles = color_styles))
}
}
dt_styles_set(data = data, styles = dplyr::bind_rows(dt_styles_get(data = data),
data_color_styles_tbl))
}
# Add function into gt namespace (so that internal gt functions can be called)
library(gt)
tmpfun <- get("data_color", envir = asNamespace("gt"))
environment(my_data_color) <- environment(tmpfun)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
library(glue)
# Map dose to color
ToothGrowth %>%
mutate(len_dose = glue('{len}: ({dose})')) %>%
gt(rowname_col = 'supp') %>%
cols_hide(c(len, dose)) %>%
my_data_color(SOURCE_columns = "dose", TARGET_columns = "len_dose",
colors = scales::col_numeric(palette = c("red", "green"), domain = c(min(ToothGrowth$dose), max(ToothGrowth$dose))))
Created on 2022-11-03 with reprex v2.0.2
I am using RSSA package in R and I need to access the eigenvalues.
using the following code I can plot the components. However, I need to access all eigenvalues as numbers.
require(Rssa)
t=ssa(co2)
plot(t)
I know almost nothing about this package. I'm taking from context that you want the values that are plotted on the y-axis of that graphic. Lacking a reproducible example, I turn to the ?ssa help page and use the first example:
> s <- ssa(co2)
>
> plot(s)
So that looks like your plot: Then I look at the code
> getAnywhere(plot.ssa)
A single object matching ‘plot.ssa’ was found
It was found in the following places
registered S3 method for plot from namespace Rssa
namespace:Rssa
with value
function (x, type = c("values", "vectors", "paired", "series",
"wcor"), ..., vectors = c("eigen", "factor"), plot.contrib = TRUE,
numvalues = nsigma(x), numvectors = min(nsigma(x), 10), idx = 1:numvectors,
idy, groups)
{
type <- match.arg(type)
vectors <- match.arg(vectors)
if (identical(type, "values")) {
.plot.ssa.values(x, ..., numvalues = numvalues)
}
else if (identical(type, "vectors")) {
.plot.ssa.vectors(x, ..., what = vectors, plot.contrib = plot.contrib,
idx = idx)
}
else if (identical(type, "paired")) {
if (missing(idy))
idy <- idx + 1
.plot.ssa.paired(x, ..., what = vectors, plot.contrib = plot.contrib,
idx = idx, idy = idy)
}
else if (identical(type, "series")) {
if (missing(groups))
groups <- as.list(1:min(nsigma(x), nu(x)))
.plot.ssa.series(x, ..., groups = groups)
}
else if (identical(type, "wcor")) {
if (missing(groups))
groups <- as.list(1:min(nsigma(x), nu(x)))
plot(wcor(x, groups = groups), ...)
}
else {
stop("Unsupported type of SSA plot!")
}
}
<environment: namespace:Rssa>
So then I look at the function called when the default arguments are used:
> getAnywhere(.plot.ssa.values)
A single object matching ‘.plot.ssa.values’ was found
It was found in the following places
namespace:Rssa
with value
function (x, ..., numvalues, plot.type = "b")
{
dots <- list(...)
d <- data.frame(A = 1:numvalues, B = x$sigma[1:numvalues])
dots <- .defaults(dots, type = plot.type, xlab = "Index",
ylab = "norms", main = "Component norms", grid = TRUE,
scales = list(y = list(log = TRUE)), par.settings = list(plot.symbol = list(pch = 20)))
do.call("xyplot", c(list(x = B ~ A, data = d, ssaobj = x),
dots))
}
<environment: namespace:Rssa>
So the answer appears to be:
s$sigma
[1] 78886.190749 329.031810 327.198387 184.659743 88.695271 88.191805
[7] 52.380502 40.527875 31.329930 29.409384 27.157698 22.334446
[13] 17.237926 14.175096 14.111402 12.976716 12.943775 12.216524
[19] 11.830642 11.614243 11.226010 10.457529 10.435998 9.774000
[25] 9.710220 9.046872 8.995923 8.928725 8.809155 8.548962
[31] 8.358872 7.699094 7.266915 7.243014 7.164837 6.203210
[37] 6.085105 6.064150 6.035110 6.028446 5.845783 5.808865
[43] 5.770708 5.753422 5.680897 5.672330 5.650324 5.612606
[49] 5.599314 5.572931