grid_plot + tikzDevice + shared legend with latex mark up - r

I've been trying to follow this vignette on how to make a shared legend for multiple ggplot2. The given examples work perfectly as is, but in my case, I'm using tikzDevice to export a tikzpicture environment. The main problem seems to be that the widths of the legend keys are not correctly captured by grid_plot.
I came up with a minimal R code that reproduces the problem:
require(ggplot2)
require(grid)
require(gridExtra)
require(cowplot)
require(tikzDevice)
tikz(file = "./tmp.tex", width = 5.6, height = 2.2, standAlone = T )
mpg2 <- mpg
mpg2$cyl = as.factor(mpg2$cyl)
levels(mpg2$cyl) <- c("\\textbf{\\textsc{four}}",
"\\textbf{\\textsc{five}}",
"\\textbf{\\textsc{six}}",
"\\textbf{\\textsc{seven}}",
"\\textbf{\\textsc{eight}}")
plot.mpg <- ggplot(mpg2, aes(x=cty, colour=cyl, y = hwy)) +
geom_point() +
theme(legend.position='none')
legend <- get_legend(plot.mpg + theme(legend.position = "top"))
print(plot_grid(legend,
plot.mpg, nrow=2, ncol=1,align='h',
rel_heights = c(.1, 1)))
dev.off()
The generated PDF file (after compiling tmp.tex) looks like this:
As we can observe, first legend key (four) is only partially displayed and legend key (eight) is completely invisible. I tried changing tikz command width to no avail.
Also, I suspect that the reason behind the problem is that grid_plot command incorrectly measures the length of the legend keys if they contain latex mark up. To show that this is the cause of the problem, consider changing the levels of the mpg2$cyl to the following:
levels(mpg2$cyl) <- c("four",
"five",
"six",
"seven",
"eight")
This should result in the following plot with a perfect legend:
Please note that the example above is just meant to reproduce the problem and is not what I'm trying to do. Instead, I have four plots that I'm trying to use a shared common legend for them.
Anyone please can tell me how to fix the legend problem when it contains latex mark up?
By the way, here is my sessionInfo():
R version 3.3.2 (2016-10-31)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X Yosemite 10.10.5
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] grid stats graphics grDevices utils datasets methods
[8] base
other attached packages:
[1] tikzDevice_0.10-1 dplyr_0.5.0 gdata_2.17.0 cowplot_0.7.0
[5] gridExtra_2.2.1 ggplot2_2.2.0
loaded via a namespace (and not attached):
[1] gtools_3.5.0 colorspace_1.2-6 DBI_0.5 RColorBrewer_1.1-2
[5] plyr_1.8.4 munsell_0.4.3 gtable_0.2.0 labeling_0.3
[9] Rcpp_0.12.6 scales_0.4.1 filehash_2.3 digest_0.6.10
[13] tools_3.3.2 magrittr_1.5 lazyeval_0.2.0 tibble_1.1
[17] assertthat_0.1 R6_2.1.3
Thank you all.

ggplot2 appears to calculate the string widths based on the raw string as opposed to box sizes that should be returned by TeX. I'm guessing it's a calculation done too early (ie not at drawing time) in the guides code.
As a workaround you could edit the relevant widths manually in the gtable, by calling getLatexStrWidth explicitly. Note I also added a package in the preamble otherwise the default font doesn't show bold small caps.
require(ggplot2)
require(grid)
require(gridExtra)
require(tikzDevice)
setTikzDefaults(overwrite = TRUE)
preamble <- options("tikzLatexPackages")
options("tikzLatexPackages" = c(preamble$tikzLatexPackages, "\\usepackage{bold-extra}"))
tikz(file = "./tmp.tex", width = 5.6, height = 2.2, standAlone = TRUE )
mpg2 <- mpg
mpg2$cyl = as.factor(mpg2$cyl)
levels(mpg2$cyl) <- c("\\textbf{\\textsc{four}}",
"\\textbf{\\textsc{five}}",
"\\textbf{\\textsc{six}}",
"\\textbf{\\textsc{seven}}",
"\\textbf{\\textsc{eight}}")
p <- ggplot(mpg2, aes(x=cty, colour=cyl, y = hwy)) +
geom_point() +
theme(legend.position='none')
leg <- cowplot::get_legend(p + theme(legend.position = "top"))
ids <- grep("label",leg$grobs[[1]]$layout$name)
pos <- leg$grobs[[1]]$layout$l[ids]
wl <- sapply(leg$grobs[[1]][["grobs"]][ids], function(g) getLatexStrWidth(g[["label"]]))
leg$grobs[[1]][["widths"]][pos] <- unit(wl, "pt")
grid.arrange(p, top=leg)
dev.off()

Maybe it's easier to introduce a temporary markup that doesn't affect much the string width, and post-process the tex file between R and latex steps,
levels(mpg2$cyl) <- c("$four$",
"$five$",
"$six$",
"$seven$",
"$eight$")
[...]
tmp <- readLines("tmp.tex")
gs <- gsub("\\$(four|five|six|seven|eight)\\$", "\\\\textsc{\\1}", tmp, perl=TRUE)
cat(paste(gs, collapse="\n"), file="tmp2.tex")

Related

Other plots disappear when DataExplorer::plot_str() called

I have been using R and RStudio with base and ggplot for a couple of years. Lately, it seems that when some plots are generated, other plots are lost/deleted.
In RStudio, I use the "Plots" pane/tab, and the blue left and right arrows to view the plots that have been created. By disappears, I mean a plot was created and visible here, but if I use the arrows, I can't see it anymore. It was there, and it is not there anymore, it has "disappeared".
After running the code below using "Source" button, which does 3 plots, I can only see 2 plots. If I step through the code using Command-Return, I see the 3 plots generated, but then the middle one gets lost.
After doing more testing, I see for this code it is the call to:
DataExplorer::plot_str(mtcars)
that is the problem. If I comment that line and use another plot from DataExplorer like:
DataExplorer::plot_intro(mtcars)
all the plots are available after the script is complete.
I believe everything is using the latest versions:
mac os - 11.5.2
R - R version 4.1.1 (2021-08-10)
RStudio - RStudio 2021.09.0+351
R libraries - have just updated all the r libraries
Here is a simple base case that seems to recreate the issue. In the example below I am using the DataExplorer library, but I get similar stuff happening in Keras.
Code
########################### Start Initialisation ########################################################################################
# Remove objects from environment
rm(list = ls())
# Clear the R studio console
cat("\014")
# Clear all plots in R studio
try(dev.off(dev.list()["RStudioGD"]),silent<-TRUE)
try(dev.off(),silent<-TRUE)
# Load packages, installing first if not already installed
if (!require(DataExplorer)) {
install.packages("DataExplorer")
library(DataExplorer)
}
##################################
# Use base plotting to plot iris, this works
base::plot(iris, main="iris 1")
# Use DataExplorer::plot_str() to plot mtcars, this works, but then disappears
data("mtcars")
# DataExplorer::plot_str(mtcars) # This causes the problem
DataExplorer::plot_intro(mtcars) # This works
# This plot appears, but seems to cause the one above "mtcars" to disappear
base::plot(iris, main="iris 2")
sessionInfo()
Output:
> # Clear all plots in R studio
> try(dev.off(dev.list()["RStudioGD"]),silent<-TRUE)
null device
1
> try(dev.off(),silent<-TRUE)
> # Load packages, installing first if not already installed
> if (!require(DataExplorer)) {
+ install.packages("DataExplorer")
+ library(DataExpl .... [TRUNCATED]
> ##################################
>
> # Use base plotting to plot iris, this works
> base::plot(iris, main="iris 1")
> # Use DataExplorer::plot_str() to plot mtcars, this works, but then disappears
> data("mtcars")
> DataExplorer::plot_str(mtcars)
> # This plot appears but seems to cause the one above "mtcars" to disappear
> base::plot(iris, main="iris 2")
> sessionInfo()
R version 4.1.1 (2021-08-10)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Big Sur 11.5.2
Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib
locale:
[1] en_AU.UTF-8/en_AU.UTF-8/en_AU.UTF-8/C/en_AU.UTF-8/en_AU.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] DataExplorer_0.8.2
loaded via a namespace (and not attached):
[1] pillar_1.6.3 compiler_4.1.1 tools_4.1.1 digest_0.6.28 jsonlite_1.7.2 evaluate_0.14 lifecycle_1.0.1 tibble_3.1.4 gtable_0.3.0 pkgconfig_2.0.3
[11] rlang_0.4.11 igraph_1.2.6 DBI_1.1.1 yaml_2.2.1 parallel_4.1.1 xfun_0.26 fastmap_1.1.0 gridExtra_2.3 dplyr_1.0.7 knitr_1.36
[21] generics_0.1.0 vctrs_0.3.8 htmlwidgets_1.5.4 grid_4.1.1 tidyselect_1.1.1 glue_1.4.2 data.table_1.14.2 R6_2.5.1 fansi_0.5.0 rmarkdown_2.11
[31] ggplot2_3.3.5 purrr_0.3.4 magrittr_2.0.1 scales_1.1.1 ellipsis_0.3.2 htmltools_0.5.2 networkD3_0.4 assertthat_0.2.1 colorspace_2.0-2 utf8_1.2.2
[41] munsell_0.5.0 crayon_1.4.1
I thought perhaps the issue was due to mixing different plotting libraries, but the code below which draws 6 plots, 3 using base:plot() and 3 using ggplot2::ggplot() works and generates 6 plots that I can navigate through in RStudio using the blue left and right arrow buttons on the "Plots" pane/tab.
base::plot(mpg, main="mpg 1 - base")
ggplot2::ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point() +
ggtitle("mpg 1 - ggplot2")
base::plot(ToothGrowth, main="ToothGrowth 2 - base")
ggplot2::ggplot(ToothGrowth, aes(x=supp, y=len, fill=dose))+
geom_boxplot() +
ggtitle("ToothGrowth 2 - ggplot2")
base::plot(iris, main="iris 3 - base")
ggplot2::ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, fill=Species))+
geom_boxplot() +
ggtitle("iris 3 - ggplot2")
RStudio is:
RStudio 2021.09.0+351 "Ghost Orchid" Release (077589bcad3467ae79f318afe8641a1899a51606, 2021-09-20) for macOS
Mozilla/5.0 (Macintosh; Intel Mac OS X 11_5_2) AppleWebKit/537.36 (KHTML, like Gecko) QtWebEngine/5.12.10 Chrome/69.0.3497.128 Safari/537.36
Mac os version:
(base) % uname -a
Darwin xxxx.lan 20.6.0 Darwin Kernel Version 20.6.0: Wed Jun 23 00:26:31 PDT 2021; root:xnu-7195.141.2~5/RELEASE_X86_64 x86_64
(base) % sw_vers
ProductName: macOS
ProductVersion: 11.5.2
BuildVersion: 20G95
I think the reason is a simple one: you're not outputting a real plot (static).
DataExplorer::plot_intro(mtcars) is the problematic "plot" and the underlying code for this includes diagonalNetwork towards the end of the function:
DataExplorer
function (data, type = c("diagonal", "radial"), max_level = NULL,
print_network = TRUE, ...)
{
i <- idx <- parent <- NULL
str_output_raw <- capture.output(str(data, vec.len = 0, give.attr = FALSE,
give.length = FALSE, list.len = 2000000000L))
str_output <- unlist(lapply(str_output_raw, function(x) {
gsub(" \\.{2}\\#", "\\$\\#", x)
}))
n <- length(str_output)
base_split <- tstrsplit(str_output[2:n], "\\$")
nest_level <- (nchar(base_split[[1]]) - nchar(gsub(" \\.{2}",
"", base_split[[1]])))/3 + 1
diff_nl <- diff(nest_level)
s4_start_index <- which(diff_nl > 1L) + 1L
if (length(s4_start_index) > 0) {
s4_end_index <- which(diff_nl == -2L)
s4_index_range <- unique(unlist(lapply(s4_start_index,
function(i) {
seq.int(i, s4_end_index[which.min(abs(s4_end_index -
i))])
})))
nest_level[s4_index_range] <- nest_level[s4_index_range] -
1L
}
if (is.null(max_level)) {
max_level <- max(nest_level)
}
else if (max_level <= 0 | max_level > max(nest_level)) {
stop(paste0("max_level should be between 1 and ",
max(nest_level)))
}
else {
max_level <- max_level
}
comp_split <- tstrsplit(base_split[[2]], ":")
comp_root <- gsub(" ", "", comp_split[[1]])
comp_root[which(comp_root == "")] <- make.names(comp_root[which(comp_root ==
"")], unique = TRUE)
if (anyDuplicated(comp_root))
comp_root[which(duplicated(comp_root))] <- make.names(comp_root[which(duplicated(comp_root))],
unique = TRUE)
comp_output <- paste0(comp_root, " (", trimws(gsub("NULL|\\.{3}|\\.{2}",
"", comp_split[[2]])), ")")
str_dt <- data.table(idx = seq_along(nest_level), nest_level,
parent = comp_output)[nest_level <= max_level]
str_dt <- str_dt[str_dt[, list(i = idx, nest_level = nest_level -
1, child = parent)], on = list(nest_level, idx < i),
mult = "last"]
drop_columns(str_dt[is.na(parent), `:=`(parent, paste0("root (",
str_output[1], ")"))], c("idx", "nest_level"))
str_to_list <- function(str_dt, root_name = as.character(str_dt[["parent"]][1])) {
str_list <- list(name = root_name)
children <- str_dt[parent == root_name][["child"]]
if (length(children) > 0) {
str_list[["children"]] <- lapply(children,
str_to_list, str_dt = str_dt)
}
str_list
}
str_list <- str_to_list(str_dt)
if (print_network) {
type <- match.arg(type)
if (type == "diagonal")
print(diagonalNetwork(str_list, ...))
if (type == "radial")
print(radialNetwork(str_list, ...))
}
invisible(str_list)
}
where diagonalNetwork uses htmlwidgets:
function (List, height = NULL, width = NULL, fontSize = 10, fontFamily = "serif",
linkColour = "#ccc", nodeColour = "#fff", nodeStroke = "steelblue",
textColour = "#111", opacity = 0.9, margin = NULL)
{
if (!is.list(List))
stop("List must be a list object.")
root <- List
margin <- margin_handler(margin)
options = list(height = height, width = width, fontSize = fontSize,
fontFamily = fontFamily, linkColour = linkColour, nodeColour = nodeColour,
nodeStroke = nodeStroke, textColour = textColour, margin = margin,
opacity = opacity)
htmlwidgets::createWidget(name = "diagonalNetwork",
x = list(root = root, options = options), width = width,
height = height, htmlwidgets::sizingPolicy(padding = 10,
browser.fill = TRUE), package = "networkD3")
}
htmlwidgets is an interactive "plot" and opens under RStudio's viewer pane and not the static plots pane.

Error: Can't add ggsave to a ggplot object

I have set up a fresh R installation in a Windows 10 machine and can't run something as simple as:
data.frame(a = rnorm(100), b = rnorm(100)) |>
ggplot(aes(a, b)) +
ggsave("temp.png")
because I get the following error:
Error: Can't add `ggsave("temp.png")` to a ggplot object.
My session info is:
R version 4.1.0 (2021-05-18)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)
Matrix products: default
locale:
[1] LC_COLLATE=Catalan_Spain.1252 LC_CTYPE=Catalan_Spain.1252 LC_MONETARY=Catalan_Spain.1252 LC_NUMERIC=C
[5] LC_TIME=Catalan_Spain.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] ggplot2_3.3.4 dplyr_1.0.6
loaded via a namespace (and not attached):
[1] magrittr_2.0.1 tidyselect_1.1.1 munsell_0.5.0 colorspace_2.0-1 R6_2.5.0 rlang_0.4.11 fansi_0.5.0 tools_4.1.0
[9] grid_4.1.0 data.table_1.14.0 gtable_0.3.0 utf8_1.2.1 withr_2.4.2 ellipsis_0.3.2 digest_0.6.27 tibble_3.1.2
[17] lifecycle_1.0.0 crayon_1.4.1 purrr_0.3.4 farver_2.1.0 vctrs_0.3.8 glue_1.4.2 labeling_0.4.2 compiler_4.1.0
[25] pillar_1.6.1 generics_0.1.0 scales_1.1.1 pkgconfig_2.0.3
I have given permissions to the directory I'm working on and also tried in different directories and run with RScript, RStudio and Pycharm R Console, always with the same issue.
Thanks in advance.
EDIT: this used to work on ggplot2 3.3.3, it's the update to 3.3.4 that breaks things.
You can no longer "add" ggsave to a ggplot addition-pipe.
Edit: this is a recent change in ggplot2-3.3.4. The previous answer is preserved below if you want to work around the new behavior. If you're particular annoyed by it, you might submit a new issue to ggplot2 suggesting that they either (a) undo the breaking change, or (b) better document the change in unintended functionality.
Side note: the day after this answer was posted, commit 389b864 included the following text: "Note that, as a side effect, an unofficial hack <ggplot object> + ggsave() no longer works (#4513)."
(In truth, I don't recall seeing documentation that suggests that + ggsave(.) should work, so the response to a new issue might be that they do not want to preserve an unintended "feature" for the sake of giving up some other elegant completeness.)
The changes from 3.3.3 to 3.3.4 (for save.R) are mostly unrelated to the act of saving the file. However, one functional change is the return value from ggsave:
## -90,5 +98,5 ## ggsave <- function(filename, plot = last_plot(),
grid.draw(plot)
- invisible()
+ invisible(filename)
}
In retrospect, this makes sense: ggplot2's ability to use +-pipes tends to be okay with trying to add NULL-like objects. That is, this works without error:
data.frame(a = rnorm(100), b = rnorm(100)) |>
ggplot(aes(a, b)) +
NULL
Why is NULL relevant here? Because the previous (3.3.3) version of ggsave ends with invisible(), which is invisibly returning NULL. (Internally, ggplot2:::add_ggplot begins with if (is.null(object)) return(p), which explains why that works.)
With the change to invisible(filename) (which, imo, is actually a little better), however, this is effectively the same as
data.frame(a = rnorm(100), b = rnorm(100)) |>
ggplot(aes(a, b)) +
"temp.png"
which does not make sense, so the +-piping fails.
In ggplot2-3.3.3, one can replicate this error with a hack/ugly code:
data.frame(a = rnorm(100), b = rnorm(100)) |>
ggplot(aes(a, b)) +
{ ggsave("temp.png"); "temp.png"; }
# Error: Can't add `{` to a ggplot object.
# * Can't add ` ggsave("temp.png")` to a ggplot object.
# * Can't add ` "temp.png"` to a ggplot object.
# * Can't add `}` to a ggplot object.
which is close enough to the error you saw to (I believe) prove my point: the new-and-improved ggplot2-3.3.4 is returning a string, and that is different enough to break your habit-pattern of adding ggsave to a ggplot2 object.
If you're going to submit a new issue to ggplot2, then I suggest you frame it as a "feature request": if the invisible(filename) is instead a class object for which + works, then the previous behavior can be retained while still supporting the string-return. For example (completely untested):
ggsave <- function(file, ...) {
# .....
class(filename) <- c("ggplot2_string", "character")
invisible(filename)
}
and then extend the +.gg-logic to actually work for strings, perhaps something like
`+.gg` <- function (e1, e2) {
if (missing(e2)) {
abort("Cannot use `+.gg()` with a single argument. Did you accidentally put + on a new line?")
}
if (inherits(e2, "ggplot2_string")) {
e2 <- NULL
e2name <- "NULL"
} else {
e2name <- deparse(substitute(e2))
}
if (is.theme(e1))
add_theme(e1, e2, e2name)
else if (is.ggplot(e1))
add_ggplot(e1, e2, e2name)
else if (is.ggproto(e1)) {
abort("Cannot add ggproto objects together. Did you forget to add this object to a ggplot object?")
}
}
No, I don't think this is the best way, but it is one way, open for discussion.
Four things you can do:
Plot it, then save it. It will be displayed in your graphic device/pane.
data.frame(a = rnorm(100), b = rnorm(100)) |>
ggplot(aes(a, b))
ggsave("temp.png")
Save to an intermediate object without rendering, and save that:
gg <- data.frame(a = rnorm(100), b = rnorm(100)) |>
ggplot(aes(a, b))
ggsave("temp.png", plot = gg)
If R-4.1, pipe it do the plot= argument. While I don't have R-4.1 yet, based on comments I am led to believe that while |> will always pass the previous result as the next call's first argument, you can work around this by naming the file= argument, which means that R-4.1 will pass to the first available argument which (in this case) happens to be plot=, what we need.
data.frame(a = rnorm(100), b = rnorm(100)) |>
ggplot(aes(a, b)) |>
ggsave(file = "temp.png")
If you're using magrittr pipes, then you can do the same thing a little more succinctly:
library(magrittr) # or dplyr, if you're using it for other things
data.frame(a = rnorm(100), b = rnorm(100)) %>% # or |> here
ggplot(aes(a, b)) %>% # but not |> here
ggsave("temp.png", plot = .)
Just remove the plus sign.
data.frame(a = rnorm(100), b = rnorm(100)) |>
ggplot(aes(a, b))
ggsave("temp.png")
ggsave has a default input last_plot()
You could always define your own ggsave() function that restores the old behavior.
library(tidyverse)
ggsave <- function(...) {
ggplot2::ggsave(...)
invisible()
}
data.frame(a = rnorm(100), b = rnorm(100)) |>
ggplot(aes(a, b)) +
ggsave("temp.png")
#> Saving 7 x 5 in image
Created on 2021-06-17 by the reprex package (v1.0.0)
Note: I do not think this is a good idea. Just pointing out that it's possible.
I don't know if my setup differs from others in some way, or if it's just the way my ggsave code happens to be configured, but it still works for me, while also now kicking up the error.
In this, Thomas says:
First, while you’ll get an error in v3.3.4, the plot is actually saved
to a file since the error is thrown after the evaluation of ggsave().
This means that you can “fix” your code by putting the whole
expression in a try() block (please don’t do this though 😬)
But you don't have to do the try block. My code blocks are:
ggplot(stuff) +
ggsave(paste0(today(), "_PlotName", ".png"),
plot = last_plot(),
device = "png", path = "", scale = 3.5, width = 8,
height = 4, units = "in", dpi = 300, limitsize = TRUE)
Presumably specifying plot = last_plot() keeps things working. But don't tell anyone, in case they take it away ;)

knitr bookdown::gitbook and webgl: rotation does not work properly

I have the following Rmd file:
---
output: bookdown::gitbook
---
```{r include=FALSE}
rgl::setupKnitr()
```
```{r testing1,webgl=TRUE}
with(attitude,
car::scatter3d(x = rating, z = complaints, y = learning)
)
```
```{r testing2,webgl=TRUE}
with(attitude,
car::scatter3d(x = rating, z = complaints, y = learning)
)
```
When I knit this file, it produces and HTML file containing two, identical 3D interactive scatterplots. Both scatterplots look like they should, but the second scatterplot does not rotate properly. It will not rotate horizontally in depth correctly (eg, around the vertical axis).
In case it helps, you can find the HTML output of the knit here: https://www.dropbox.com/s/v3usmtes7n54t6q/Untitled.html.zip?dl=0
I have done all the following, none of which have fixed the problem:
Updated all packages with update.packages().
Installed the development version of bookdown.
Installed the development version of knitr.
Tried the solution here (didn't work): interactive 3D plots in markdown file - not working anymore?
I have noted the following:
If I change the output to html_document I do not have the problem (I'm debugging the problem in a bookdown::gitbook though, so that knowledge does not directly help me).
In the Firefox (77.0.1, 64-bit) javascript error console there is an error: TypeError: li[0] is undefined / plugin-bookdown.js:152:43 (which appears to have something to do with the table of contents and scrolling?)
Here is the output of sessionInfo():
> sessionInfo()
R version 4.0.0 (2020-04-24)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.5
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
locale:
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] bookdown_0.19.4 fansi_0.4.1 digest_0.6.25 crayon_1.3.4
[5] assertthat_0.2.1 evaluate_0.14 rlang_0.4.6 cli_2.0.2
[9] rstudioapi_0.11 rmarkdown_2.3 tools_4.0.0 glue_1.4.1
[13] xfun_0.14 yaml_2.2.1 rsconnect_0.8.16 compiler_4.0.0
[17] htmltools_0.5.0 knitr_1.28.7
In addition, here are the versions of some other relevant packages:
> installed.packages()[c("rgl","mgcv","car"),"Version"]
rgl mgcv car
"0.100.54" "1.8-31" "3.0-8"
Edit to add more detail
I have the same problem while using rgl::persp3d, so it isn't specific to car::scatter3d. The HTML from the Rmd file below uses only rgl but exhibits the same behavior.
---
output: bookdown::gitbook
---
```{r include=FALSE}
rgl::setupKnitr()
x <- seq(-10, 10, length = 30)
y <- x
f <- function(x, y) { r <- sqrt(x^2 + y^2); 10 * sin(r)/r }
z <- outer(x, y, f)
z[is.na(z)] <- 1
```
```{r testing1,webgl=TRUE}
rgl::persp3d(x, y, z, aspect = c(1, 1, 0.5), col = "lightblue",
xlab = "X", ylab = "Y", zlab = "Sinc( r )",
polygon_offset = 1)
```
```{r testing2,webgl=TRUE}
rgl::persp3d(x, y, z, aspect = c(1, 1, 0.5), col = "lightblue",
xlab = "X", ylab = "Y", zlab = "Sinc( r )",
polygon_offset = 1)
```
This turned out to be a bug in rgl, that was using an obsolete method to compute the location of mouse clicks relative to objects in scenes. It worked in an html_document, but not with bookdown::gitbook.
The development version (0.102.6) of rgl has fixed this, but it contains some really major changes, and a few other things are still broken by them: in particular using the webgl=TRUE chunk option. If you want to use the devel version, you should use explicit calls to rglwidget() in each chunk, or if you want to try out the new stuff, use rgl::setupKnitr(autoprint = TRUE) and just treat rgl graphics like base graphics, controlled by chunk options fig.keep etc.
Edited to add: version 0.102.7 fixes the known webgl=TRUE issue.

Error in grid.Call(L_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : polygon edge not found (new)

I know that the title of this question is a duplicate of this Question and this Question but the solutions over there don't work for me and the error message is (slightly) different:
Error in grid.Call(L_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
polygon edge not found
(note the missing part about the missing font)
I tried all suggestions that I found (updating / reinstalling all loaded graphic packages, ggplot2, GGally, and scales, reinitialising the Fonts on Mac OSX by starting in safe mode, moving the Fonts from /Fonts/ (Disabled) back into /Fonts...) but none of it resolved the problem.
The error seems to occure when I plot a ggplot graph with
scale_y_continuous(label=scientific_10)
where scientific_10 is defined as
scientific_10 <- function(x) {
parse(text = gsub("e", " %*% 10^", scientific_format()(x)))
}
Therefore the I suspect that the scales library has something to do with it.
The most puzzling is that the error only occurs each so-and-so many times, maybe each 3rd or 5th time i try to plot the same graph...
> sessionInfo()
R version 3.2.2 (2015-08-14)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X 10.9.5 (Mavericks)
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] gridExtra_2.0.0 scales_0.3.0 broom_0.4.0 tidyr_0.3.1 ggplot2_1.0.1 GGally_0.5.0 dplyr_0.4.3
loaded via a namespace (and not attached):
[1] Rcpp_0.11.5 magrittr_1.5 MASS_7.3-43 mnormt_1.5-1 munsell_0.4.2 colorspace_1.2-6 lattice_0.20-33 R6_2.0.1
[9] stringr_0.6.2 plyr_1.8.1 tools_3.2.2 parallel_3.2.2 grid_3.2.2 gtable_0.1.2 nlme_3.1-121 psych_1.5.8
[17] DBI_0.3.1 htmltools_0.2.6 lazyeval_0.1.10 yaml_2.1.13 assertthat_0.1 digest_0.6.8 reshape2_1.4.1 rmarkdown_0.8.1
[25] labeling_0.3 reshape_0.8.5 proto_0.3-10
traceback()
35: grid.Call(L_textBounds, as.graphicsAnnot(x$label), x$x, x$y,
resolveHJust(x$just, x$hjust), resolveVJust(x$just, x$vjust),
x$rot, 0)
34: widthDetails.text(x)
33: widthDetails(x)
32: (function (x)
{
widthDetails(x)
})(list(label = expression(5 %*% 10^+5, 7.5 %*% 10^+5, 1 %*%
10^+6, 1.25 %*% 10^+6, 1.5 %*% 10^+6), x = 1, y = c(0.0777214770341215,
0.291044141334423, 0.504366805634725, 0.717689469935027, 0.931012134235329
), just = "centre", hjust = 1, vjust = 0.5, rot = 0, check.overlap = FALSE,
name = "axis.text.y.text.8056", gp = list(fontsize = 9.6,
col = "black", fontfamily = "", lineheight = 0.9, font = 1L),
vp = NULL))
31: grid.Call.graphics(L_setviewport, vp, TRUE)
30: push.vp.viewport(X[[i]], ...)
I solved it by installing the library extrafont, installing a set of specific fonts and forcing ggplot to use only these fonts:
require(extrafont)
# need only do this once!
font_import(pattern="[A/a]rial", prompt=FALSE)
require(ggplot2)
# extending the help file example
df <- data.frame(gp = factor(rep(letters[1:3], each = 10)), y = rnorm(30))
ds <- plyr::ddply(df, "gp", plyr::summarise, mean = mean(y), sd = sd(y))
plotobj <- ggplot(df, aes(gp, y)) +
geom_point() +
geom_point(data = ds, aes(y = mean), colour = 'red', size = 3) +
theme(text=element_text(size=16, family="Arial"))
print(plotobj)
I experienced the same issue when trying to plot ggplot/grid output to the graph window in Rstudio. However, plotting to an external graphing device seems to work fine.
The external device of choice depends on your system, but the script below, paraphrased from this blog, works for most systems:
a = switch(tolower(Sys.info()["sysname"]),
"darwin" = "quartz",
"linux" = "x11",
"windows" = "windows")
options("device" = a)
graphics.off()
rm(a)
and to switch back to using the Rstudio plot window:
options("device"="RStudioGD")
graphics.off()
Note that by switching, you lose any existing plots.
A lot of solutions for this particular error direct you to look under the hood of your computer but this error can also be caused by a scripting error in which R expects to match elements from two data structures but cannot.
For me the error was caused by calling a fairly complex graphing function (see below) that read an ordered character vector as well as a matrix whose row names were supposed to each match a value in the ordered character vector. The problem was that some of my values contained dashes in them and R's read.table() function translated those dashes to periods (Ex: "HLA-DOA" became "HLA.DOA").
I was using the ComplexHeatmap package with a call like this:
oncoPrint(mat,
get_type = function(x) strsplit(x, ";")[[1]],
alter_fun_list = alter_fun_list,
col = col,
row_order = my_order,
column_title = "OncoPrint",
heatmap_legend_param = list(title = "Alternations", at = c("AMP", "HOMDEL", "MUT"), labels = c("Amplification", "Deep deletion", "Mutation"))
)
In this call:
mat was a matrix that had dashes swapped out for periods
my_order was a character vector containing the same values as the row names of matexcept the dashes remained
every other argument is essential to the call but irrelevant to this post
To help R find this elusive "polygon edge", I just edited my character vector with:
row_order <- gsub("\\.", "-", row_order)
If you've tried re-installing packages, restarting your computer and re-enabling fonts - maybe check and see if you've got some faulty character matching going on in your call.
i tried to set the font of aes,returned the error info
the added words:
p <- p + theme(text = element_text(family = "宋体"))
when i tried to remove the setting,it's ok then.
Actually, I have the same problem on my MAC and couldn't solve it on a regular base... Since it also happens like every 5th or 10th execution I decided to wrap the whole ggplot command into a trycatch call and execute it until it doesn't fail...
The code would looks like this
error_appeared <- FALSE
repeat{
tryCatch({ # we put everything into a try catch block, because sometimes we get an error
gscat <-
ggplot() # my ggplot command which sometimes fail
ggsave('file.pdf', gscat, width=8,height=8)
plot(gscat)
},
error=function(e) {
print('redo the ratioscatterplot.')
error_appeared <- TRUE
}
)
if(!error_appeared){
break
}
}
Actually I figured out, only the drawing/plotting of the figure gives problems! Saving always works.
Maybe this is helping someone, since I couldn't find a solution which actually solves the whole thing!
Additional:
If somebody wants to play with the problem on a "reproducible example" the code below throws an average of 2 errors out of 20 within the loop.
library(scales)
library(ggplot2)
df <- data.frame(
log2.Ratio.H.L.normalized.rev = c(2.53861265542646, 0.402176424979483, 0.438931541934545, 0.639695233399582, 0.230203013366421,
2.88223218956399, 1.23051046036618, 2.56554843533357, 0.265436896049098,
1.32866415755805, -0.92108963514092, 0.0976107966264223, -0.43048946484291,
-0.558665259531966, 4.13183638727079, 0.904580434921318, -0.0733780789564803,
-0.621932351219966, 1.48594198341242, -0.365611185917855, 1.21088754922081,
-2.3717583289898, 2.95160644380282, 3.71446534016249),
Intensity = c(5951600000, 2.4433e+10, 1.1659e+10, 2273600000, 6.852e+10, 9.8746e+10, 5701600000,
1758500000, 987180000, 3.4167e+11, 1.5718e+10, 6.8888e+10, 5.5936e+10,
8702900000, 1093500000, 4426200000, 1.3681e+11, 7.773e+09, 5860400000,
1.2861e+12, 2017900000, 2061300000, 240520000, 1382700000),
my_label = c("RPL18",
"hCG_2024613", "NOL7", "PRPF4B", "HIST1H2BC", "XRCC1", "C9orf30",
"CABIN1", "MGC3731", "XRCC6", "RPL23", "RPL27", "RPL17", "RPL32",
"XPC", "RPL15", "GNL3", "RPL29", "JOSD3", "PARP1", "DNAPTP6",
"ORC2L", "NCL", "TARDBP"))
unlink("figures", recursive=TRUE)
if(!dir.exists('figures')) dir.create('figures')
for(i in 1:20) {
error_appeared <- FALSE
repeat{
tryCatch({ # we put everything into a try catch block, because sometimes we get an error
gscat <-
ggplot(df, aes_string("log2.Ratio.H.L.normalized.rev", 'Intensity')) +
geom_point(data=df[abs(df[["log2.Ratio.H.L.normalized.rev"]]) < 1,],
color='black', alpha=.3, na.rm=TRUE) +
scale_y_log10(labels = scales::trans_format("log10", scales::math_format()))
ggsave(file.path('figures', paste0('intensity_scatter_', i, '.pdf')),
gscat, width=8, height=8)
plot(gscat)
},
error=function(e) {
# print(e)
print(sprintf('%s redo the ratioscatterplot.', i))
error_appeared <- TRUE
}
)
if(!error_appeared){
break
}
}
}

R programming ggvis histogram verses hist - How to size the buckets, and define X axis spacing (ticks)

I am learning to use ggvis and wanted to understand how to create the equivalent histogram to that produced by hist. Specifically, how do you set the bin widths and upper and lower bounds of x in ggvis histograms? What am I missing?
Question: How do I get the ggvis histogram output to match the hist output?
Let me provide an example:
require(psych)
require(RCurl)
require(ggvis)
if ( !exists("impact") ) {
url <- "https://dl.dropboxusercontent.com/u/8272421/stat/stat_one.txt"
myCsv <- getURL(url, ssl.verifypeer = FALSE)
impact <- read.csv(textConnection(myCsv), sep = "\t")
impact$subject <- factor(impact$subject)
}
describe(impact)
hist(impact$verbal_memory_baseline,
main = "Distribution of verbal memory baseline scores",
xlab = "score", ylab = "frequency")
Ok, lets try and reproduce with ggvis... the output does not match...
impact %>%
ggvis( x = ~verbal_memory_baseline, fill := "white") %>%
layer_histograms(width = 5) %>%
add_axis("x", title = "score") %>%
add_axis("y", title = "frequency")
How do I get the ggvis output to match the hist output?
> sessionInfo()
R version 3.2.2 (2015-08-14)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X 10.11.2 (El Capitan)
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] psych_1.5.6 knitr_1.11 ggvis_0.4.2.9000 setwidth_1.0-4 colorout_1.1-1 vimcom_1.2-3
loaded via a namespace (and not attached):
[1] Rcpp_0.12.0 digest_0.6.8 dplyr_0.4.3.9000 assertthat_0.1 mime_0.3
[6] R6_2.1.1 jsonlite_0.9.16 xtable_1.7-4 DBI_0.3.1 magrittr_1.5
[11] lazyeval_0.1.10.9000 rstudioapi_0.3.1 rmarkdown_0.7 tools_3.2.2 shiny_0.12.2
[16] httpuv_1.3.3 yaml_2.1.13 parallel_3.2.2 rsconnect_0.4.1.4 mnormt_1.5-3
[21] htmltools_0.2.6
Try
impact %>%
ggvis( x = ~verbal_memory_baseline, fill := "white") %>%
layer_histograms(width = 5, boundary = 5) %>%
add_axis("y", title = "frequency") %>%
add_axis("x", title = "score", ticks = 5)
Which gives:
The official documentation is a bit cryptic about how boundary and center works. Have a look at DataCamp's How to Make a Histogram with ggvis in R
The width argument already set the bin width to 5, but where do bins
start and where do they end? You can use the center or boundary
argument for this. center should refer to one of the bins’ center
value, which automatically determines the other bins location. The
boundary argument specifies the boundary value of one of the bins.
Here again, specifying a single value fixes the location of all bins.
As these two arguments specify the same thing in a different way, you
should set at most one of center or boundary.
If you want the same result using center instead of boundary try:
impact %>%
ggvis( x = ~verbal_memory_baseline, fill := "white") %>%
layer_histograms(width = 5, center = 77.5) %>%
add_axis("y", title = "frequency") %>%
add_axis("x", title = "score", ticks = 5)
Here you specify the center of a bin (77.5) and it determines all the others automatically
Stevens answer is correct.
Having his pointers allowed me to read the documentation much more deeply:
layer_histograms():
http://www.rdocumentation.org/packages/ggvis/functions/layer_histograms
Boundary
A boundary between two bins. As with center, things are shifted when
boundary is outside the range of the data. For example, to center on
integers, use width = 1 and boundary = 0.5, even if 1 is outside the
range of the data. At most one of center and boundary may be
specified.
add_axis()
http://www.rdocumentation.org/packages/ggvis/functions/add_axis
ticks
A desired number of ticks. The resulting number may be different so
that values are "nice" (multiples of 2, 5, 10) and lie within the
underlying scale's range.

Resources