Display Data Frames Beautifully with the paint Package

Published Apr 17, 2022
Updated Nov 15, 2025
5 minutes read
Note

This old post is translated by AI.

##Introduction

Sorry for the gap in updates! Long time no see! Apparently Dr. Stone finished in the main Jump magazine, so I binge-read from volume 1 to the latest released volume 25 and this happened 😅 This time, as a light topic for rehabilitation, I want to talk about methods for previewing data frames!

##First, Please Take a Look at the paint() Function

While surfing the R community, I found an interesting package!

When you preview a data frame using the paint package, it's displayed like this with the first few values of each column color-coded. The operation is extremely fast, so it seems convenient for quick checks!

pacman::p_load(tidyverse, paint)
starwars %>% paint()
Default paint() function coloring (RStudio terminal)

###How to Use

According to the official repository instructions, installation is done from r-universe. It doesn't seem to be registered on CRAN yet.

install.packages(
    "paint",
    repos = c(mm = "https://milesmcbain.r-universe.dev", getOption("repos"))
)

When using normally, use the paint() function.

starwars %>% paint()

If it's too tedious to use the paint() function every time, using the mask_print() function will mask all subsequent previews with the paint() function.

paint::mask_print()
## {paint} masked print.data.frame
## {paint} masked print.tbl_df

If you decide you don't want the mask after all, you can remove it with unmask_print()!

paint::unmask_print()
## {paint} unmasked print.data.frame
## {paint} unmasked print.tbl_df

###You Can Also Change the Color Pattern

Apparently you can change the color pattern to your preference by specifying color codes!

# Official usage example
pacman::p_load(viridisLite)
pacman::p_load(crayon, paint)
my_magma <- lapply(viridisLite::magma(6), crayon::make_style)
options(paint_palette = my_magma)
paint(mtcars)
viridis pattern example (VSCode, radian terminal)
# My favorite color pattern AAAS
# The ggsci package can be installed with install.packages()
my_pal <- lapply(ggsci::pal_aaas()(6), crayon::make_style)
options(paint_palette = my_pal)
paint(mtcars)
AAAS color pattern

###Persisting paint Function Settings

Personally, I thought paint is nice and colorful (though I'll probably get tired of it and revert in a month), so I set it to auto-load on R startup.

For the color code pattern, I used the pastel colors from catppuccin, my current favorite theme.

library(paint)
pal_catppuccin <- lapply(
    c('#F28FAD', '#ABE9B3', '#FAE3B0', '#96CDFB', '#F5C2E7', '#89DCEB'),
    crayon::make_style
)
options(paint_palette = pal_catppuccin)
 
# It looks like this when displayed
paint::paint(starwars)

By writing up to options in .Rprofile, you can have it automatically loaded on R startup ♪

Normally, the .Rprofile file exists directly under home, but it might vary depending on your OS. If you're not sure where to put it, I think using the usethis::edit_r_profile() function is good!

##Other Data Frame Preview Methods

Actually, the content from here might be the main point lol. The paint() introduced this time is reasonably easy to see, but I think it's good to know other methods too. The content I'm about to introduce is often surprisingly unknown, so I'll take this opportunity to introduce all the methods I know!

###Absolutely Don't Do print(data.frame)

It might be fine to simply output a data.frame, but when the data gets large, the terminal gets flooded. When this happens, you can't even check the column names. As a preview method, this is a bad move.

Beginner-oriented explanation sites say things like "use the head() function to display the first few rows," but I feel it's tedious to write head() just for a quick check...

print(iris)
head(iris)

###Use the View() Function

If you want to preview data somewhat thoroughly, I think using the View() function is good. About 1 in 10 times I also use this method.

The View() function is a function that displays data frames in a very easy-to-see format in basically any environment.

View(starwars)

The View function is only unavailable when you start R from the terminal and can't do GUI operations. (When you can't connect to a display port)

For RStudio: In RStudio, the data preview button in Environment is the same action as executing View().

View() @Rstudio

For Visual Studio Code:

View() @VSCode

For Rconsole:

View() @Rconsole Windows

###Use tibble

When using tidyverse functions, the output is almost certainly converted to tibble. Therefore, you may be benefiting from tibble without realizing it. I mostly use this method.

When you print() a tibble, or just execute the object itself, you can automatically see summarized information.

r$> as_tibble(starwars)
# # A tibble: 87 × 14
#    name   height  mass hair_color skin_color eye_color birth_year sex   gender homeworld species
#    <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr>  <chr>     <chr>
#  1 Luke …    172    77 blond      fair       blue            19   male  mascu… Tatooine  Human
#  2 C-3PO     167    75 NA         gold       yellow         112   none  mascu… Tatooine  Droid
#  3 R2-D2      96    32 NA         white, bl… red             33   none  mascu… Naboo     Droid
#  4 Darth…    202   136 none       white      yellow          41.9 male  mascu… Tatooine  Human
#  5 Leia …    150    49 brown      light      brown           19   fema… femin… Alderaan  Human
#  6 Owen …    178   120 brown, gr… light      blue            52   male  mascu… Tatooine  Human
#  7 Beru …    165    75 brown      light      blue            47   fema… femin… Tatooine  Human
#  8 R5-D4      97    32 NA         white, red red             NA   none  mascu… Tatooine  Droid
#  9 Biggs…    183    84 black      light      brown           24   male  mascu… Tatooine  Human
# 10 Obi-W…    182    77 auburn, w… fair       blue-gray       57   male  mascu… Stewjon   Human
# # … with 77 more rows, and 3 more variables: films <list>, vehicles <list>, starships <list>

You probably won't configure this often, but you can also specify the number of rows to display.

as_tibble(starwars) %>% print(n = 1)
## # A tibble: 87 × 14
##   name      height  mass hair_color skin_color eye_color birth_year sex   gender
##   <chr>      <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr>
## 1 Luke Sky…    172    77 blond      fair       blue              19 male  mascu…
## # … with 86 more rows, and 5 more variables: homeworld <chr>, species <chr>,
## #   films <list>, vehicles <list>, starships <list>

Similarly, the number of columns can be specified with the width argument.

as_tibble(starwars) %>% print(width = 1)
## # A
## #   tibble:
## #   87
## #   ×
## #   14
## # … with 77 more rows, and 14 more variables: name <chr>, height <int>, mass <dbl>, hair_color <chr>, skin_color <chr>, eye_color <chr>, birth_year <dbl>, sex <chr>, gender <chr>, homeworld <chr>, species <chr>, films <list>, vehicles <list>, starships <list>

###dplyr::glimpse

The dplyr package has a function for previewing data frames called glimpse(). glimpse is a preview method similar in format to the paint introduced this time, with columns lined up in a row. It's convenient when you have many columns and think "What variables does this data have?" However, glimpse has no color coding, so understanding data relationships is difficult.

glimpse(starwars)
## Rows: 87
## Columns: 14
## $ name       <chr> "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "Leia Or…
## $ height     <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 2
## $ mass       <dbl> 77.0, 75.0, 32.0, 136.0, 49.0, 120.0, 75.0, 32.0, 84.0, 77.
## $ hair_color <chr> "blond", NA, NA, "none", "brown", "brown, grey", "brown", N
## $ skin_color <chr> "fair", "gold", "white, blue", "white", "light", "light", "…
## $ eye_color  <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "blue",
## $ birth_year <dbl> 19.0, 112.0, 33.0, 41.9, 19.0, 52.0, 47.0, NA, 24.0, 57.0,
## $ sex        <chr> "male", "none", "none", "male", "female", "male", "female",
## $ gender     <chr> "masculine", "masculine", "masculine", "masculine", "femini…
## $ homeworld  <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "T…
## $ species    <chr> "Human", "Droid", "Droid", "Human", "Human", "Human", "Huma…
## $ films      <list> <"The Empire Strikes Back", "Revenge of the Sith", "Return…
## $ vehicles   <list> <"Snowspeeder", "Imperial Speeder Bike">, <>, <>, <>, "Imp…
## $ starships  <list> <"X-wing", "Imperial shuttle">, <>, <>, "TIE Advanced x1",…

###data.table

I don't use the data.table package much so I'm not very familiar with it, but the data.table type also previews in its own format like tibble.

data.table is a package for high-speed data frame processing. It's a separate entity from tidyverse's tibble.

pacman::p_load(data.table)
as.data.table(iris)
## data.table [150, 5]
## Sepal.Length dbl 5.1 4.9 4.7 4.6 5 5.4
## Sepal.Width  dbl 3.5 3 3.2 3.1 3.6 3.9
## Petal.Length dbl 1.4 1.4 1.3 1.5 1.4 1.7
## Petal.Width  dbl 0.2 0.2 0.2 0.2 0.2 0.4
## Species      fct setosa setosa setosa setosa setosa setosa

I'll just paste the data.table options from the manual as-is.

Usage
  ## S3 method for class 'data.table'
print(x,
    topn=getOption("datatable.print.topn"),             # default: 5
    nrows=getOption("datatable.print.nrows"),           # default: 100
    class=getOption("datatable.print.class"),           # default: FALSE
    row.names=getOption("datatable.print.rownames"),    # default: TRUE
    col.names=getOption("datatable.print.colnames"),    # default: "auto"
    print.keys=getOption("datatable.print.keys"),       # default: FALSE
    trunc.cols=getOption("datatable.print.trunc.cols"), # default: FALSE
    quote=FALSE,
    timezone=FALSE, ...)

##Summary

So this time I introduced the paint package along with various methods for previewing data frames!

Programming in R essentially means data frame operations. If you can quickly and coolly preview data frames, wouldn't your usual analysis become more enjoyable? Try using the paint() function if you like 😀