Change how RStudio environment pane describes variables

Is it possible to change the way the RStudio environment pane displays the value of variables?

My specific use case is that I am working with the units package. For anyone not familiar with it, units allows you to assign units to variables and will perform unit conversion and so on when you perform operations on the variables.

An example:

library(units)
distance_travelled <- units::set_units(100, m)
time_taken <- units::set_units(30, s)
average_speed <- distance_travelled / time_taken
average_speed

average_speed prints to the console as 3.333333 [m/s]. However, in the RStudio environment pane it just displays the variable name and Object of class units. Is there a way of overriding the default behaviour so the environment pane displays the units and value?

Here's a screenshot for reference.

I'm using Rstudio server 1.2.5033 via the Docker image rocker/tidyverse.

Any tips would be much appreciated!

1 Like

RStudio uses the output of str() for what it chooses to display in the Environment pane. One solution would be to implement a method for str() that displays something more appropriate for RStudio.

Alternatively, you might consider filing a feature request asking whether we could improve on the display for variables in the Environment pane.

Hi @kevinushey, many thanks for your reply.

Creating a new str.units() method worked perfectly, although I had to Install and Restart via the Build pane in RStudio (rather than using devtools::load_all()) for the environment pane to use it, which confused me for a while.

I implemented a new str.units() method, shown below. This borrows from the current print.units() method here: units/R/summaries.R at main · r-quantities/units · GitHub.

str.units <- function(object) {
  gr <- units_options("group")
  unit_string <- paste0(gr[1], as.character(attr(object, "units")), gr[2])
  str_default <- capture.output(str(unclass(object)))
  cat(paste(unit_string, str_default[1], "\n"))
}

As you can see my earlier example now looks just how I wanted...

There are improvements you could make from here but this is enough for my purposes.

Two points I think are worth flagging for anyone else going down this route:

  1. Use cat() rather than print() or return() from your custom function. Poking around with capture.output(str(x)) was helpful as this is what RStudio uses internally (as far as I can tell) - in my case I only wanted the first line.
  2. Use Install and Restart in RStudio to see the changes, otherwise your new function won't be used.

Hopefully this will be useful for someone else in future, thanks again @kevinushey for your help.

2 Likes

Hi @kevinushey, I wonder if you could help with a follow-up on this? I am working on adding this new S3 method to the units package and am not able to get past one point:

units contains an S3 class mixed_units which is a modified list. When a mixed_units object is constructed the list class is overwritten, but R still identifies it as a list:

library(units)
mix <- units::mixed_units(1:5, c("s", "m", "cd", "kg", "lb"))

class(mix)
## "mixed_units"

inherits(mix, "list")
## FALSE

is.list(mix)
## TRUE

The new S3 str.mixed_units() method gives the output I want in the terminal, but not in the RStudio environment pane (see screenshot). In the screenshot below I would like the environment pane to display Mixed units: cd (1), kg (1), lb (1), m (1), s (1) instead of List of 5. The display for column b of the dataframe gives you an idea of what I'm trying to achieve.

I assume this is something to do with the fact that the object is still a list, but it would be good to understand why things are treated differently when the list is its own object vs when it is a list col in a data frame. Any pointers would be much appreciated.

Thanks, Lewin

P.S. This is the current function definition:

str.mixed_units = function(x, ...) {
  tbl <- table(as.character(units(x)))
  tbl <- paste(names(tbl), " (", as.numeric(tbl), ")", sep = "")
  tbl_str <- paste(tbl, collapse = ", ")
  file <- textConnection("rval", "w", local = TRUE)
  sink(file)
  on.exit(sink())
  NextMethod()
  sink()
  on.exit()
  cat(" Mixed units:", tbl_str, "\n")
  cat(rval[2:length(rval)], sep = "\n")
}
1 Like

I would also be interested in additional information or any suggestions here. I am seeing the same issue @lewinfox describes with a list-based S3 object.