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