Customizing general objects formatting output

When using Rmd format in the IDE and a dataset is evaluated it creates custom output. For example evaluating

cars

creates a paged table view.

My question is can this functionality be extended to custom objects, such as those passed through C++? It appears there is some sort of html magic to print the data frame as it eventually ends up as a div with class "pagedtable", but I cannot replicate it. Is there an R method to implement for objects other than data.frames to have an html object or widget returned to represent the object different from what the console would print?

I am not sure I'm really answering your question, but hopefully I can point you to some useful documentation.

This table is generated by the rmarkdown::print.paged_df function which creates a pageable HTML table.

You might also consider other table options, Output Nice-Looking Formatted Tables

I'm looking at trying to have custom output in the interactive session but have the printing sensitive to where it is being printed at. I have gathered that when code is evaluated from a code chuck it is handled differently than code evaluated directly in the console.

When I evaluate rmarkdown:::print.paged_df(iris) from a code chuck I get no output. But when I run

x <- rmarkdown:::print.paged_df(iris)
class(x)
unclass(x)

I get the output:

[1] "knit_asis"
[1] "<div data-pagedtable=\"false\">\n  <script data-pagedtable-source type=\"application/json\">\n{\"columns\":[{\"label\":[\"Sepal.Length\"],\"name\":[1],

Truncated for space

attr(,"knit_meta")
attr(,"knit_meta")$dependencies
List of 10
 $ name      : chr "pagedtable"
 $ version   : chr "1.1"
 $ src       :List of 1
  ..$ file: chr "/usr/local/lib/R/site-library/rmarkdown/rmd/h/pagedtable-1.1"
 $ meta      : NULL
 $ script    : chr "js/pagedtable.js"
 $ stylesheet: chr "css/pagedtable.css"
 $ head      : NULL
 $ attachment: NULL
 $ package   : NULL
 $ all_files : logi TRUE
 - attr(*, "class")= chr "html_dependency"

attr(,"knit_cacheable")
[1] NA

From what I gather in the code Rstudio registers data capture overrides for certain classes of object; data.frame, tbl_df, etcetera. Then uses these functions to return an object, options and meta information that is then used to format the data into an HTML widget, that is then incorporated into the R notebook. But this is different than if you directly evaluated a widget such as the example from the htmlwidgets [Introduction vignette]:frowning:Introduction to HTML Widgets)

library(sigma)
sigma(system.file("examples/ediaspora.gexf.xml", package = "sigma"))

There is clearly some polymorphic behavior for the print method depending on where it is being printed, console or notebook. From examining the code, there does not appear to be a straightforward way to add an override method for printing when returned to the notebook, such as returning an HTML widget, unless I am missing something. Is there an approved of way to implement this location dependent print functionality?

If not, is there an official way to detect that output is being directed to be returned to RStudio as opposed to the Console? I think that I can hack a way but an official api function would be preferred.

1 Like

I'm not an IDE developer, so definitely take this with a grain of salt, but here are some possible points of interest in the source code (all of which is available in the rstudio github repo)

Don't know if these are necessarily what you're looking for, but possible places to start.

1 Like

I think that the way it is currently structured there is an enumerated hardcoded list of types for which the print functions are overridden each time a call is evaluated from the notebook. There does not appear to be a way to add a type to be handled specially. It looks like the route is to create a function that returns TRUE when evaluated in Rstudio and FALSE otherwise. This is the hack that I came up with.

rs_has_overrides <- function(){
    length(as.environment("tools:rstudio")$.rs.S3Overrides) > 0L
}

Which so far works. This as a conditional in my print.* function to then create and print the corresponding html should get me what I need.

As an aside I will mention that a more elegant and less error prone solution might be to add a function that handles all printing for rstudio, similar to what is done in knitr with knit_print.

rstudio_print <- function(x, ...)UseMethod("rstudio_print")
rstudio_print.default <- function(x, ...)UseMethod("print")
rstudio_print.myclass <- function(x, ...){
    # the customized methods would actually call the functions to register
    # the html output, widgets, plots, etc. to be incorporated into the 
    # Rmd Notebook.
    base::print(div("printing from ", code("rstudio_print"), "function."))
    invisible(x)
}

Even better one could override the base print method with something like

print <- function(x, ...){
    method <- getOption("print.method", "print")
    UseMethod(method, x)
}

Then those that capture and direct output to other places could set

options(print.method = "rstudio_print")

Then if

x <- structure(1L, class="myclass")
print(x)

is called from RStudio it produces

printing from rstudio_print function.

Otherwise it would produce the default print method for the object. However it appears that this approach must be implemented at a level above the global environment as just defining this but evaluating

x

still returns the results from the base:print.

[1] 1
attr(,"class")
[1] "myclass"
1 Like