1 Quick start

library(dplyr)
data(starwars)
sw <- starwars[, c(1:3, 7:8)]
sw %>% colorDF
# Color data frame (class colorDF) 5 x 87:
# (Showing rows 1 - 20 out of 87)
  │name                 │height│mass │birth_year│sex           
 1Luke Skywalker          172   77        19male          
 2C-3PO                   167   75       112none          
 3R2-D2                    96   32        33none          
 4Darth Vader             202  136        42male          
 5Leia Organa             150   49        19female        
 6Owen Lars               178  120        52male          
 7Beru Whitesun lars      165   75        47female        
 8R5-D4                    97   32        NAnone          
 9Biggs Darklighter       183   84        24male          
10Obi-Wan Kenobi          182   77        57male          
11Anakin Skywalker        188   84        42male          
12Wilhuff Tarkin          180   NA        64male          
13Chewbacca               228  112       200male          
14Han Solo                180   80        29male          
15Greedo                  173   74        44male          
16Jabba Desilijic Tiure   175 1358       600hermaphroditic
17Wedge Antilles          170   77        21male          
18Jek Tono Porkins        180  110        NAmale          
19Yoda                     66   17       896male          
20Palpatine               170   75        82male          
colorDF(sw) %>% summary
# Color data frame (class colorDF) 5 x 5:
 │Col       │Class│NAs  │unique│Summary                                         
1name      <chr>    0    87All values unique                               
2height    <int>    6    45 66 [167 <180> 191] 264                         
3mass      <dbl>   28    38  15.0 [  55.6 <  79.0>   84.5] 1358.0          
4birth_year<dbl>   44    36  8 [ 35 < 52>  72] 896                         
5sex       <chr>    4     4male: 60, female: 16, none: 6, hermaphroditic: 1

2 Colorful data frames

Your average terminal in which you run R is capable of displaying colors, styles and unicode characters. Wouldn’t it be nice to add some color to the data frames you are displaying? For example, that factors are shown in a distinct color (no confusing of strings and factors any more!) or that significant p-values are colored in red?

This was my motivation when writing this tiny package. Of course, changing default method for printing data frames is nothing a package is allowed to do (but read on!). However, this package defines everything you need to get dynamic, colorful output when viewing data frames. There are two things about colorDF which are important:

  1. colorDF never modifies the behavior of the data frame like object or its contents (i.e. it does not redefine methods like [<-, removes row names etc.1). The only two things that change are (i) the default print method (visualization), and (ii) the “.style” and “.coltp” attributes of the object, and that only if you really change the class of the object, which is often unnecessary.
  2. Any data frame like object can be used in colorDF, and you don’t need to modify these objects to use the colorful visualizations.

Yes, you can color any object that can be cast into a data frame with this or related functions! For example, you can apply it to both tibbles and data.table objects:

## works with standard data.frames
colorDF(mtcars)

## works with tidyverse tibbles
mtcars %>% as_tibble %>% colorDF

## works with data.table
colorDF(data.table(mtcars))

The output of these three commands is identical:

# Color data frame (class colorDF) 11 x 32:
# (Showing rows 1 - 20 out of 32)
                   │mpg  │cyl  │disp │hp   │drat │wt   │qsec │vs   │am   │gear │carb 
          Mazda RX4   21    6  160  110  3.9  2.6   16    0    1    4    4
      Mazda RX4 Wag   21    6  160  110  3.9  2.9   17    0    1    4    4
         Datsun 710   23    4  108   93  3.9  2.3   19    1    1    4    1
     Hornet 4 Drive   21    6  258  110  3.1  3.2   19    1    0    3    1
  Hornet Sportabout   19    8  360  175  3.1  3.4   17    0    0    3    2
            Valiant   18    6  225  105  2.8  3.5   20    1    0    3    1
         Duster 360   14    8  360  245  3.2  3.6   16    0    0    3    4
          Merc 240D   24    4  147   62  3.7  3.2   20    1    0    4    2
           Merc 230   23    4  141   95  3.9  3.1   23    1    0    4    2
           Merc 280   19    6  168  123  3.9  3.4   18    1    0    4    4
          Merc 280C   18    6  168  123  3.9  3.4   19    1    0    4    4
         Merc 450SE   16    8  276  180  3.1  4.1   17    0    0    3    3
         Merc 450SL   17    8  276  180  3.1  3.7   18    0    0    3    3
        Merc 450SLC   15    8  276  180  3.1  3.8   18    0    0    3    3
 Cadillac Fleetwood   10    8  472  205  2.9  5.2   18    0    0    3    4
Lincoln Continental   10    8  460  215  3.0  5.4   18    0    0    3    4
  Chrysler Imperial   15    8  440  230  3.2  5.3   17    0    0    3    4
           Fiat 128   32    4   79   66  4.1  2.2   19    1    1    4    1
        Honda Civic   30    4   76   52  4.9  1.6   19    1    1    4    2
     Toyota Corolla   34    4   71   65  4.2  1.8   20    1    1    4    1

3 Column types

Column types are mostly like classes, but colorDF introduces some additional distinctions, specifically “identifier” (such that character columns which contain identifiers can be shown with a particular, distinct style) and “pval”, to show significant p-values in a different color (and use format.pval() for formatting). Column types are stored in the .coltp attribute of the colorDF object.

colorDF tries to guess how each column should be displayed. First it checks whether any column types have been assigned explicitely using the col_type<- function and stored in the .coltp attribute of the object. Next, it looks up whether it can guess the contents of the column by looking at the column name (ID, p-value). Finally, it determines the class of the column (character, integer, numeric, logical, factor).

To assign a particular column type, you need first to turn a data frame colorful and then modify the column type:

sw <- sw %>% as.colorDF
col_type(sw, "name") <- "identifier"
col_type(sw, "gender") <- "factor"
sw$probability <- runif(nrow(sw), 0, 0.1)
col_type(sw, "probability") <- "pval"
sw
# Color data frame (class colorDF) 6 x 87:
# (Showing rows 1 - 20 out of 87)
  │name                 │height│mass │birth_year│sex           │probability
 1       Luke Skywalker   172   77        19male          0.0919     
 2                C-3PO   167   75       112none          0.0046     
 3                R2-D2    96   32        33none          0.0750     
 4          Darth Vader   202  136        42male          0.0348     
 5          Leia Organa   150   49        19female        0.0932     
 6            Owen Lars   178  120        52male          0.0135     
 7   Beru Whitesun lars   165   75        47female        0.0836     
 8                R5-D4    97   32        NAnone          0.0483     
 9    Biggs Darklighter   183   84        24male          0.0556     
10       Obi-Wan Kenobi   182   77        57male          0.0126     
11     Anakin Skywalker   188   84        42male          0.0712     
12       Wilhuff Tarkin   180   NA        64male          0.0917     
13            Chewbacca   228  112       200male          0.0990     
14             Han Solo   180   80        29male          0.0541     
15               Greedo   173   74        44male          0.0905     
16Jabba Desilijic Tiure   175 1358       600hermaphroditic0.0091     
17       Wedge Antilles   170   77        21male          0.0203     
18     Jek Tono Porkins   180  110        NAmale          0.0711     
19                 Yoda    66   17       896male          0.0423     
20            Palpatine   170   75        82male          0.0434     

Note that changing the column type does not change the class of the column in the data frame! colorDF never touches the data frame contents, the only operations concern the “class”, “.style” and “.coltp” attributes. So while you may set a column type to “character” instead of “factor”, even though it will be looking like a character type on the terminal output, the column class will still be a factor.

You can also hide a column:

sw <- colorDF(starwars)
col_type(sw, c("vehicles", "films", "starships")) <- "hidden"
sw
# Color data frame (class colorDF) 14 x 87:
# (Showing rows 1 - 20 out of 87)
  │name                 │height│mass │hair_color   │skin_color      │eye_color│birth_year
 1Luke Skywalker          172   77blond        fair            blue             19
 2C-3PO                   167   75NA           gold            yellow          112
 3R2-D2                    96   32NA           white, blue     red              33
 4Darth Vader             202  136none         white           yellow           42
 5Leia Organa             150   49brown        light           brown            19
 6Owen Lars               178  120brown, grey  light           blue             52
 7Beru Whitesun lars      165   75brown        light           blue             47
 8R5-D4                    97   32NA           white, red      red              NA
 9Biggs Darklighter       183   84black        light           brown            24
10Obi-Wan Kenobi          182   77auburn, whitefair            blue-gray        57
11Anakin Skywalker        188   84blond        fair            blue             42
12Wilhuff Tarkin          180   NAauburn, grey fair            blue             64
13Chewbacca               228  112brown        unknown         blue            200
14Han Solo                180   80brown        fair            brown            29
15Greedo                  173   74NA           green           black            44
16Jabba Desilijic Tiure   175 1358NA           green-tan, brownorange          600
17Wedge Antilles          170   77brown        fair            hazel            21
18Jek Tono Porkins        180  110brown        fair            blue             NA
19Yoda                     66   17white        green           brown           896
20Palpatine               170   75grey         pale            yellow           82
  │sex           │gender   │homeworld │species       
 1male          masculineTatooine  Human         
 2none          masculineTatooine  Droid         
 3none          masculineNaboo     Droid         
 4male          masculineTatooine  Human         
 5female        feminine Alderaan  Human         
 6male          masculineTatooine  Human         
 7female        feminine Tatooine  Human         
 8none          masculineTatooine  Droid         
 9male          masculineTatooine  Human         
10male          masculineStewjon   Human         
11male          masculineTatooine  Human         
12male          masculineEriadu    Human         
13male          masculineKashyyyk  Wookiee       
14male          masculineCorellia  Human         
15male          masculineRodia     Rodian        
16hermaphroditicmasculineNal Hutta Hutt          
17male          masculineCorellia  Human         
18male          masculineBestine IVHuman         
19male          masculineNA        Yoda's species
20male          masculineNaboo     Human         
# Hidden columns (3): vehicles, films, starships

4 Styles and Themes

I am a bit confused when it comes to distinguishing the two. Themes are basically internally predefined styles. Styles are simply lists that hold information how different columns, column and row headers, separators between the columns and highlighted rows are displayed.

Themes can be set using the options(colorDF_theme="<theme name>") command or by directly specifying the option in a call to colorDF:

colorDF(sw, theme="bw")
# Color data frame (class colorDF) 14 x 87:
# (Showing rows 1 - 20 out of 87)
  │name                 │height│mass │hair_color   │skin_color      │eye_color│birth_year
 1Luke Skywalker       │   172│   77│blond        fair            blue     │        19
 2C-3PO                │   167│   75│NA           gold            yellow   │       112
 3R2-D2                │    96│   32│NA           white, blue     red      │        33
 4Darth Vader          │   202│  136│none         white           yellow   │        42
 5Leia Organa          │   150│   49│brown        light           brown    │        19
 6Owen Lars            │   178│  120│brown, grey  light           blue     │        52
 7Beru Whitesun lars   │   165│   75│brown        light           blue     │        47
 8R5-D4                │    97│   32│NA           white, red      red              NA
 9Biggs Darklighter    │   183│   84│black        light           brown    │        24
10Obi-Wan Kenobi       │   182│   77│auburn, whitefair            blue-gray│        57
11Anakin Skywalker     │   188│   84│blond        fair            blue     │        42
12Wilhuff Tarkin       │   180│   NAauburn, grey fair            blue     │        64
13Chewbacca            │   228│  112│brown        unknown         blue     │       200
14Han Solo             │   180│   80│brown        fair            brown    │        29
15Greedo               │   173│   74│NA           green           black    │        44
16Jabba Desilijic Tiure│   175│ 1358│NA           green-tan, brownorange   │       600
17Wedge Antilles       │   170│   77│brown        fair            hazel    │        21
18Jek Tono Porkins     │   180│  110│brown        fair            blue             NA
19Yoda                 │    66│   17│white        green           brown    │       896
20Palpatine            │   170│   75│grey         pale            yellow   │        82
  │sex           │gender   │homeworld │species       
 1male          masculineTatooine  Human         
 2none          masculineTatooine  Droid         
 3none          masculineNaboo     Droid         
 4male          masculineTatooine  Human         
 5female        feminine Alderaan  Human         
 6male          masculineTatooine  Human         
 7female        feminine Tatooine  Human         
 8none          masculineTatooine  Droid         
 9male          masculineTatooine  Human         
10male          masculineStewjon   Human         
11male          masculineTatooine  Human         
12male          masculineEriadu    Human         
13male          masculineKashyyyk  Wookiee       
14male          masculineCorellia  Human         
15male          masculineRodia     Rodian        
16hermaphroditicmasculineNal Hutta Hutt          
17male          masculineCorellia  Human         
18male          masculineBestine IVHuman         
19male          masculineNA        Yoda's species
20male          masculineNaboo     Human         
# Hidden columns (3): vehicles, films, starships

Here is an overview of the themes. Some of them are intended for dark background and will not look great on a light background, which is why we use force_bg=TRUE to force black on white background for these themes:

colorDF_themes_show(force_bg=TRUE)
Theme light - Suitable for black on white terminals:
# Color data frame (class colorDF) 7 x 3:
 │ID   │String   │Factor│Number│Integer│Logical│Pvalue
1  ID1foo      foo     12.1     12TRUE   0.001 
2  ID2baz      baz     -3.1    -13FALSE  0.314 
3  ID3highlightboo      2.7     42NA     NA    

Theme minimal - Almost no style:
# Color data frame (class colorDF) 7 x 3:
  ID    String    Factor Number            Integer Logical Pvalue  
1 ID1   foo       foo    12.1              12      TRUE    0.001   
2 ID2   baz       baz    -3.14159265358979 -13     FALSE   0.314159
3 ID3   highlight boo    2.71828182845905  42      NA      NA      

Theme universal - Suitable for all terminals:
# Color data frame (class colorDF) 7 x 3:
 │ID   │String   │Factor│Number│Integer│Logical│Pvalue
1  ID1foo      foo     12.1     12TRUE   0.001 
2  ID2baz      baz     -3.1    -13FALSE  │0.314 
3  ID3highlightboo      2.7     42NA     NA    

Theme tibble - Very much like a tibble:
# Color data frame (class colorDF) 7 x 3:
  ID    String    Factor Number Integer Logical Pvalue
  <chr> <chr>     <chr>  <dbl>  <dbl>   <lgl>   <dbl> 
1 ID1   foo       foo    12.10   12     TRUE    0.001 
2 ID2   baz       baz    -3.14  -13     FALSE   0.314 
3 ID3   highlight boo     2.72   42     NA         NA 

Theme dark - Suitable for white on black terminals:
# Color data frame (class colorDF) 7 x 3:
 │ID   │String   │Factor│Number│Integer│Logical│Pvalue
1  ID1foo      foo     12.1     12TRUE   0.001 
2  ID2baz      baz     -3.1    -13FALSE  0.314 
3  ID3highlightboo      2.7     42NA     NA    

Theme bw - Black and white only. Suitable for black on white terminals:
# Color data frame (class colorDF) 7 x 3:
 │ID   │String   │Factor│Number│Integer│Logical│Pvalue
1  ID1foo      foo   │  12.1│     12│TRUE   0.001 
2  ID2baz      baz   │  -3.1│    -13│FALSE  0.314 
3  ID3highlightboo   │   2.7│     42│NA     NA    

Theme wb - Black and white only. Suitable for white on black terminals:
# Color data frame (class colorDF) 7 x 3:
 │ID   │String   │Factor│Number│Integer│Logical│Pvalue
1  ID1foo      foo   │  12.1│     12│TRUE   │0.001 
2  ID2baz      baz   │  -3.1│    -13│FALSE  0.314 
3  ID3highlightboo   │   2.7│     42│NA     NA    

Default theme: light
Change it with `options(colorDF_theme="<theme name>")`

You can add your own themes using add_colorDF_theme() (see the example section on the help page).

5 Column styles

Styles of a colorDF object can be directly manipulated using df_style:

mtcars.c <- colorDF(mtcars)
df_style(mtcars.c, "sep") <- "; "

If interested, read the help file for df_style().

6 Utilities

6.1 Summaries

colorDF comes with a couple of utility functions. Firstly, it defines a summary method for colorful data frames which can also be used for any other data frame like object and which I find much more useful than the regular summary:

starwars %>% as.colorDF %>% summary
# Color data frame (class colorDF) 5 x 14:
  │Col       │Class│NAs  │unique│Summary                                                         
 1name      <chr>    0    87All values unique                                               
 2height    <int>    6    45 66 [167 <180> 191] 264                                         
 3mass      <dbl>   28    38  15.0 [  55.6 <  79.0>   84.5] 1358.0                          
 4hair_color<chr>    5    12none: 37, brown: 18, black: 13, white: 4, blond: 3, auburn: 1, …
 5skin_color<chr>    0    31fair: 17, light: 11, dark: 6, green: 6, grey: 6, pale: 5, brown…
 6eye_color <chr>    0    15brown: 21, blue: 19, yellow: 11, black: 10, orange: 8, red: 5, …
 7birth_year<dbl>   44    36  8 [ 35 < 52>  72] 896                                         
 8sex       <chr>    4     4male: 60, female: 16, none: 6, hermaphroditic: 1                
 9gender    <chr>    4     2masculine: 66, feminine: 17                                     
10homeworld <chr>   10    48Naboo: 11, Tatooine: 10, Alderaan: 3, Coruscant: 3, Kamino: 3, …
11species   <chr>    4    37Human: 35, Droid: 6, Gungan: 3, Kaminoan: 2, Mirialan: 2, Twi'l…
12films     <lst>    0    24Attack of the Clones: 40, Revenge of the Sith: 34, The Phantom …
13vehicles  <lst>    0    11Imperial Speeder Bike: 2, Snowspeeder: 2, Tribubble bongo: 2, A…
14starships <lst>    0    17Millennium Falcon: 4, X-wing: 4, Imperial shuttle: 3, Naboo fig…

There is a directly visible (exported) version of the colorful summary called summary_colorDF:

starwars %>% summary_colorDF

As you can see, the summary is much more informative than the default summary.data.frame function. Not only this, but the object does not need to be a data frame – any list can do!

mtcars_cyl <- split(mtcars$mpg, mtcars$cyl)
sapply(mtcars_cyl, length)
 4  6  8 
11  7 14 

The list mtcars_cyl is the miles per gallon column split by number of cylinders. We can use summary_colorDF to create a (semi)graphical summary of this list:

summary_colorDF(mtcars_cyl, numformat="g", width=90)
# Color data frame (class colorDF) 5 x 3:
 │Col  │Class│NAs  │unique│Summary                                                     
14    <dbl>    0     9                            ╾──┤       +          ├────────╼
26    <dbl>    0     6                   ╾─┤ +   ├╼                               
38    <dbl>    0    12╾─────────┤ +  ├──────╼                                     

In fact, this is so useful (especially if an interactive graphic device is not practical, e.g. when running R over ssh/screen) that I implemented a terminal boxplotting function:

term_boxplot(Sepal.Length ~ Species, data=iris, width=90)
# Color data frame (class colorDF) 5 x 4:
 │Col       │Class│NAs  │unique│Summary                                               
1setosa    <dbl>    0    15╾──────┤  +  ├────────╼                               
2versicolor<dbl>    0    21         ╾─────────┤    +    ├──────────╼             
3virginica <dbl>    0    21         ╾──────────────────┤   +     ├──────────────╼
4Range     <chr>    0     1Only one value: Range: 4.3 - 7.9                      

6.2 Highlighting

The highlight() function allows to mark selected rows from the table:

foo <- starwars %>% select(name, species, homeworld) %>% 
  highlight(.$homeworld == "Tatooine")
# Tibble (class tbl_df) 3 x 87:
# (Showing rows 1 - 20 out of 87)
  │name                 │species       │homeworld 
 1Luke Skywalker       Human         Tatooine  
 2C-3PO                Droid         Tatooine  
 3R2-D2                Droid         Naboo     
 4Darth Vader          Human         Tatooine  
 5Leia Organa          Human         Alderaan  
 6Owen Lars            Human         Tatooine  
 7Beru Whitesun lars   Human         Tatooine  
 8R5-D4                Droid         Tatooine  
 9Biggs Darklighter    Human         Tatooine  
10Obi-Wan Kenobi       Human         Stewjon   
11Anakin Skywalker     Human         Tatooine  
12Wilhuff Tarkin       Human         Eriadu    
13Chewbacca            Wookiee       Kashyyyk  
14Han Solo             Human         Corellia  
15Greedo               Rodian        Rodia     
16Jabba Desilijic TiureHutt          Nal Hutta 
17Wedge Antilles       Human         Corellia  
18Jek Tono Porkins     Human         Bestine IV
19Yoda                 Yoda's speciesNA        
20Palpatine            Human         Naboo     

(Unfortunately, the HTML representation of the ANSI terminal doesn’t show that one correctly).

7 Setting up colorDF as the default data frame print method

You can use colorDF as the default method for displaying data frames and similar objects. For this, you need to use the colorDF:::print.colorDF function:

## for regular data frames
print.data.frame <- colorDF:::print_colorDF

## for tidyverse tibbles
print.tbl        <- colorDF:::print_colorDF

## for data.tables
print.data.table <- colorDF:::print_colorDF

This will not replace or modify the original functions from data.table or tibble packages, but merely mask these. And from now on, every data frame like object will be shown in color, but otherwise, its behavior will not change.

Should you want to go back to the original print functions, just remove these new functions:

rm(print.data.frame, print.tbl, print.data.table)

This is a bit more complicated in case of S4 objects. One such object type is a DataFrame defined in the S4Vectors package. It is commonly used in many Bioconductor packages such as DESeq2. Unfortunately, the show method defined for DataFrames is not convenient, for example it always displays a ridiculous number of significant digits, cluttering the output. print_colorDF can print these classes, as it can work on anything that can be cast into a data frame using an as.data.frame method.

To take over the output of DataFrames and all other objects inheriting from it (such as DESeqResults), we need to use the S4 convention of defining the methods:

setMethod("show", "DataFrame", function(object) colorDF::print_colorDF(object))

Since methods can be only defined for existing classes, if you want to put it in your .Rprofile, you need to first load (but not necessarily attach) the S4Vectors package:

loadNamespace("S4Vectors")
setMethod("show", "DataFrame", function(object) colorDF::print_colorDF(object))

8 Global options

There is a number of options which override whatever has been defined in a particular theme / style. You can view them with colorDF_options():

colorDF_options()
# Data frame like object (class data.frame) 4 x 6:
 │Option              │Description                       │Default           │Current
1colorDF_n           Number of rows to show            20                Not set
2colorDF_noitalic    Suppress italics (read on loading)FALSE             Not set
3colorDF_tibble_styleBehave like tibble                FALSE             Not set
4colorDF_sep         Column separator                  " "               Not set
5colorDF_theme       colorDF theme to use              light             light  
6width               Width of the terminal             getOption("width")100    

To change these options, use options() just like with any other global option. For example,

options(colorDF_tibble_style=TRUE)
options(colorDF_sep= " ")
options(colorDF_n=5)
colorDF(starwars)
# Color data frame (class colorDF) 14 x 87:
# (Showing rows 1 - 5 out of 87)
  name           height mass  hair_color skin_color  eye_color birth_year sex    gender   
  <chr>          <int>  <dbl> <chr>      <chr>       <chr>     <dbl>      <chr>  <chr>    
1 Luke Skywalker    172    77 blond      fair        blue              19 male   masculine
2 C-3PO             167    75 NA         gold        yellow           112 none   masculine
3 R2-D2              96    32 NA         white, blue red               33 none   masculine
4 Darth Vader       202   136 none       white       yellow            42 male   masculine
5 Leia Organa       150    49 brown      light       brown             19 female feminine 
# 5 more columns: homeworld (<chr>), species (<chr>), films (<lst>), vehicles (<lst>), starships (<lst>)

9 Rmarkdown

The package is intended to be used in terminal. However, as you see above, it is possible to get the colored tables also in an rmarkdown document. For this, include the following chunk at the beginning of your document:

```{r echo=FALSE}
options(crayon.enabled = TRUE)
knitr::knit_hooks$set(output = function(x, options){
  paste0(
    '<pre class="r-output"><code>',
    fansi::sgr_to_html(x = htmltools::htmlEscape(x), warn = FALSE),
    '</code></pre>'
  )
})
```

  1. Strictly speaking, that is not true, as there is a [.colorDF method which serves only as a wrapper around the respective [ of the underlying data frame, tibble or data table. The only reason is exist is that otherwise the style and column type attributes will be lost.↩︎