When printing a tibble, how do I print the cells with nested data types (in list columns)? Let's have a look at two examples:
1. call data type
b <- tibble(a = 1, prior = list(call("rnorm", quote(N), mean = 0, sd = 2)))
b
which prints
# A tibble: 1 × 2
a prior
<dbl> <list>
1 1 <language>
How do I get expanded printing of the call, to get output like this? :
# A tibble: 1 × 2
a prior
<dbl> <list>
1 1 rnorm(N, mean = 0, sd = 2)
The call already has its own simple print method (print(b$prior[[1]]) will print this cell correctly), so how to tell tibble's print method to do that?
2. list data type
Say I have tibble with lists in cells:
a <- tibble(id = 1:2, data = list(list(x = 1, y = 2), list(a = 3, b = 4)))
it prints like this:
# A tibble: 2 × 2
id data
<int> <list>
1 1 <named list [2]>
2 2 <named list [2]>
how do I print it in a dput() style like this? :
# A tibble: 2 × 2
id data
<int> <list>
1 1 list(x = 1, y = 2)
2 2 list(a = 3, b = 4)
PS: I am not interested to transform these tibble tables into a different ones that will print like this... (e.g. by converting the nested columns to character vector) - that is trival but clumsy solution. I want to be able to simply print my object while I am working with it, without converting it to another one just for the printing. I am still hoping that the tibble system somehow allows to tweak printing of these columns.
The tidyverse uses pillar under the hood for printing. I would prefer not to override the default printing methods for tibbles or for lists. This gives you two options. Let's create some data with both column types in first, and some normal lists we don't want to be affected:
dat <- tibble(
id = 1:2,
data = list(list(x = 1, y = 2), list(a = 3, b = 4)),
prior = list(call("rnorm", quote(N), mean = 0, sd = 2), call("rnorm", quote(N), mean = 1, sd = 4)),
normal_int_list = list(1, 2),
normal_char_list = list("A", "B")
)
Here are your options:
Create a method for pillar::ctl_new_pillar(), defining your own print function for lists. The method will move on to the default NextMethod() for all other column types.
ctl_new_pillar.nice_list_tbl <- function(controller, x, width, ..., title = NULL) {
if (!is.list(x)) { # might want to add &!is.data.frame(x) etc.
return(NextMethod())
}
pillar::new_pillar(list(
title = pillar::pillar_component(pillar::new_pillar_title(title)),
type = pillar::new_pillar_component(list("<list>"), width = 6),
data = pillar::new_pillar_shaft_simple(dput(x), align = "left")
))
}
Then we assign the nice_list_tbl class to the tibble:
class(dat) <- c("nice_list_tbl", class(dat))
This will print as desired:
dat
id data prior normal_int_list normal_char_list
<int> <list> <list> <list> <list>
1 1 list(x = 1, y = 2) rnorm(N, mean = 0, sd = 2) 1 A
2 2 list(a = 3, b = 4) rnorm(N, mean = 1, sd = 4) 2 B
But note that it prints the full contents of all lists. If this not desired, use option 2.
Alternatively, if you don't want to apply your custom print style to all lists columns in the entire tibble, you can do it on a per-column basis. For example:
pillar_shaft.nicelist <- function(x, ...) {
pillar::new_pillar_shaft_simple(dput(x), align = "left")
}
Then we only assign this class to the desired columns:
class(dat$data) <- c("nicelist", class(dat$data))
class(dat$prior) <- c("nicelist", class(dat$prior))
This will print those columns with the desired format and leave the other lists in the standard tibble style:
dat
id data prior normal_int_list normal_char_list
<int> <nicelist> <nicelist> <list> <list>
1 1 list(x = 1, y = 2) rnorm(N, mean = 0, sd = 2) <dbl [1]> <chr [1]>
2 2 list(a = 3, b = 4) rnorm(N, mean = 1, sd = 4) <dbl [1]> <chr [1]>
More custom formatting options for pillar are in the docs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With