20

In order to access my server, I am forced to work with an old text terminal application that does not have X windows. The best thing I have going is emacs/ESS.

Often, I wish to make a rudimentary plots such as histograms and scatter plots and not have to go through the trouble of transferring the file to a computer with a graphics display.

Is there a text terminal-based R graphics library?

Glen_b
  • 7,883
  • 2
  • 37
  • 48
Eric Brown
  • 399
  • 4
  • 9

1 Answers1

33

There are a number of things that can do bits of it. There's stem in default R, there's this scatter plot function, but best of all, there's the package txtplot on CRAN which does scatterplots, boxplots, barplots, density traces, acfs and plots curves (like the curve function... kinda).

I only need it once in a while - but if I am trying to convey a rough idea of a graphic in pure text as I sometimes need to, it's a life-saver.

In the past I wrote a short piece of R code that made tally-style ascii graphic in very quick time (like a sideways barchart or a stem-and-leaf plot with the numbers replaced by symbols, which solved a problem I had) - but I didn't keep it since stem mostly covers that territory.

Of course the 'table' facility produces ascii output and can be manipulated to do some interesting/useful semigraphical things.

There's also the package ascii that can be used to render various R objects into ascii form in similar fashion to Sweave - handy for formatting tables and so on. Just formatting a table into ascii is not really what it's for but you might still be able to get some use out of it with a little work and the right output format.

Sample output from txtplot:

scatter plot:

 > with(cars,txtplot(speed,dist))
     +----+-----------+------------+-----------+-----------+--+
 120 +                                                   *    +
     |                                                        |
 100 +                                                        +
     |                                                   * *  |
  80 +                          *         *                   +
     |                                       *      *    *    |
  60 +                          *              *              +
     |                             *    * *    *      *       |
  40 +                        *      *  * *  *                +
     |                *       * *    *  *    * *              |
  20 +         *      *  * *  * *  *                          +
     |           *    *  * *                                  |
     |  *      *    *                                         |
   0 +----+-----------+------------+-----------+-----------+--+
          5          10           15          20          25   

acf plot:

 > txtacf(ldeaths)
      +-+--------------+--------------+--------------+--------+
    1 + *                                                     +
      | *                                                     |
      | *  *                        * *  *                    |
  0.5 + *  *                        * *  *                    +
      | *  * *                   *  * *  * *                  |
      | *  * *                   *  * *  * *                  |
      | *  * *                   *  * *  * *                  |
    0 + *  * *  * *  * *  * *  * *  * *  * *  * *  * *  * *   +
      |           *  * *  * *                   *  * *  * *   |
      |           *  * *  * *                   *  * *  * *   |
      |           *  * *  * *                      * *  * *   |
 -0.5 +              * *  *                        * *  *     +
      |              * *  *                          *        |
      +-+--------------+--------------+--------------+--------+
        0             0.5             1             1.5        

density trace:

 > txtdensity(rnorm(100,m=5,s=.1))
   +------+----------+----------+----------+----------+-------+
   |                           *****                          |
 4 +                          **   ***                        +
   |                         *       ***                      |
   |                        **         ***                    |
 3 +                       **            ***                  +
   |                     ***               **                 |
   |                 *****                   **               |
 2 +               ***                        **              +
   |             ***                           **             |
   |            **                              **            |
 1 +           **                                ***          +
   |         ***                                   ******     |
   |  ********                                          ***   |
   +------+----------+----------+----------+----------+-------+
         4.8        4.9         5         5.1        5.2       
 

box plot:

 > vc <- ToothGrowth[,2]=="VC"
 > oj <- ToothGrowth[,2]=="OJ"
 > txtboxplot(ToothGrowth[vc,1],ToothGrowth[oj,1])
       5      10       15       20       25       30      35   
  |----+-------+--------+--------+--------+--------+-------+--|
                  +--------+-----------+                       
 1   -------------|        |           |------------------     
                  +--------+-----------+                       
                         +------------+----+                   
 2          -------------|            |    |---------          
                         +------------+----+                   
 Legend: 1=ToothGrowth[vc, 1], 2=ToothGrowth[oj, 1]

curve plot:

 > txtcurve(sin(pi*x),from=0,to=2)
      +--+-----------+------------+------------+-----------+--+
    1 +          *********                                    +
      |        ***        **                                  |
      |       **            **                                |
  0.5 +     **               **                               +
      |    **                  **                             |
      |   *                     **                            |
    0 +  *                       **                        *  +
      |                            *                      *   |
      |                             **                  **    |
 -0.5 +                              ***               **     +
      |                                **            **       |
      |                                  **        ***        |
   -1 +                                    *********          +
      +--+-----------+------------+------------+-----------+--+
         0          0.5           1           1.5          2   

bar chart:

 > txtbarchart(as.factor(res),pch="|")
    +--+------------+------------+------------+------------+--+
 50 +  |                                                      +
    |  |                                                      |
 40 +  |                                                      +
    |  |                                                      |
 30 +  |                         |                            +
    |  |                         |                            |
    |  |                         |                            |
 20 +  |                         |                         |  +
    |  |                         |                         |  |
 10 +  |                         |                         |  +
    |  |                         |                         |  |
  0 +  |                         |                         |  +
    +--+------------+------------+------------+------------+--+
       1           1.5           2           2.5           3   
 Legend: 1=A, 2=B, 3=C

Add in the stem function from default R graphics:

> stem(log(islands,10))

  The decimal point is at the |

  1 | 1111112222233444
  1 | 5555556666667899999
  2 | 3344
  2 | 59
  3 | 
  3 | 5678
  4 | 012

and you have quite a lot of coverage.

David LeBauer
  • 31,011
  • 31
  • 115
  • 189
Glen_b
  • 7,883
  • 2
  • 37
  • 48
  • 2
    Here's some code for a ASCII world map plot: https://gist.github.com/nevrome/d071bc9d636a2f32991f8d984d6f25ef – nevrome May 09 '20 at 14:01
  • Not mentioned in the answer, but you can also get a "histogram" (sort of) via `txtbarchart(cut(x,...))` but the y-axis won't generally be what you'd get using `hist`. – Glen_b Oct 10 '20 at 10:56
  • Thanks! This made my day :) – webb Jan 07 '22 at 23:22
  • Thank you! This is really fun and useful, and thank you for all the examples. One follow up, how come the ticks on the y axis are not matching the values of the data? For me they're always between 0 and 50 for txtbarchart even when i know that there are larger numbers than that – Laserhedvig May 10 '22 at 14:14
  • Bar charts are for count data. The y-axis of bar charts should only ever display counts (or proportions). The x-axis should display categories. If you use txtbarchart to make something like a histogram then the x-axis should have data values (which `cut` gives you), and the y should still be counts or proportions. If you're using a bar chart for a purpose it's not suited to, you can hardly blame the display for that. (Are you in biology? There seems to be wide misuse of displays in this fashion there, such as dynamite plots...) – Glen_b May 10 '22 at 22:43
  • If you are nevertheless seeking something that reproduces a dynamite plot (with or without the handle) - i.e. where the y-axis is data values rather than frequencies in a category - the best best is probably to take the code for something like txtbarchart and modify it so it does what you need (or even to write one from scratch; code wise ascii displays are relatively simple to write). – Glen_b May 10 '22 at 23:01