New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for displaying plots and help files in VS Code IDE #51
Comments
@iainmstott Thank you for using and issue! |
Maybe the new webview API can be used for displaying plots: https://code.visualstudio.com/docs/extensions/webview |
@issuehuntfest has funded $40.00 to this issue. See it on IssueHunt |
Without plotting capabilities, unfortunately |
Hi @nlneas1, for me functions like What happens when you run the following line of code?
If nothing appears at all, it may be a bug. In that case, could you let me know your OS, VSCode version and vscode-R version? |
There is an issue open for adding support for other languages to the (very good) Jupyter component of the Python extension. This would allow display of images and help within the VSCode window, although it would be more like a Jupyter notebook than RStudio. If this sounds good to you, please consider voting for R support here: Thank you! |
Yeah that definitely doesn't happen for me.
The VSCode extensions I have installed right now are:
It might be important to note that I am remote accessing a Linux machine (CentOS) using the Microsoft Remotes extension. |
@nlneas1 That does sound like a bug then. Thank you for all the version details - I've copied them to a new issue. I suspect the remote access aspect is probably central to the problem. |
I’ve had a bit of a look at how the Julia extension handles plotting. I think it starts the REPL in a socket server. If a message returned from the server is a plot instruction, then it renders it in a webview. The relevant file: Currently R Interactive terminals simply launch R in a terminal, so implementing plotting as the Julia extension does would require introducing a socket server. If anyone has thoughts on other possible ways of introducing plotting within the VSCode window, please post. |
If vscode-R has to start R session itself for interprocess communication, then user-manageable R sessions (in any screen or tmux window) will probably be compromised. I'm wondering if we could add task callback functions to let user started R session to communicate with vscode-R so that plots, global variable updates (in environment pane), etc. could be handled without sending command to the R session. This task callback function will be called each time user evaluated an expression in the global level. addTaskCallback(function(...) {
# tell vscode-R a global expression is evaluated
# update global variables using ls(globalenv())
# check if some graphics device is open,
# and use altered default device made easier to communite with vscode-R,
# or copy device contents to a file,
# tell vscode-R a plot is created or updated.
# some other tasks
}, name = "handler") Then vscode-R should listen or read file and respond to this global task handler. I'm doing some experiement with this and see if this idea works. |
@renkun-ken I was imagining a socket server approach only applying to the R Interactive sessions that vscode-R creates by default, with user-manageable R sessions being left as-is. (My normal workflow involves Radian in user-managed sessions so I definitely don't want to negatively affect that functionality.) It sounds like you're thinking about an approach that would also work for user-managed sessions? That would be great! Very interested to hear how your experiments go. |
I can not find much documentation about this, but we could also try to implement a R graphics device: https://bookdown.org/rdpeng/exdata/graphics-devices.html People have implemented some as packages: https://www.stat.auckland.ac.nz/~paul/R/devices.html The graphics device could send something like SVG over http to vscode. |
The tricky part of a graphics device is that only screen devices such as An initial attempt is to add the following to if (interactive()) {
local({
dir <- file.path("~", ".vscode-R", Sys.getpid())
dir.create(dir, showWarnings = FALSE, recursive = TRUE, mode = "0700")
reg.finalizer(globalenv(), function(e) {
unlink(dir, recursive = TRUE, force = TRUE)
}, onexit = TRUE)
session_file <- file.path(dir, "session")
cat(utils::capture.output(sessionInfo()), sep = "\n", file = session_file)
info_file <- file.path(dir, "pwd")
cat(getwd(), file = info_file)
plot_file <- file.path(dir, "plot.png")
options(device = function(...) {
png(filename = plot_file, ...)
})
addTaskCallback(function(expr, value, ok, visible) {
env_file <- file.path(dir, "globalenv")
cat(utils::capture.output(ls.str(globalenv())), sep = "\n", file = env_file)
TRUE
}, name = "vscode-R")
})
} so that each R session creates a subdirectory named by User can choose which session to attach in vscode-R and show the plot graphics and global environment variables, etc. This is a rather passive approach for vscode-R to work with active R sessions by maintaining the capability of user-manageable sessions anywhere in screen or tmux, and customized R terminal (original or radian) and without too much intrusive actions in R. |
@renkun-ken Wow, this is really nice! If I’m following correctly, the next step would be to have VSCode watch the contents of @nx10 Thank you for having a look into the problem as well! I suppose that a custom graphics device might be a way of seeing intermediate plot output? For now, a plot window that updates only on |
@andycraig That's exactly what I'm suggesting. The known issues are:
|
@renkun-ken For the cleanup problem, we could probably do it in vscode-R’s It would be fine to replace the current Excel Viewer with a different approach if it worked better for remote development. (I’ve never done remote work with VSCode so I don’t know much about that topic.) |
I do remote work with VSCode everyday so I'd be happy to test once implemented. |
I just went through the RStudio code and found their c++ implementation of a graphics device which is licensed AGPL v3. Could this be modified to use in vscode-R? https://github.com/rstudio/rstudio/tree/master/src/cpp/r/session/graphics |
@nx10 Interesting! I’m not sure if VSCode extensions can include C++ code. They might be able to, but I’m not sure. I believe using AGPL code would require changing the license of vscode-R to AGPL, so if you’re thinking about having a try at this approach I would make sure that @Ikuyadeu is happy with that. |
@nx10 License is now AGPL, so no obstacle there. |
The licensing change is a shame due to the virality of AGPL. This disallows usage at many organizations due to the risk of contaminating licenses for other software. See this AGPL Policy page at Google for an example. I'd also like to state a personal opinion that a license change is not a minor change in a project, and should have been accompanied with a major release. |
I think I find a way to output intermediate graphics (thanks for the introduction of options(device = function(...) {
pdf(NULL, bg = "white")
dev.control(displaylist = "enable")
})
addTaskCallback(function(...) {
if (dev.cur() > 1 && !dev.interactive()) {
record <- recordPlot()
if (length(record[[1]])) {
png("plot.png")
on.exit(dev.off())
replayPlot(record)
}
}
TRUE
}) With this, user won't have to |
@renkun-ken That is a really nice solution! |
Just a note that the vscode-R license is MIT again. |
The drawback of my code is that if a heavy plot is produced (e.g. It seems that all graphics operations calls I tried using trace(".External.graphics", exit = function() {
plot_updated <<- TRUE
}, print = FALSE) which works but if user calls Then we might need a hard injection to this primitive function. Following are my updates of the plot replay code: plot_updated <- FALSE
options(device = function(...) {
pdf(NULL, bg = "white")
dev.control(displaylist = "enable")
})
setHook("plot.new", function(...) {
plot_updated <<- TRUE
})
unlockBinding(".External.graphics", baseenv())
assign(".External.graphics", function(...) {
plot_updated <<- TRUE
.prim <- .Primitive(".External.graphics")
.prim(...)
}, baseenv())
lockBinding(".External.graphics", baseenv())
addTaskCallback(function(...) {
if (dev.cur() == 2L && plot_updated) {
plot_updated <<- FALSE
record <- recordPlot()
if (length(record[[1]])) {
png("plot.png")
on.exit(dev.off())
replayPlot(record)
}
}
TRUE
}) which hacks |
Thanks, Thanks, HM |
@hmassalha, please take a look at #150. I'm trying to continue the great pioneer work of @andycraig by implementing a complete solution for this. I've been already using it in my work and I'm trying to improve it gradually. |
With R session watcher enabled, using |
Great work on this, thank you!
One thing I find useful is to see plots and help documents in the IDE (both RStudio and R Tools for Visual Studio offer this). It would be great to have the same thing for R in VS Code.
The julia-vscode and pythonVSCode extensions both include plot panes within VS Code itself, which I guess means it's possible.
Thanks
The text was updated successfully, but these errors were encountered: