repr icon indicating copy to clipboard operation
repr copied to clipboard

better stack traces (e.g. for plotting and help_files_with_topic)

Open jankatins opened this issue 9 years ago • 6 comments

This is what currently happens if a ggplot object raises an error:

library(ggplot2)
data <- data.frame(x = letters[1:5], y = runif(5))
ggplot(data, aes(x, y)) + geom_bar()
Error: stat_count() must not be used with a y aesthetic.
Traceback:

1. prepare_mimebundle(obj, .self$handle_display_error)
2. repr_text(obj)
3. repr_text.default(obj)
4. paste(capture.output(print(obj)), collapse = "\n")
5. capture.output(print(obj))
6. evalVis(expr)
7. withVisible(eval(expr, pf))
8. eval(expr, pf)
9. eval(expr, envir, enclos)
10. print(obj)
11. print.ggplot(obj)
12. ggplot_build(x)
13. by_layer(function(l, d) l$compute_statistic(d, panel))
14. f(l = layers[[i]], d = data[[i]])
15. l$compute_statistic(d, panel)
16. f(..., self = self)
17. self$stat$setup_params(data, self$stat_params)
18. f(...)
19. stop("stat_count() must not be used with a y aesthetic.", call. = FALSE)

It seems that ggplot plots are build by

returning a ggplot object -> repr_text.default does print -> evaluate registers a plot -> calls the handler for a plot.

IMO:

  • this shouldn't spit out a traceback
  • do not do a plot building in repr_text

So implement repr_xxx.ggplot (and other high level plotting libs)?

jankatins avatar Apr 19 '16 10:04 jankatins

Or ask for a repr_text.ggplot and repr_png.ggplot in ggplot itself?

jankatins avatar Apr 19 '16 10:04 jankatins

Or wrap the print in the repr_text.default in a tryCatch...

jankatins avatar Apr 19 '16 10:04 jankatins

This seems to be the easiest fix:

repr_text.default <- function(obj, ...) {
    tryCatch({
        paste(capture.output(print(obj)), collapse = '\n')
    }, error = function(e) paste("ERROR:", e))

}

But on my system, it still returns some plot, at least there is a big space below the error message.

jankatins avatar Apr 21 '16 16:04 jankatins

Yep, this is returned:

<body><div style="width: 504pt; height: 504pt;"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="504pt" height="504pt" viewBox="0 0 504 504" version="1.1" style="width: 100%; height: 100%;">
<g id="surface2">
</g>
</svg></div></body>

And a black plot picture if svg is removed...

knitr refuses to knit a document with that error (or, if I specify {r error=TRUE}, it also has a big space under the code), RStudio does not print anything...

IMO, the one workaround would be to specify all relevant repr_xxx.ggplot, but that wouldn't help us here: we would have to build the plot in repr_text to catch and display the error, so it's basically build the plot 3 instead of 2 times (repr_text, svg, png) and just display errors in repr_text :-(

The other workaround would be to somehow find out if a recorded plot is empty and then simple return NULL...

-> I will add a PR with only the above tryCatch workaround and then have a look if there is any way to catch the recordedplot stuff...

jankatins avatar Apr 21 '16 16:04 jankatins

This seems to be a way to test for empty recordedPlot objetcs:

> library(ggplot2)
> data <- data.frame(x = letters[1:5], y = runif(5))
> plot(1:10)
> full <- recordPlot()
> length(full[[1]])
[1] 8
> ggplot(data, aes(x, y)) + geom_point()
> full <- recordPlot()
> length(full[[1]])
[1] 3
> ggplot(data, aes(x, y)) + geom_bar()
Error: stat_count() must not be used with a y aesthetic.
> length(empty[[1]])
[1] 2

If the object passed to repr_xxx.recodedPlot(obj) has more than two things in obj[[1]], then it seems to be a legitimate plot... But I'm not sure that there are no plots with less than 3 things... seems to be a bit risky... But maybe someone else has a better test...

jankatins avatar Apr 21 '16 17:04 jankatins

I removed the 0.5 milestone as I think this is ok to release with until we have found a solution we all find agreeable :-)

further discussion in the PR #46

jankatins avatar Apr 22 '16 07:04 jankatins