ggplotcli: Universal ggplot2 to Terminal Plotting

Claas Heuer

2025-11-27

Introduction

ggplotcli is a universal converter that renders any ggplot2 plot in the terminal using Unicode/ASCII characters. It automatically extracts data, aesthetics, and styling from ggplot objects, supporting 15+ geom types, faceting, color aesthetics, and legends.

Basic Usage

library(plotcli)
#> Loading required package: R6
#> Loading required package: ggplot2
#> plotcli loaded. Use plotcli_options() to set global options.
library(ggplot2)

# Create a ggplot
p <- ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
  geom_point() +
  labs(title = "MPG vs Weight by Cylinders")

# Render in terminal
ggplotcli(p, width = 60, height = 16)
#> 
#>                 MPG vs Weight by Cylinders                       
#>   35.0       ⠄                                                   
#>                  ⠐                                               
#>   30.0   ⠐⠐                                                      
#>               ⠠                                             fac  
#> m 25.0           ⠁           ⢀                              * 4  
#> p                  ⠄         ⠄                              * 6  
#> g 20.0              ⠐ ⠠ ⠐⠠   ⠐                              * 8  
#>                         ⠈       ⢰    ⠐                           
#>                              ⡀      ⠁   ⠄                        
#>   15.0                          ⠈⠈⠆ ⠈                  ⠂         
#>                                      ⠁                           
#>   10.0                                                ⠂ ⠂        
#>               2.0         3.0         4.0         5.0            
#>                                wt                                
#> 

Supported Geoms

Scatter Plots (geom_point)

p <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
  geom_point() +
  labs(title = "Iris: Sepal Dimensions by Species")
ggplotcli(p, width = 60, height = 16)
#> 
#>             Iris: Sepal Dimensions by Species                             
#> S  4.5                     ⠠                                              
#> e                    ⡀   ⠄                                                
#> p  4.0                 ⢀     ⠂                                            
#> a                  ⢐  ⢀⢀   ⠐                         ⠐  ⠂   Species       
#> l  3.5       ⠁   ⠁⠨⠠ ⠄   ⠄                     ⠁            * setosa      
#> .         ⢀  ⡁⢀ ⠁ ⢨⠨ ⠁ ⠈      ⡀⠈  ⠁⠨⢀ ⡀ ⠠ ⡀⡀⢀  ⡀            * versicolor  
#> W  3.0   ⢀⢀  ⠂  ⡂⡂⢀    ⢀  ⡀⢀  ⡀⢀⢀   ⠐ ⡀⢀⢐ ⡀⠂  ⡀⡀    ⢀⢀      * virginica   
#> i         ⠐               ⡂⢐ ⡀ ⠐⢐ ⡂⢐⢐ ⡀⠐  ⡀     ⠐⢀   ⢀                    
#> d  2.5               ⠁   ⠄⠁⠠ ⠅ ⠈⠠  ⠈⠈                ⠠                    
#> t                ⠅ ⠈     ⠅⠁⠈       ⠈    ⠈                                 
#> h           ⠁     ⠈      ⠁     ⠐  ⠂⠈                                      
#>    2.0            ⠐                                                       
#>                  5.0          6.0          7.0          8.0               
#>                           Sepal.Length                                    
#> 

Line Plots (geom_line)

# Multiple colored lines
df <- data.frame(
  x = rep(1:30, 2),
  y = c(sin(1:30/4) * 10, cos(1:30/4) * 10),
  type = rep(c("sin", "cos"), each = 30)
)
p <- ggplot(df, aes(x, y, color = type)) +
  geom_line() +
  labs(title = "Sine and Cosine Waves")
ggplotcli(p, width = 60, height = 12)
#> 
#>                   Sine and Cosine Waves                            
#>   10.0   ⠠⢄⡀   ⣀⠤⠒⠢⠤⣀⡀                       ⣀⠤⠔⠒⠤⠤⣀   ⣀⠄          
#>            ⠈⡱⢖⠉      ⠈⠑⠤⡀                 ⣀⠔⠊       ⢉⠶⢎     type   
#>    5.0    ⡠⠊  ⠑⠢⡀       ⠈⠢⡀             ⢠⠊        ⣀⠔⠁  ⠣⡀   * cos  
#> y        ⠈      ⠘⢄        ⠑⢄          ⢀⠔⠁       ⢠⠊          * sin  
#>      0            ⠑⢄        ⠑⠤⡀     ⢀⠔⠁       ⢀⠔⠁                  
#>   -5.0              ⠑⠤⡀       ⠈⢆  ⢀⠔⠁        ⡰⠁                    
#>                       ⠈⠢⡀       ⡱⠶⣁       ⡠⠒⠉                      
#>  -10.0                  ⠈⠑⠒⠒⠤⠤⠒⠉   ⠉⠑⠒⠤⠔⠒⠉                         
#>         0      5.0    10.0    15.0    20.0    25.0    30.0         
#>                                x                                   
#> 

Histograms (geom_histogram)

p <- ggplot(mtcars, aes(x = mpg, fill = factor(cyl))) +
  geom_histogram(bins = 10, position = "dodge") +
  labs(title = "MPG Distribution by Cylinders")
ggplotcli(p, width = 60, height = 12)
#> 
#>               MPG Distribution by Cylinders                      
#>                       ⣶⣶                                         
#> c  6.0                ⣿⣿                                    fac  
#> o                     ⣿⣿                                    * 4  
#> u  4.0                ⣿⣿     ⢰⣶⡆                            * 6  
#> n                     ⣿⣿ ⣤⣤⣤⡄⢸⣿⡇⢠⣤⣤            ⣤⣤           * 8  
#> t  2.0      ⢠⣤⡄  ⣤⣤   ⣿⣿ ⣿⣿⣿⣧⣼⣿⡇⢸⣿⣿  ⢠⣤⡄       ⣿⣿                
#>             ⢸⣿⡇  ⣿⣿   ⣿⣿ ⣿⣿⣿⣿⣿⣿⡇⢸⣿⣿  ⢸⣿⡇       ⣿⣿  ⢠⣤⡄           
#>      0   ⠠⠤⠤⠼⠿⠧⠤⠤⠿⠿⠤⠤⠤⠿⠿⠤⠿⠿⠿⠿⠿⠿⠧⠼⠿⠿⠤⠤⠼⠿⠧⠤⠤⠤⠤⠤⠤⠤⠿⠿⠤⠤⠼⠿⠧⠤⠤⠄        
#>          10.0     15.0     20.0    25.0     30.0     35.0        
#>                               mpg                                
#> 

Density Plots (geom_density)

p <- ggplot(mtcars, aes(x = mpg, color = factor(cyl))) +
  geom_density() +
  labs(title = "MPG Density by Cylinders")
ggplotcli(p, width = 60, height = 12)
#> 
#>                  MPG Density by Cylinders                        
#> d 0.25            ⣠⢦                                             
#> e 0.20           ⢠⠃⠈⣇      ⢀⡠⠞⠙⣆                            fac  
#> n                ⡞  ⠸⡀  ⢠⠚⠉⠁   ⠸⡄                           * 4  
#> s 0.15          ⢠⠃   ⢣ ⢠⠃       ⢧                           * 6  
#> i 0.10         ⢀⡎    ⠈⢆⡎        ⠘⡄                          * 8  
#> t 0.05   ⠘⢦   ⢀⡞      ⡼⠳⠤⠖⠒⢦ ⢀⣠⠤⠖⢳⠒⠒⠒⠒⠒⠦⠤⠤⣄⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀            
#> y         ⠈⢣⡀⣠⠞      ⡰⠁ ⢀⣀⡤⠔⢻⡉   ⠈⢧                 ⠈⠉⠉⠓⠂        
#>      0   ⠠⠤⠤⠭⠥⠤⠤⠤⠴⠶⠒⠚⠓⠒⠉⠉    ⠙⠒⠦⠤⠤⠬⠷⠶⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠄        
#>        10.0     15.0      20.0      25.0      30.0      35.0     
#>                               mpg                                
#> 

Bar Charts (geom_col)

df <- data.frame(
  category = c("A", "B", "C", "D", "E", "F"),
  value = c(25, 45, 30, 60, 35, 50)
)
p <- ggplot(df, aes(x = category, y = value, fill = category)) +
  geom_col() +
  labs(title = "Category Values")
ggplotcli(p, width = 60, height = 12)
#> 
#>                      Category Values                             
#>   60.0                           ⣶⣶⣶⣶⣶⣶⣶⣶                   cat  
#> v 50.0                           ⣿⣿⣿⣿⣿⣿⣿⣿         ⣤⣤⣤⣤⣤⣤⣤⣤  * A  
#> a 40.0          ⢸⣿⣿⣿⣿⣿⣿⣿⡇        ⣿⣿⣿⣿⣿⣿⣿⣿         ⣿⣿⣿⣿⣿⣿⣿⣿  * B  
#> l 30.0          ⢸⣿⣿⣿⣿⣿⣿⣿⡇⣀⣀⣀⣀⣀⣀⣀⣀⣿⣿⣿⣿⣿⣿⣿⣿⢰⣶⣶⣶⣶⣶⣶⣶⡆⣿⣿⣿⣿⣿⣿⣿⣿  * C  
#> u       ⣤⣤⣤⣤⣤⣤⣤⣤⢸⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⣿⣿⣿⣿⣿⣿  * D  
#> e 20.0  ⣿⣿⣿⣿⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⣿⣿⣿⣿⣿⣿  * E  
#>   10.0  ⣿⣿⣿⣿⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⣿⣿⣿⣿⣿⣿  * F  
#>      0  ⠿⠿⠿⠿⠿⠿⠿⠿⠸⠿⠿⠿⠿⠿⠿⠿⠇⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠸⠿⠿⠿⠿⠿⠿⠿⠇⠿⠿⠿⠿⠿⠿⠿⠿       
#>            1.0     2.0     3.0      4.0     5.0     6.0          
#>                             category                             
#> 

Boxplots (geom_boxplot)

Boxplots are rendered with box-drawing characters by default, showing whiskers, box (Q1-Q3), median line, and outliers:

set.seed(42)
df <- data.frame(
  group = factor(rep(paste0("Group ", 1:6), each = 50)),
  value = c(rnorm(50, 10, 3), rnorm(50, 5, 2), rnorm(50, 8, 4),
            rnorm(50, 6, 2), rnorm(50, 12, 3), rnorm(50, 7, 2))
)
p <- ggplot(df, aes(x = group, y = value, fill = group)) +
  geom_boxplot() +
  labs(title = "Boxplot Colored by Group", y = "Value", x = "Group")
ggplotcli(p, width = 80, height = 20, boxplot_style = "ascii")
#> 
#>                            Boxplot Colored by Group                                        
#>                                     *                    ───────                           
#>           ───────                                           │                              
#>              │                      *                       │                              
#>   15.0       │                                          ┌───────┐               group      
#>              │                   ───*───                │       │               * Group 1  
#> V        ┌───────┐                  │                   │───────│   ───────     * Group 2  
#> a        │       │                  │                   └───────┘      │        * Group 3  
#> l 10.0   │───────│              ┌───────┐    ───────        │          │        * Group 4  
#> u        └───────┘    ───────   │       │   ┌───────┐       │      ┌───────┐    * Group 5  
#> e            │       ┌───────┐  └───────┘   │───────│    ───────   │       │    * Group 6  
#>    5.0       │       │───────│      │       └───────┘              └───────┘               
#>              │       └───────┘      │           │                      │                   
#>           ───*───     ───────       │        ───────                ───────                
#>                                  ───────                                                   
#>      0                   *          *                                                      
#>                                                                                            
#>              1.0        2.0         3.0        4.0         5.0        6.0                  
#>                                        Group                                               
#> 

You can also use Braille rendering for boxplots:

ggplotcli(p, width = 80, height = 20, boxplot_style = "braille")
#> 
#>                            Boxplot Colored by Group                                        
#>                                      ⡀                                                     
#>                                                           ⠒⠒⡖⠒⠂                            
#>             ⠉⠉⡏⠉⠁                                           ⡇                              
#>   15.0        ⡇                      ⠂                      ⡇                   group      
#>               ⡇                      ⠂                 ⢰⠒⠒⠒⠒⠓⠒⠒⠒⢲               * Group 1  
#> V        ⢀⣀⣀⣀⣀⣇⣀⣀⣀⡀                ⠉⠉⡏⠉⠁               ⢸        ⢸    ⢀⣀⣀⣀⣀      * Group 2  
#> a        ⢸        ⡇                  ⡇                 ⢸⠉⠉⠉⠉⠉⠉⠉⠉⢹      ⢸        * Group 3  
#> l 10.0   ⢸⠒⠒⠒⠒⠒⠒⠒⠒⡇                  ⡇        ⠐⠒⢲⠒⠒    ⠘⠒⠒⠒⠒⡖⠒⠒⠒⠚      ⢸        * Group 4  
#> u        ⠸⠤⠤⠤⠤⡤⠤⠤⠤⠇    ⠠⠤⢤⠤⠤    ⢰⠒⠒⠒⠒⠓⠒⠒⠒⢲      ⢸           ⡇      ⢰⠒⠒⠒⠚⠒⠒⠒⠒⡆   * Group 5  
#> e             ⡇      ⣀⣀⣀⣀⣸⣀⣀⣀⣀⡀ ⢸⠒⠒⠒⠒⠒⠒⠒⠒⢺  ⡖⠒⠒⠒⠚⠒⠒⠒⠒⡆      ⡇      ⢸⠒⠒⠒⠒⠒⠒⠒⠒⡇   * Group 6  
#>    5.0        ⡇      ⡗⠒⠒⠒⠒⠒⠒⠒⠒⡇ ⠘⠒⠒⠒⠒⡖⠒⠒⠒⠚  ⣏⣉⣉⣉⣉⣉⣉⣉⣉⡇    ⠉⠉⠉⠉⠁    ⠘⠒⠒⠒⢲⠒⠒⠒⠒⠃              
#>               ⡇      ⠧⠤⠤⠤⢤⠤⠤⠤⠤⠇      ⡇          ⢸                      ⢸                   
#>             ⠤⠤⡧⠤⠄      ⢀⣀⣸⣀⣀         ⡇        ⠠⠤⠼⠤⠤                    ⢸                   
#>                                    ⠒⠒⠓⠒⠂                             ⠐⠒⠚⠒⠒                 
#>      0                               ⠄                                                     
#>                          ⠈                                                                 
#>              1.0        2.0         3.0        4.0         5.0        6.0                  
#>                                        Group                                               
#> 

Combining Multiple Geoms

# Histogram with density overlay
p <- ggplot(mtcars, aes(x = mpg)) +
  geom_histogram(aes(y = after_stat(density)), bins = 10, fill = "gray") +
  geom_density(color = "red") +
  labs(title = "Histogram with Density Overlay")
ggplotcli(p, width = 60, height = 12)
#> 
#>               Histogram with Density Overlay                 
#> d                 ⢰⣶⣶⣶⣶⣶                                     
#> e 0.08            ⢸⣿⣿⣿⣿⣿⣶⣶⣶⣶⣶⣶⣶⣶⣶                            
#> n 0.06            ⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿                            
#> s               ⢀⡴⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠓⢦⡀                         
#> i 0.04        ⣀⠴⠋ ⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣤⣤⣭⣶⣤⡀        ⣤⣤⣤⣤⣤         
#> t 0.02   ⢠⣤⣤⣤⣾⣥⣤⣤⣤⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣭⣶⣦⣤⣄⣀⣀⣀⣀⣿⣿⣿⣿⣿         
#> y        ⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇    ⣿⣿⣿⣿⣿⣽⣶⣤⣤⡄    
#>      0   ⠸⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠧⠤⠤⠤⠤⠿⠿⠿⠿⠿⠿⠿⠿⠿⠇    
#>          10.0     15.0     20.0    25.0     30.0     35.0    
#>                               mpg                            
#> 
# Points with smooth line
p <- ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point(color = "gray") +
  geom_smooth(method = "loess", color = "red") +
  labs(title = "Scatter with LOESS Smooth")
suppressMessages(ggplotcli(p, width = 60, height = 12))
#> 
#>                 Scatter with LOESS Smooth                    
#>                                                              
#>   35.0   ⢐⢤⣀⣀⠁   ⠐                                           
#> m 30.0       ⠉⠲⠢⢄⡀                                           
#> p 25.0           ⠉⠉⡒⠤⣀⣀      ⡐                               
#> g 20.0              ⠈ ⠐⠉⠩⠙⠒⠒⠢⠬⢄⣀⣠    ⠠                       
#>   15.0                       ⠄  ⢈⠩⡒⠒⢣⠤⠤⢄⣂⣀⣀            ⡀     
#>   10.0                               ⠁     ⠉⠉⠉⠉⠑⠒⠒⠒⠒⠢⠤⡤⠤⡄    
#>                                                              
#>               2.0         3.0         4.0         5.0        
#>                                wt                            
#> 

Faceting

facet_wrap with Color Aesthetics

Faceting works seamlessly with color/fill aesthetics and legends:

mtcars$cyl_fac <- factor(mtcars$cyl)
p <- ggplot(mtcars, aes(x = wt, y = mpg, color = cyl_fac)) +
  geom_point() +
  facet_wrap(~cyl_fac) +
  labs(title = "MPG vs Weight: Faceted by Cylinders")
ggplotcli(p, width = 75, height = 16)
#> 
#>                    MPG vs Weight: Faceted by Cylinders                          
#>                 4                     6                     8                   
#>         ⠠                                                                       
#>           ⠁                                                                     
#>   30.0 ⠉                                                                        
#>          ⠂⡀                                                                cyl  
#>                ⠄                                                           * 4  
#>            ⢁ ⡀⠈                   ⡀⢀ ⡀                                     * 6  
#>   20.0                             ⠄  ⠄                     ⡀ ⠄            * 8  
#>                                       ⠃                      ⠠ ⡀                
#>                                                            ⠁⢒⠐       ⠄          
#>                                                               ⠁                 
#>   10.0                                                              ⠐⠐          
#>         2.0      4.0          2.0      4.0          2.0      4.0                
#>                                                                                 
#> 

facet_grid

p <- ggplot(mtcars, aes(x = wt, y = mpg, color = factor(gear))) +
  geom_point() +
  facet_grid(am ~ cyl) +
  labs(title = "MPG: AM (rows) x Cylinders (cols)")
ggplotcli(p, width = 80, height = 20)
#> 
#>                       MPG: AM (rows) x Cylinders (cols)                              
#>                0, 4                    0, 6                    0, 8                  
#>                                                                                      
#>   30.0                                                                               
#>                 ⡀                                                                    
#>   20.0      ⠄  ⠐                        ⠄                                            
#>                                          ⠆                       ⠂⢀⠂                 
#>                                                                  ⠊⠄⡂⠈      ⠂    fac  
#>   10.0                                                                    ⠠⠠    * 3  
#>                1, 4                    1, 6                    1, 8             * 4  
#>         ⠐ ⢀                                                                     * 5  
#>   30.0 ⠒                                                                             
#>          ⠁⠐                                                                          
#>   20.0     ⠂ ⠠                       ⡀⡀                                              
#>                                      ⠈                                               
#>                                                                ⠈  ⠂                  
#>   10.0                                                                               
#>         2.0        4.0          2.0        4.0          2.0        4.0               
#>                                                                                      
#> 

Styling Options

Borders and Grid Lines

p <- ggplot(mtcars, aes(x = hp, y = qsec)) +
  geom_point(color = "cyan") +
  labs(title = "Quarter Mile Time vs HP")

# With border
ggplotcli(p, width = 55, height = 12, border = TRUE)
#> 
#>                Quarter Mile Time vs HP                  
#>        ⡏⠉⠉⠉⠉⠉⠉⠉⠉⡉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢹  
#>   22.0 ⡇                                             ⢸  
#> q      ⡇         ⢀                                   ⢸  
#> s 20.0 ⡇   ⠈⡃   ⠈ ⠐ ⡀                                ⢸  
#> e 18.0 ⡇  ⠁     ⠁ ⠁ ⠂       ⢠   ⠄⠠ ⢀                 ⢸  
#> c      ⡇       ⠐  ⠸     ⠃  ⠈                         ⢸  
#>   16.0 ⡇                   ⠐         ⠘            ⢀  ⢸  
#>        ⣇⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣈⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣸  
#>        50.0    100     150    200    250     300        
#>                             hp                          
#> 

# With grid
ggplotcli(p, width = 55, height = 12, grid = "major")
#> 
#>                Quarter Mile Time vs HP                  
#>          ⡇     ⠐⢸       ⡇      ⡇      ⢸       ⡇         
#>   22.0 ⠉⠉⡏⠉⠉⠉⠉⠉⠉⢹⠉⠉⠉⠉⠉⠉⠉⡏⠉⠉⠉⠉⠉⠉⡏⠉⠉⠉⠉⠉⠉⢹⠉⠉⠉⠉⠉⠉⠉⡏⠉⠉⠉⠉⠉⠉⠉  
#> q      ⣀⣀⣇⣀⣀⣀⣀⣀⣀⣸⣄⣀⣀⣀⣀⣀⣀⣇⣀⣀⣀⣀⣀⣀⣇⣀⣀⣀⣀⣀⣀⣸⣀⣀⣀⣀⣀⣀⣀⣇⣀⣀⣀⣀⣀⣀⣀  
#> s 20.0   ⡇ ⡂    ⢸ ⠂⢀    ⡇      ⡇      ⢸       ⡇         
#> e 18.0 ⠤⠤⡧⠤⠤⠤⠤⠤⠥⢼⠬⠤⠴⠤⠤⠤⠤⡧⠤⠤⠤⡤⠤⠤⡧⠤⠤⠤⠤⠤⠤⢼⠤⠤⠤⠤⠤⠤⠤⡧⠤⠤⠤⠤⠤⠤⠤  
#> c        ⡇     ⠄⢸ ⡆     ⡇  ⠐⠁  ⡇   ⠈  ⢸       ⡇         
#>   16.0 ⠒⠒⡗⠒⠒⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⠒⠒⡗⠒⠒⠲⠒⠒⠒⡗⠒⠒⠒⠒⠒⠒⣺⠒⠒⠒⠒⠒⠒⠒⡗⠒⠒⠒⠒⠒⠒⠒  
#>          ⡇      ⢸       ⡇      ⡇      ⢸  ⠄    ⡇    ⠐    
#>        50.0    100     150    200    250     300        
#>                             hp                          
#> 

# Both
ggplotcli(p, width = 55, height = 12, border = TRUE, grid = "major")
#> 
#>                Quarter Mile Time vs HP                  
#>        ⡏⠉⢹⠉⠉⠉⠉⠉⠉⡉⡏⠉⠉⠉⠉⠉⠉⡏⠉⠉⠉⠉⠉⠉⡏⠉⠉⠉⠉⠉⠉⢹⠉⠉⠉⠉⠉⠉⢹⠉⠉⠉⠉⠉⠉⠉⢹  
#>   22.0 ⡧⠤⢼⠤⠤⠤⠤⠤⠤⠤⡧⠤⠤⠤⠤⠤⠤⡧⠤⠤⠤⠤⠤⠤⡧⠤⠤⠤⠤⠤⠤⢼⠤⠤⠤⠤⠤⠤⢼⠤⠤⠤⠤⠤⠤⠤⢼  
#> q      ⡇ ⢸       ⣇      ⡇      ⡇      ⢸      ⢸       ⢸  
#> s 20.0 ⡏⠉⢹⠉⠉⡋⠉⠉⠉⠉⡏⠙⠉⡉⠉⠉⠉⡏⠉⠉⠉⠉⠉⠉⡏⠉⠉⠉⠉⠉⠉⢹⠉⠉⠉⠉⠉⠉⢹⠉⠉⠉⠉⠉⠉⠉⢹  
#> e 18.0 ⡧⠤⢼⠥⠤⠤⠤⠤⠤⠥⡧⠥⠤⠦⠤⠤⠤⡧⠤⠤⠤⢤⠤⠤⡧⠤⠤⠤⢤⠤⠤⢼⠤⠤⠤⠤⠤⠤⢼⠤⠤⠤⠤⠤⠤⠤⢼  
#> c      ⣇⣀⣸⣀⣀⣀⣀⣀⣐⣀⣇⣸⣀⣀⣀⣀⣀⣇⣀⣀⣈⣀⣀⣀⣇⣀⣀⣀⣀⣀⣀⣸⣀⣀⣀⣀⣀⣀⣸⣀⣀⣀⣀⣀⣀⣀⣸  
#>   16.0 ⡇ ⢸       ⡇      ⡇  ⠐   ⡇     ⠘⢸      ⢸    ⢀  ⢸  
#>        ⣇⣀⣸⣀⣀⣀⣀⣀⣀⣀⣇⣀⣀⣀⣀⣀⣀⣇⣀⣀⣀⣀⣀⣀⣇⣀⣀⣀⣀⣀⣀⣸⣀⣈⣀⣀⣀⣀⣸⣀⣀⣀⣀⣀⣀⣀⣸  
#>        50.0    100     150    200    250     300        
#>                             hp                          
#> 

Theme Auto-Detection

ggplotcli automatically respects ggplot2 themes:

p <- ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point(color = "blue") +
  labs(title = "theme_bw() - Grid + Border")

# theme_bw has both grid and border
ggplotcli(p + theme_bw(), width = 60, height = 14, border = "auto", grid = "auto")
#> 
#>                 theme_bw() - Grid + Border                   
#>   35.0 ⣏⣉⣉⣏⣉⣉⣉⣉⣉⣏⣉⣉⣉⣉⣹⣉⣉⣉⣉⣉⣹⣉⣉⣉⣉⣉⣏⣉⣉⣉⣉⣉⣏⣉⣉⣉⣉⣹⣉⣉⣉⣉⣉⣹⣉⣉⣉⣉⣉⣏⣉⣹  
#>        ⡧⠤⠤⡧⠤⠤⠤⠥⠤⡧⠤⠤⠤⠤⢼⠤⠤⠤⠤⠤⢼⠤⠤⠤⠤⠤⡧⠤⠤⠤⠤⠤⡧⠤⠤⠤⠤⢼⠤⠤⠤⠤⠤⢼⠤⠤⠤⠤⠤⡧⠤⢼  
#>   30.0 ⡗⠒⠒⡟⠚⠒⠒⠒⠒⡗⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⡗⠒⠒⠒⠒⠒⡗⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⡗⠒⢺  
#> m      ⡯⠭⠭⡯⠭⠭⠭⠭⠯⡯⠭⠭⠭⠭⢽⠭⠭⠭⠭⠭⢽⠭⠭⠭⠭⠭⡯⠭⠭⠭⠭⠭⡯⠭⠭⠭⠭⢽⠭⠭⠭⠭⠭⢽⠭⠭⠭⠭⠭⡯⠭⢽  
#> p 25.0 ⡗⠒⠒⡗⠒⠒⠒⠒⠒⡗⠒⠒⢒⠒⢺⠒⠒⠒⠒⠒⢺⠒⡚⠒⠒⠒⡗⠒⠒⠒⠒⠒⡗⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⡗⠒⢺  
#> g 20.0 ⡯⠭⠭⡯⠭⠭⠭⠭⠭⡯⠭⠭⠭⠭⢽⠭⠯⢭⠯⠯⢽⠭⠭⠯⠭⢭⡯⠭⠭⠭⡭⠭⡯⠭⠭⠭⠭⢽⠭⠭⠭⠭⠭⢽⠭⠭⠭⠭⠭⡯⠭⢽  
#>        ⡗⠒⠒⡗⠒⠒⠒⠒⠒⡗⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⢺⠒⠒⠒⠒⠚⡗⠒⠒⠖⠒⠒⣗⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⡗⠒⢺  
#>   15.0 ⣏⣉⣉⣏⣉⣉⣉⣉⣉⣏⣉⣉⣉⣉⣹⣉⣉⣉⣉⣉⣹⣉⣉⣉⣉⣙⣟⣏⣉⣙⣉⣉⣏⣉⣉⣉⣉⣹⣉⣉⣉⣉⣉⣹⣉⣉⣉⣩⣉⣏⣉⣹  
#>        ⡗⠒⠒⡗⠒⠒⠒⠒⠒⡗⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⡗⠒⠒⠒⠒⠒⡗⠒⠒⠒⠒⢺⠒⠒⠒⠒⠒⢺⠒⠒⡒⠒⢒⡗⠒⢺  
#>   10.0 ⣏⣉⣉⣏⣉⣉⣉⣉⣉⣏⣉⣉⣉⣉⣹⣉⣉⣉⣉⣉⣹⣉⣉⣉⣉⣉⣏⣉⣉⣉⣉⣉⣏⣉⣉⣉⣉⣹⣉⣉⣉⣉⣉⣹⣉⣉⣉⣉⣉⣏⣉⣹  
#>               2.0         3.0         4.0         5.0        
#>                                wt                            
#> 

# theme_classic has border but no grid
ggplotcli(p + theme_classic() + labs(title = "theme_classic() - Border Only"), 
           width = 60, height = 14, border = "auto", grid = "auto")
#> 
#>               theme_classic() - Border Only                  
#>   35.0 ⡏⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢹  
#>        ⡇      ⠁   ⠄                                       ⢸  
#>   30.0 ⡇  ⠈⠈                                              ⢸  
#> m      ⡇       ⠂ ⠠                                        ⢸  
#> p 25.0 ⡇           ⢀         ⡈                            ⢸  
#> g 20.0 ⡇             ⠁ ⠂⢀⠂⠂   ⠂ ⢀    ⡀                    ⢸  
#>        ⡇                        ⠘   ⠄  ⢀                  ⢸  
#>   15.0 ⡇                     ⠈  ⠐⠐⠆ ⠐⡀                ⠠   ⢸  
#>        ⡇                                             ⡀ ⢀  ⢸  
#>   10.0 ⣇⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣸  
#>               2.0         3.0         4.0         5.0        
#>                                wt                            
#> 

Canvas Types

Three rendering modes are available:

wave <- ggplot(data.frame(x = 1:25, y = sin(1:25/4)*8), aes(x, y)) +
  geom_line(color = "green")

# Braille (highest resolution - 2x4 dots per character)
ggplotcli(wave + labs(title = "Braille Canvas (highest resolution)"), 
           width = 50, height = 8, canvas_type = "braille")
#> 
#>       Braille Canvas (highest resolution)          
#>            ⢀⣀⠤⠔⠒⠒⠒⠒⠒⠒⠤⢄⡀                           
#> y  5.0   ⠔⠊⠁           ⠈⠑⠤⣀                        
#>   -5.0                     ⠉⠑⠢⢄⡀           ⣀⠤⠒⠉    
#>                                ⠈⠑⠢⠤⠤⠤⠤⠤⠤⠒⠊⠉        
#>        0      5.0    10.0    15.0   20.0    25.0   
#>                           x                        
#> 

# Block (medium resolution - uses block characters)
ggplotcli(wave + labs(title = "Block Canvas (medium resolution)"), 
           width = 50, height = 8, canvas_type = "block")
#> 
#>         Block Canvas (medium resolution)           
#>             ▄▄▄▀▀▀▀▀▄▄▄                            
#> y  5.0   ▄▀▀           ▀▀▀▄▄                       
#>   -5.0                      ▀▄▄▄           ▄▄▀▀    
#>                                 ▀▀▀▄▄▄▄▄▀▀▀        
#>        0      5.0    10.0    15.0   20.0    25.0   
#>                           x                        
#> 

# ASCII (basic, most compatible)
ggplotcli(wave + labs(title = "ASCII Canvas (most compatible)"), 
           width = 50, height = 8, canvas_type = "ascii")
#> 
#>          ASCII Canvas (most compatible)            
#>               *********                            
#> y  5.0   *****         *****                       
#>   -5.0                      ****         ******    
#>                                 *********          
#>        0      5.0    10.0    15.0   20.0    25.0   
#>                           x                        
#> 

Color Mapping

ggplotcli intelligently maps ggplot2 colors to terminal colors (red, yellow, green, cyan, blue, magenta). The mapping prioritizes color distinctness over hue accuracy to maximize visual differentiation between groups.

Many Groups (8+)

Even with many groups, colors are distributed to minimize repetition:

set.seed(123)
df <- data.frame(
  group = factor(rep(paste0("G", 1:8), each = 30)),
  value = unlist(lapply(1:8, function(i) rnorm(30, mean = i * 2, sd = 1.5)))
)
p <- ggplot(df, aes(x = group, y = value, fill = group)) +
  geom_boxplot() +
  labs(title = "8 Groups with Optimized Color Distribution")
ggplotcli(p, width = 85, height = 18, boxplot_style = "ascii")
#> 
#>                     8 Groups with Optimized Color Distribution                             
#>                                                                            ─────           
#>                                                            *      ─────   ┌─────┐    grou  
#>                                                            *     ┌─────┐  └─────┘    * G1  
#>   15.0                                                   ─────   │─────│   ─────     * G2  
#> v                                              ─────    ┌─────┐  └─────┘             * G3  
#> a                                     ─────   ┌─────┐   └─────┘                      * G4  
#> l 10.0                         *     ┌─────┐  │─────│                                * G5  
#> u                  ─────     ─────   └─────┘  └─────┘                                * G6  
#> e                    │      └─────┘   ─────                                          * G7  
#>    5.0    ─────   ┌─────┐    ─────                                                   * G8  
#>          ┌─────┐  └─────┘      *                                                           
#>          └─────┘   ─────                                                                   
#>      0    ─────                                                                            
#>                                                                                            
#>                      2.0               4.0                6.0               8.0            
#>                                           group                                            
#> 

Showcase: Maximum Complexity

Complex Faceted Boxplot

set.seed(42)
df <- data.frame(
  treatment = factor(rep(c("Control", "Drug A", "Drug B"), each = 60)),
  timepoint = factor(rep(rep(c("Baseline", "Week 4", "Week 8"), each = 20), 3)),
  response = c(
    rnorm(20, 50, 10), rnorm(20, 52, 10), rnorm(20, 51, 10),  # Control
    rnorm(20, 50, 10), rnorm(20, 65, 12), rnorm(20, 70, 11),  # Drug A
    rnorm(20, 50, 10), rnorm(20, 58, 11), rnorm(20, 62, 10)   # Drug B
  )
)

p <- ggplot(df, aes(x = timepoint, y = response)) +
  geom_boxplot(aes(fill = treatment)) +
  labs(title = "Treatment Response Over Time",
       subtitle = "Faceted by treatment group",
       x = "Timepoint", y = "Response") +
  theme_bw()

ggplotcli(p, width = 100, height = 22, boxplot_style = "ascii")
#> 
#>                                    Treatment Response Over Time                                                
#>                                     Faceted by treatment group                                                 
#>        ⡏⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢹            
#>    100 ⡇                                                                                          ⢸            
#>        ⡇                                                                        *                 ⢸            
#>        ⡇                                          ─────                         *                 ⢸            
#> R 80.0 ⡇                                            │                         ─────  ─────        ⢸            
#> e      ⡇       ─────                             ┌─────┐   *                    │      │          ⢸ treatment  
#> s      ⡇         │                         ───── │     │   *           ───── ┌─────┐┌─────┐       ⢸ * Control  
#> p      ⡇      ┌─────┐ ─────  ─────           │   │─────│ ─────           │   └─────┘│─────│       ⢸ * Drug A   
#> o 60.0 ⡇      │     │┌─────┐   │          ┌─────┐└─────┘┌─────┐       ┌─────┐   │   └─────┘       ⢸ * Drug B   
#> n      ⡇      │─────││─────│┌─────┐       │     │   │   └─────┘       │─────│ ──*──    │          ⢸            
#> s      ⡇      └─────┘│     ││─────│       │─────│ ─────    │          └─────┘        ─────        ⢸            
#> e      ⡇         │   └─────┘└─────┘       └─────┘        ──*──           │             *          ⢸            
#>   40.0 ⡇         │    ─────    │             │                         ─────                      ⢸            
#>        ⡇         │           ─────           │                                                    ⢸            
#>        ⡇       ─────                       ─────                                                  ⢸            
#>   20.0 ⡇                                                                 *                        ⢸            
#>        ⣇⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣸            
#>         0.50           1.0           1.5            2.0           2.5           3.0           3.5              
#>                                                Timepoint                                                       
#> 

Multi-Layer Scientific Plot

# Simulated experiment data
set.seed(123)
x <- seq(0, 10, length.out = 50)
df <- data.frame(
  x = rep(x, 3),
  y = c(
    2 * x + rnorm(50, 0, 1.5),
    1.5 * x + 3 + rnorm(50, 0, 1.2),
    x^1.2 + rnorm(50, 0, 1)
  ),
  group = rep(c("Linear", "Offset", "Power"), each = 50)
)

p <- ggplot(df, aes(x = x, y = y, color = group)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "loess", se = FALSE) +
  labs(title = "Multi-Group Regression Analysis",
       subtitle = "Points with LOESS smoothing",
       x = "Predictor", y = "Response") +
  theme_minimal()

suppressMessages(ggplotcli(p, width = 70, height = 18))
#> 
#>                   Multi-Group Regression Analysis                               
#>                     Points with LOESS smoothing                                 
#>                                                            ⠄    ⠠               
#>   20.0                                                      ⠂⢀⡐⣤⢰⣾              
#> R                                                      ⡀⣠⡄⣶⢰⣇⣿⣿⣿⣿⣿              
#> e 15.0                                         ⢀⢀⠠⡀⣤⣠⣾⣸⣯⣿⣿⣿⣿⣿⣿⡟⣿⢹⠿    group     
#> s                                          ⠂⡀⡀⣬⢰⣾⣸⣧⣿⣾⣿⣿⣿⣿⡟⣿⠹⠇⠛⢁⠁ ⠈    * Linear  
#> p                              ⢀   ⡀  ⠐⠐⣀⣠⢠⣦⣿⣷⣿⣿⣿⢿⡟⣿⢻⠿⠸⠃⠋⠡ ⠂⠁         * Offset  
#> o 10.0                        ⠠  ⡀⣠⢠⣴⢴⡇⣿⣷⣿⣿⡟⣿⡏⡿⢸⠛⠘⠁⡁  ⠈               * Power   
#> n                         ⡀⣥⡆⣶⢰⣿⢸⡇⣿⣸⣿⣿⡿⣿⡯⠿⠘⠃⠉   ⠐                               
#> s            ⡀ ⠐  ⢄⣀⢤⡆⣶⣖⣿⢸⡇⣿⣇⣿⣼⣿⢾⡟⡿⡹⠟⠘⠑⠁ ⠈                                      
#> e  5.0    ⢀⡀⣠⢠⣴⢰⡇⣿⢸⣿⢸⡇⣿⣧⣿⣾⡿⣿⡟⡿⠹⠫⠈ ⠂                                             
#>           ⣿⡇⣿⢸⣿⣸⣿⣿⢾⣿⢻⡟⠿⠃⠛⠈⠁                                                     
#>      0    ⣿⡷⣿⠿⢿⠙⠣⠋⡊⠁   ⠈                                                        
#>           ⠋                                                                     
#>           0         2.0        4.0        6.0        8.0       10.0             
#>                                 Predictor                                       
#> 

Dense Scatter with Facets

p <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, color = Species)) +
  geom_point() +
  facet_wrap(~Species) +
  labs(title = "Iris Dataset: Sepal vs Petal Length",
       subtitle = "Faceted by species with color legend") +
  theme_bw()

ggplotcli(p, width = 80, height = 16)
#> 
#>                      Iris Dataset: Sepal vs Petal Length                                      
#>               setosa                versicolor               virginica                        
#>       ⡏⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢹ ⡏⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢹ ⡏⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢹                 
#>       ⡇                     ⢸ ⡇                     ⢸ ⡇                ⢀ ⠜⢀ ⢸                 
#>    6.0⡇                     ⢸ ⡇                     ⢸ ⡇           ⠐⠠⢠⢄⠠⠆⠂⠐  ⢸                 
#>       ⡇                     ⢸ ⡇         ⢀   ⢀       ⢸ ⡇        ⣀⣀⠁⢊⢫⠨⢑      ⢸   Species       
#>       ⡇                     ⢸ ⡇      ⠠⡠⠄⠡⠆⣜⡤⣔⠉⠂     ⢸ ⡇    ⠄  ⠈ ⠈⠁⠉         ⢸   * setosa      
#>    4.0⡇                     ⢸ ⡇     ⠠ ⡾⠳⠑⠂          ⢸ ⡇                     ⢸   * versicolor  
#>       ⡇                     ⢸ ⡇    ⠚⡀ ⠈⠁            ⢸ ⡇                     ⢸   * virginica   
#>       ⡇                     ⢸ ⡇                     ⢸ ⡇                     ⢸                 
#>    2.0⡇   ⠠ ⡄⢀ ⡀            ⢸ ⡇                     ⢸ ⡇                     ⢸                 
#>       ⡇ ⡐⢚⠛⠻⠛⠙⠂⠡            ⢸ ⡇                     ⢸ ⡇                     ⢸                 
#>       ⣇⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣸ ⣇⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣸ ⣇⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣸                 
#>           5.0  6.0   7.0   8.0    5.0  6.0   7.0   8.0    5.0  6.0   7.0   8.0                
#>                                                                                               
#> 

Supported Features Summary

Feature Status
geom_point
geom_line, geom_path
geom_bar, geom_col, geom_histogram
geom_density
geom_smooth
geom_area
geom_segment, geom_hline, geom_vline
geom_rect
geom_text
geom_boxplot
Color/fill aesthetics
Legends (auto-generated)
facet_wrap, facet_grid
Titles, subtitles, captions
Theme auto-detection
Optimized color mapping
Multiple canvas types
geom_tile (heatmaps) Planned
geom_violin Planned