ttt
: Formatted Tables the Easy Wayttt
stands for “The Table Tool” (or, if you prefer “Tables! Tables! Tables!”). It allows you to creates formatted HTML tables of in a flexible and convenient way.
Creating nice formatted tables has traditionally been a pain points with R. Over the years, however, things have gotten a lot better, with the emergence of packages that can produce nice looking tables in HTML (or LaTex or even Microsoft® Word), or which there are now a large number.1 But most of those packages treat tables just like data.frames
, i.e. a grid of rows and columns, with very little structure. While some packages do have constructs that allow you to group columns or rows with additional headers and labels, that structure is basically superficial, tacked onto the data.frame
after the fact. And while it may achieve the desired result it tends to require more code and by consequence, effort. Another thing that some of these packages do is they give you the flexibility to control the visual appearance or styling of the tables (fonts, colors, grid lines, spacing, etc.) directly from the R code. This is nice, but typically achieving that level of flexibility requires a pretty complex interface of functions and arguments dedicated to styling, and achieving the desired result can take a considerable amount of code and hence again, effort.
This package takes a different approach. It focuses on the table structure and content, leaving the formatting duties to CSS, a dedicated language that was designed specifically for this purpose (the downside is that it only works for HTML, but we accept this inconvenience). Also, the package follows the philosophy of not trying to solve all problems, but solving some problems well. Design decisions have been made to make some things easy, at the expense of limiting the package’s generality (while still keeping in it some sense quite general, as this vignette will demonstrate). That it is not possible with this package to produce all conceivable tables is a given; that was never the intention.
Before we start, let’s load a couple of packages that we will be using:
library(table1, quietly=T)
library(magrittr, quietly=T)
It is worth taking a minute to comment on these packages. The first, table1
, is like a “sister” package of ttt
(they are both written by the same author). While not a strict requirement, table1
contains some utility functions that can also be quite useful in conjunction with ttt
, so most of the time it is a good idea to load table1
along with ttt
. The magrittr
package contains the well-known “pipe” operator that we will make use of at some point in this vignette, so we load that, too.
With that out of the way, let’s start looking at what ttt
can do, and how to use it. The types of tables that can be produced are many and varied. At its simplest, the ttt()
function can turn a data.frame
into an HTML table:
ttt(mtcars)
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb | |
---|---|---|---|---|---|---|---|---|---|---|---|
Mazda RX4 | 21.0 | 6 | 160.0 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
Mazda RX4 Wag | 21.0 | 6 | 160.0 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
Datsun 710 | 22.8 | 4 | 108.0 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
Hornet 4 Drive | 21.4 | 6 | 258.0 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
Hornet Sportabout | 18.7 | 8 | 360.0 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
Valiant | 18.1 | 6 | 225.0 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
Duster 360 | 14.3 | 8 | 360.0 | 245 | 3.21 | 3.570 | 15.84 | 0 | 0 | 3 | 4 |
Merc 240D | 24.4 | 4 | 146.7 | 62 | 3.69 | 3.190 | 20.00 | 1 | 0 | 4 | 2 |
Merc 230 | 22.8 | 4 | 140.8 | 95 | 3.92 | 3.150 | 22.90 | 1 | 0 | 4 | 2 |
Merc 280 | 19.2 | 6 | 167.6 | 123 | 3.92 | 3.440 | 18.30 | 1 | 0 | 4 | 4 |
Merc 280C | 17.8 | 6 | 167.6 | 123 | 3.92 | 3.440 | 18.90 | 1 | 0 | 4 | 4 |
Merc 450SE | 16.4 | 8 | 275.8 | 180 | 3.07 | 4.070 | 17.40 | 0 | 0 | 3 | 3 |
Merc 450SL | 17.3 | 8 | 275.8 | 180 | 3.07 | 3.730 | 17.60 | 0 | 0 | 3 | 3 |
Merc 450SLC | 15.2 | 8 | 275.8 | 180 | 3.07 | 3.780 | 18.00 | 0 | 0 | 3 | 3 |
Cadillac Fleetwood | 10.4 | 8 | 472.0 | 205 | 2.93 | 5.250 | 17.98 | 0 | 0 | 3 | 4 |
Lincoln Continental | 10.4 | 8 | 460.0 | 215 | 3.00 | 5.424 | 17.82 | 0 | 0 | 3 | 4 |
Chrysler Imperial | 14.7 | 8 | 440.0 | 230 | 3.23 | 5.345 | 17.42 | 0 | 0 | 3 | 4 |
Fiat 128 | 32.4 | 4 | 78.7 | 66 | 4.08 | 2.200 | 19.47 | 1 | 1 | 4 | 1 |
Honda Civic | 30.4 | 4 | 75.7 | 52 | 4.93 | 1.615 | 18.52 | 1 | 1 | 4 | 2 |
Toyota Corolla | 33.9 | 4 | 71.1 | 65 | 4.22 | 1.835 | 19.90 | 1 | 1 | 4 | 1 |
Toyota Corona | 21.5 | 4 | 120.1 | 97 | 3.70 | 2.465 | 20.01 | 1 | 0 | 3 | 1 |
Dodge Challenger | 15.5 | 8 | 318.0 | 150 | 2.76 | 3.520 | 16.87 | 0 | 0 | 3 | 2 |
AMC Javelin | 15.2 | 8 | 304.0 | 150 | 3.15 | 3.435 | 17.30 | 0 | 0 | 3 | 2 |
Camaro Z28 | 13.3 | 8 | 350.0 | 245 | 3.73 | 3.840 | 15.41 | 0 | 0 | 3 | 4 |
Pontiac Firebird | 19.2 | 8 | 400.0 | 175 | 3.08 | 3.845 | 17.05 | 0 | 0 | 3 | 2 |
Fiat X1-9 | 27.3 | 4 | 79.0 | 66 | 4.08 | 1.935 | 18.90 | 1 | 1 | 4 | 1 |
Porsche 914-2 | 26.0 | 4 | 120.3 | 91 | 4.43 | 2.140 | 16.70 | 0 | 1 | 5 | 2 |
Lotus Europa | 30.4 | 4 | 95.1 | 113 | 3.77 | 1.513 | 16.90 | 1 | 1 | 5 | 2 |
Ford Pantera L | 15.8 | 8 | 351.0 | 264 | 4.22 | 3.170 | 14.50 | 0 | 1 | 5 | 4 |
Ferrari Dino | 19.7 | 6 | 145.0 | 175 | 3.62 | 2.770 | 15.50 | 0 | 1 | 5 | 6 |
Maserati Bora | 15.0 | 8 | 301.0 | 335 | 3.54 | 3.570 | 14.60 | 0 | 1 | 5 | 8 |
Volvo 142E | 21.4 | 4 | 121.0 | 109 | 4.11 | 2.780 | 18.60 | 1 | 1 | 4 | 2 |
But this is far from the typical use case. More typically, there is some structure to the data, in the sense that some columns contain values, while others contain keys that are used to group values according to some common characteristic. We will refer to these latter columns as facets, borrowing a term from the ggplot2
package. We will assume that the data are in a “tidy” format, by which we mean that all the values have been placed in a single column (if this is not the case, there are many functions that will allow you to “reshape” the data accordingly).
For the second example, continuing with the mtcars
data, we would like to tabulate the average mpg
(miles per gallon) by number of gears (rows) and cylinders (columns). Here is the code:
ttt(mpg ~ gear | cyl, data=mtcars, lab="Number of Cylinders", render=mean)
Number of Gears |
Number of Cylinders | ||
---|---|---|---|
4 | 6 | 8 | |
3 | 21.5 | 19.75 | 15.05 |
4 | 26.925 | 19.75 | NaN |
5 | 28.2 | 19.7 | 15.4 |
Let’s break this down. The first argument is a formula
with 3 parts: <values> ~ <row facets> | <column facets>
. The first part, to the left of the symbol ~
, is the name of the column that contains the values (recall that in the “tidy” format there is only one such column). The second part, between the symbols ~
and |
contains the row facets, one or more variables that define how the values should be split into rows. The third part, to the right of the symbol |
is the column facets, one or more variables that define how the values should be split into columns.
Following the formula
comes the data
argument, which is the data.frame
that contains the data that the formula
refers to. The next argument lab
is an optional label placed over all the columns. The last argument, render
, is a function
. This function is called for each grouping of data defined by unique combinations of the row and column facets, and produces the value that appears in the corresponding cell of the table. Hopefully this is fairly intuitive.
Now, the above table is nice, but still not quite what we want. Here are the issues that need to be addressed:
The label “gear” should be changed to “Number of Gears”.
One table cell contains the cryptic value “NaN” because there aren’t any cars with 8 cylinders and 4 gears in our dataset; we would like this cell to remain empty instead.
The number of decimal digits is different in each cell; we would like it to be the same throughout the table (1 decimal digit).
Let us now address these issues.
label(mtcars$gear) <- "Number of<br/>Gears"
<- function(x, ...) {
rndr if (length(x) == 0) return("")
round_pad(mean(x), 1)
}
ttt(mpg ~ gear | cyl, data=mtcars, lab="Number of Cylinders", render=rndr)
Number of Gears |
Number of Cylinders | ||
---|---|---|---|
4 | 6 | 8 | |
3 | 21.5 | 19.8 | 15.1 |
4 | 26.9 | 19.8 | |
5 | 28.2 | 19.7 | 15.4 |
The way we addressed the first issue was to add a label to the variable gear
using the label()
function (one of the useful utility functions from the table1
package). The two other issues were fixed by defining a function rndr()
to do the rendering.
The ttt()
function allows the order of the formula
data data
arguments to be switched, so that an alternative syntax using the magrittr
“pipe” operator may be used:
%>% ttt(mpg ~ gear | cyl, lab="Number of Cylinders", render=rndr) mtcars
Number of Gears |
Number of Cylinders | ||
---|---|---|---|
4 | 6 | 8 | |
3 | 21.5 | 19.8 | 15.1 |
4 | 26.9 | 19.8 | |
5 | 28.2 | 19.7 | 15.4 |
The facets allow you to “slide-&-dice” the data however you want. The column facet is optional; it can be omitted:
ttt(mpg ~ gear, data=mtcars, render=rndr)
Number of Gears |
mpg |
---|---|
3 | 16.1 |
4 | 24.5 |
5 | 21.4 |
The row facet is required by the formula syntax, but the “magic” value 1
may be used to indicate no splitting by rows:
ttt(mpg ~ 1 | cyl, data=mtcars, lab="Number of Cylinders", render=rndr)
Number of Cylinders | ||
---|---|---|
4 | 6 | 8 |
26.7 | 19.7 | 15.1 |
Both row and column facets may consist of more than one variable, joined together by the symbol +
. Here is an example with 2 row facets:
label(mtcars$cyl) <- "Number of<br/>Cylinders"
ttt(mpg ~ gear + cyl, data=mtcars, render=rndr)
Number of Gears |
Number of Cylinders |
mpg |
---|---|---|
3 | 4 | 21.5 |
6 | 19.8 | |
8 | 15.1 | |
4 | 4 | 26.9 |
6 | 19.8 | |
5 | 4 | 28.2 |
6 | 19.7 | |
8 | 15.4 |
And, similarly for 2 column facets:
ttt(mpg ~ 1 | gear + cyl, data=mtcars, lab="Number of Cylinders/Gears", render=rndr)
Number of Cylinders/Gears | |||||||
---|---|---|---|---|---|---|---|
3 | 4 | 5 | |||||
4 | 6 | 8 | 4 | 6 | 8 | 4 | 8 |
21.5 | 26.9 | 28.2 | 19.8 | 19.8 | 19.7 | 15.1 | 15.4 |
The order of the variables is obviously important, as they define a nesting structure. If we think of the |
that separates the row and column facets as the “values” (i.e. the central part of the table), then the order makes sense: variables closer to the center (|
) are grouped within variables that are farther away.
Just to demonstrate, here is a synthetic example of a large table where both row and column facets are nested 3 levels deep:
<- expand.grid(
bigtable R1=LETTERS[1:3],
R2=LETTERS[4:6],
R3=LETTERS[7:9],
C1=LETTERS[10:12],
C2=LETTERS[13:15],
C3=LETTERS[16:18])
$x <- 1:nrow(bigtable)
bigtablettt(x ~ R3 + R2 + R1 | C1 + C2 + C3, data=bigtable)
R3 | R2 | R1 | P | Q | R | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
M | N | O | M | N | O | M | N | O | |||||||||||||||||||||
J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | |||
G | D | A | 1 | 28 | 55 | 82 | 109 | 136 | 163 | 190 | 217 | 244 | 271 | 298 | 325 | 352 | 379 | 406 | 433 | 460 | 487 | 514 | 541 | 568 | 595 | 622 | 649 | 676 | 703 |
B | 2 | 29 | 56 | 83 | 110 | 137 | 164 | 191 | 218 | 245 | 272 | 299 | 326 | 353 | 380 | 407 | 434 | 461 | 488 | 515 | 542 | 569 | 596 | 623 | 650 | 677 | 704 | ||
C | 3 | 30 | 57 | 84 | 111 | 138 | 165 | 192 | 219 | 246 | 273 | 300 | 327 | 354 | 381 | 408 | 435 | 462 | 489 | 516 | 543 | 570 | 597 | 624 | 651 | 678 | 705 | ||
E | A | 4 | 31 | 58 | 85 | 112 | 139 | 166 | 193 | 220 | 247 | 274 | 301 | 328 | 355 | 382 | 409 | 436 | 463 | 490 | 517 | 544 | 571 | 598 | 625 | 652 | 679 | 706 | |
B | 5 | 32 | 59 | 86 | 113 | 140 | 167 | 194 | 221 | 248 | 275 | 302 | 329 | 356 | 383 | 410 | 437 | 464 | 491 | 518 | 545 | 572 | 599 | 626 | 653 | 680 | 707 | ||
C | 6 | 33 | 60 | 87 | 114 | 141 | 168 | 195 | 222 | 249 | 276 | 303 | 330 | 357 | 384 | 411 | 438 | 465 | 492 | 519 | 546 | 573 | 600 | 627 | 654 | 681 | 708 | ||
F | A | 7 | 34 | 61 | 88 | 115 | 142 | 169 | 196 | 223 | 250 | 277 | 304 | 331 | 358 | 385 | 412 | 439 | 466 | 493 | 520 | 547 | 574 | 601 | 628 | 655 | 682 | 709 | |
B | 8 | 35 | 62 | 89 | 116 | 143 | 170 | 197 | 224 | 251 | 278 | 305 | 332 | 359 | 386 | 413 | 440 | 467 | 494 | 521 | 548 | 575 | 602 | 629 | 656 | 683 | 710 | ||
C | 9 | 36 | 63 | 90 | 117 | 144 | 171 | 198 | 225 | 252 | 279 | 306 | 333 | 360 | 387 | 414 | 441 | 468 | 495 | 522 | 549 | 576 | 603 | 630 | 657 | 684 | 711 | ||
H | D | A | 10 | 37 | 64 | 91 | 118 | 145 | 172 | 199 | 226 | 253 | 280 | 307 | 334 | 361 | 388 | 415 | 442 | 469 | 496 | 523 | 550 | 577 | 604 | 631 | 658 | 685 | 712 |
B | 11 | 38 | 65 | 92 | 119 | 146 | 173 | 200 | 227 | 254 | 281 | 308 | 335 | 362 | 389 | 416 | 443 | 470 | 497 | 524 | 551 | 578 | 605 | 632 | 659 | 686 | 713 | ||
C | 12 | 39 | 66 | 93 | 120 | 147 | 174 | 201 | 228 | 255 | 282 | 309 | 336 | 363 | 390 | 417 | 444 | 471 | 498 | 525 | 552 | 579 | 606 | 633 | 660 | 687 | 714 | ||
E | A | 13 | 40 | 67 | 94 | 121 | 148 | 175 | 202 | 229 | 256 | 283 | 310 | 337 | 364 | 391 | 418 | 445 | 472 | 499 | 526 | 553 | 580 | 607 | 634 | 661 | 688 | 715 | |
B | 14 | 41 | 68 | 95 | 122 | 149 | 176 | 203 | 230 | 257 | 284 | 311 | 338 | 365 | 392 | 419 | 446 | 473 | 500 | 527 | 554 | 581 | 608 | 635 | 662 | 689 | 716 | ||
C | 15 | 42 | 69 | 96 | 123 | 150 | 177 | 204 | 231 | 258 | 285 | 312 | 339 | 366 | 393 | 420 | 447 | 474 | 501 | 528 | 555 | 582 | 609 | 636 | 663 | 690 | 717 | ||
F | A | 16 | 43 | 70 | 97 | 124 | 151 | 178 | 205 | 232 | 259 | 286 | 313 | 340 | 367 | 394 | 421 | 448 | 475 | 502 | 529 | 556 | 583 | 610 | 637 | 664 | 691 | 718 | |
B | 17 | 44 | 71 | 98 | 125 | 152 | 179 | 206 | 233 | 260 | 287 | 314 | 341 | 368 | 395 | 422 | 449 | 476 | 503 | 530 | 557 | 584 | 611 | 638 | 665 | 692 | 719 | ||
C | 18 | 45 | 72 | 99 | 126 | 153 | 180 | 207 | 234 | 261 | 288 | 315 | 342 | 369 | 396 | 423 | 450 | 477 | 504 | 531 | 558 | 585 | 612 | 639 | 666 | 693 | 720 | ||
I | D | A | 19 | 46 | 73 | 100 | 127 | 154 | 181 | 208 | 235 | 262 | 289 | 316 | 343 | 370 | 397 | 424 | 451 | 478 | 505 | 532 | 559 | 586 | 613 | 640 | 667 | 694 | 721 |
B | 20 | 47 | 74 | 101 | 128 | 155 | 182 | 209 | 236 | 263 | 290 | 317 | 344 | 371 | 398 | 425 | 452 | 479 | 506 | 533 | 560 | 587 | 614 | 641 | 668 | 695 | 722 | ||
C | 21 | 48 | 75 | 102 | 129 | 156 | 183 | 210 | 237 | 264 | 291 | 318 | 345 | 372 | 399 | 426 | 453 | 480 | 507 | 534 | 561 | 588 | 615 | 642 | 669 | 696 | 723 | ||
E | A | 22 | 49 | 76 | 103 | 130 | 157 | 184 | 211 | 238 | 265 | 292 | 319 | 346 | 373 | 400 | 427 | 454 | 481 | 508 | 535 | 562 | 589 | 616 | 643 | 670 | 697 | 724 | |
B | 23 | 50 | 77 | 104 | 131 | 158 | 185 | 212 | 239 | 266 | 293 | 320 | 347 | 374 | 401 | 428 | 455 | 482 | 509 | 536 | 563 | 590 | 617 | 644 | 671 | 698 | 725 | ||
C | 24 | 51 | 78 | 105 | 132 | 159 | 186 | 213 | 240 | 267 | 294 | 321 | 348 | 375 | 402 | 429 | 456 | 483 | 510 | 537 | 564 | 591 | 618 | 645 | 672 | 699 | 726 | ||
F | A | 25 | 52 | 79 | 106 | 133 | 160 | 187 | 214 | 241 | 268 | 295 | 322 | 349 | 376 | 403 | 430 | 457 | 484 | 511 | 538 | 565 | 592 | 619 | 646 | 673 | 700 | 727 | |
B | 26 | 53 | 80 | 107 | 134 | 161 | 188 | 215 | 242 | 269 | 296 | 323 | 350 | 377 | 404 | 431 | 458 | 485 | 512 | 539 | 566 | 593 | 620 | 647 | 674 | 701 | 728 | ||
C | 27 | 54 | 81 | 108 | 135 | 162 | 189 | 216 | 243 | 270 | 297 | 324 | 351 | 378 | 405 | 432 | 459 | 486 | 513 | 540 | 567 | 594 | 621 | 648 | 675 | 702 | 729 |
The render
function gives a lot of flexibility. For example, instead of the mean mpg
, we can list the cars according to their gear/cylinder combination:
ttt(rownames(mtcars) ~ gear | cyl, data=mtcars, lab="Number of Cylinders",
render=paste, collapse="<br/>")
Number of Gears |
Number of Cylinders | ||
---|---|---|---|
4 | 6 | 8 | |
3 | Toyota Corona | Hornet 4 Drive Valiant |
Hornet Sportabout Duster 360 Merc 450SE Merc 450SL Merc 450SLC Cadillac Fleetwood Lincoln Continental Chrysler Imperial Dodge Challenger AMC Javelin Camaro Z28 Pontiac Firebird |
4 | Datsun 710 Merc 240D Merc 230 Fiat 128 Honda Civic Toyota Corolla Fiat X1-9 Volvo 142E |
Mazda RX4 Mazda RX4 Wag Merc 280 Merc 280C |
|
5 | Porsche 914-2 Lotus Europa |
Ferrari Dino | Ford Pantera L Maserati Bora |
Note that additional arguments can be passed to the render
function through ...
(as in this case, collapse
).
Furthermore, a render
function can return more than one value in a named vector. In this case, the argument expand.along
also comes into play. It determines how the multiple values are laid out, either vertically (along rows), or the horizontally (along columns).
For example, here we define a function that computes both the mean and standard deviation (SD), each to 3 significant digits, and apply it to the response variable in the OrchardSprays
dataset (i.e., decrease
) according to treatment:
<- function(x) signif_pad(c(Mean=mean(x), SD=sd(x)), digits=3)
rndr.meansd
ttt(decrease ~ treatment, data=OrchardSprays, render=rndr.meansd)
treatment | Statistic | decrease |
---|---|---|
A | Mean | 4.63 |
SD | 3.20 | |
B | Mean | 7.63 |
SD | 3.29 | |
C | Mean | 25.3 |
SD | 24.4 | |
D | Mean | 35.0 |
SD | 13.4 | |
E | Mean | 63.1 |
SD | 26.9 | |
F | Mean | 69.0 |
SD | 29.2 | |
G | Mean | 68.5 |
SD | 20.1 | |
H | Mean | 90.3 |
SD | 24.2 |
The default is expand.along="rows"
, which produces the result above. As we can see, the table contains an additional column with the values “Mean” and “SD”, and each value is displayed in its own row. By default, the extra column is labeled “Statistic”, but to change the label to “Blah” we can specify a named vector as follows:
ttt(decrease ~ treatment, data=OrchardSprays, render=rndr.meansd, expand.along=c(Blah="rows"))
treatment | Blah | decrease |
---|---|---|
A | Mean | 4.63 |
SD | 3.20 | |
B | Mean | 7.63 |
SD | 3.29 | |
C | Mean | 25.3 |
SD | 24.4 | |
D | Mean | 35.0 |
SD | 13.4 | |
E | Mean | 63.1 |
SD | 26.9 | |
F | Mean | 69.0 |
SD | 29.2 | |
G | Mean | 68.5 |
SD | 20.1 | |
H | Mean | 90.3 |
SD | 24.2 |
The other option is expand.along="columns"
, which produces this result:
ttt(decrease ~ treatment, data=OrchardSprays, render=rndr.meansd, expand.along="columns")
treatment | decrease | |
---|---|---|
Mean | SD | |
A | 4.63 | 3.20 |
B | 7.63 | 3.29 |
C | 25.3 | 24.4 |
D | 35.0 | 13.4 |
E | 63.1 | 26.9 |
F | 69.0 | 29.2 |
G | 68.5 | 20.1 |
H | 90.3 | 24.2 |
Now “Mean” and “SD” each have their own column.
The appearance of the tables produced by ttt
can be changed in 2 ways: using themes, or custom styling. Themes are easier, but don’t give much flexibility. For fine-level control, custom styling must be used.
The ttt
package comes with 2 themes at this time: the default
theme that has been used throughout this vignette so far, and the booktabs
theme. (More themes may be added later.) Selecting the theme can be done using the ttt.theme
global option:
options(ttt.theme="booktabs") # Select the "booktabs" theme
If we select the booktabs
theme, our large table looks like this:
ttt(x ~ R3 + R2 + R1 | C1 + C2 + C3, data=bigtable)
R3 | R2 | R1 | P | Q | R | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
M | N | O | M | N | O | M | N | O | |||||||||||||||||||||
J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | |||
G | D | A | 1 | 28 | 55 | 82 | 109 | 136 | 163 | 190 | 217 | 244 | 271 | 298 | 325 | 352 | 379 | 406 | 433 | 460 | 487 | 514 | 541 | 568 | 595 | 622 | 649 | 676 | 703 |
B | 2 | 29 | 56 | 83 | 110 | 137 | 164 | 191 | 218 | 245 | 272 | 299 | 326 | 353 | 380 | 407 | 434 | 461 | 488 | 515 | 542 | 569 | 596 | 623 | 650 | 677 | 704 | ||
C | 3 | 30 | 57 | 84 | 111 | 138 | 165 | 192 | 219 | 246 | 273 | 300 | 327 | 354 | 381 | 408 | 435 | 462 | 489 | 516 | 543 | 570 | 597 | 624 | 651 | 678 | 705 | ||
E | A | 4 | 31 | 58 | 85 | 112 | 139 | 166 | 193 | 220 | 247 | 274 | 301 | 328 | 355 | 382 | 409 | 436 | 463 | 490 | 517 | 544 | 571 | 598 | 625 | 652 | 679 | 706 | |
B | 5 | 32 | 59 | 86 | 113 | 140 | 167 | 194 | 221 | 248 | 275 | 302 | 329 | 356 | 383 | 410 | 437 | 464 | 491 | 518 | 545 | 572 | 599 | 626 | 653 | 680 | 707 | ||
C | 6 | 33 | 60 | 87 | 114 | 141 | 168 | 195 | 222 | 249 | 276 | 303 | 330 | 357 | 384 | 411 | 438 | 465 | 492 | 519 | 546 | 573 | 600 | 627 | 654 | 681 | 708 | ||
F | A | 7 | 34 | 61 | 88 | 115 | 142 | 169 | 196 | 223 | 250 | 277 | 304 | 331 | 358 | 385 | 412 | 439 | 466 | 493 | 520 | 547 | 574 | 601 | 628 | 655 | 682 | 709 | |
B | 8 | 35 | 62 | 89 | 116 | 143 | 170 | 197 | 224 | 251 | 278 | 305 | 332 | 359 | 386 | 413 | 440 | 467 | 494 | 521 | 548 | 575 | 602 | 629 | 656 | 683 | 710 | ||
C | 9 | 36 | 63 | 90 | 117 | 144 | 171 | 198 | 225 | 252 | 279 | 306 | 333 | 360 | 387 | 414 | 441 | 468 | 495 | 522 | 549 | 576 | 603 | 630 | 657 | 684 | 711 | ||
H | D | A | 10 | 37 | 64 | 91 | 118 | 145 | 172 | 199 | 226 | 253 | 280 | 307 | 334 | 361 | 388 | 415 | 442 | 469 | 496 | 523 | 550 | 577 | 604 | 631 | 658 | 685 | 712 |
B | 11 | 38 | 65 | 92 | 119 | 146 | 173 | 200 | 227 | 254 | 281 | 308 | 335 | 362 | 389 | 416 | 443 | 470 | 497 | 524 | 551 | 578 | 605 | 632 | 659 | 686 | 713 | ||
C | 12 | 39 | 66 | 93 | 120 | 147 | 174 | 201 | 228 | 255 | 282 | 309 | 336 | 363 | 390 | 417 | 444 | 471 | 498 | 525 | 552 | 579 | 606 | 633 | 660 | 687 | 714 | ||
E | A | 13 | 40 | 67 | 94 | 121 | 148 | 175 | 202 | 229 | 256 | 283 | 310 | 337 | 364 | 391 | 418 | 445 | 472 | 499 | 526 | 553 | 580 | 607 | 634 | 661 | 688 | 715 | |
B | 14 | 41 | 68 | 95 | 122 | 149 | 176 | 203 | 230 | 257 | 284 | 311 | 338 | 365 | 392 | 419 | 446 | 473 | 500 | 527 | 554 | 581 | 608 | 635 | 662 | 689 | 716 | ||
C | 15 | 42 | 69 | 96 | 123 | 150 | 177 | 204 | 231 | 258 | 285 | 312 | 339 | 366 | 393 | 420 | 447 | 474 | 501 | 528 | 555 | 582 | 609 | 636 | 663 | 690 | 717 | ||
F | A | 16 | 43 | 70 | 97 | 124 | 151 | 178 | 205 | 232 | 259 | 286 | 313 | 340 | 367 | 394 | 421 | 448 | 475 | 502 | 529 | 556 | 583 | 610 | 637 | 664 | 691 | 718 | |
B | 17 | 44 | 71 | 98 | 125 | 152 | 179 | 206 | 233 | 260 | 287 | 314 | 341 | 368 | 395 | 422 | 449 | 476 | 503 | 530 | 557 | 584 | 611 | 638 | 665 | 692 | 719 | ||
C | 18 | 45 | 72 | 99 | 126 | 153 | 180 | 207 | 234 | 261 | 288 | 315 | 342 | 369 | 396 | 423 | 450 | 477 | 504 | 531 | 558 | 585 | 612 | 639 | 666 | 693 | 720 | ||
I | D | A | 19 | 46 | 73 | 100 | 127 | 154 | 181 | 208 | 235 | 262 | 289 | 316 | 343 | 370 | 397 | 424 | 451 | 478 | 505 | 532 | 559 | 586 | 613 | 640 | 667 | 694 | 721 |
B | 20 | 47 | 74 | 101 | 128 | 155 | 182 | 209 | 236 | 263 | 290 | 317 | 344 | 371 | 398 | 425 | 452 | 479 | 506 | 533 | 560 | 587 | 614 | 641 | 668 | 695 | 722 | ||
C | 21 | 48 | 75 | 102 | 129 | 156 | 183 | 210 | 237 | 264 | 291 | 318 | 345 | 372 | 399 | 426 | 453 | 480 | 507 | 534 | 561 | 588 | 615 | 642 | 669 | 696 | 723 | ||
E | A | 22 | 49 | 76 | 103 | 130 | 157 | 184 | 211 | 238 | 265 | 292 | 319 | 346 | 373 | 400 | 427 | 454 | 481 | 508 | 535 | 562 | 589 | 616 | 643 | 670 | 697 | 724 | |
B | 23 | 50 | 77 | 104 | 131 | 158 | 185 | 212 | 239 | 266 | 293 | 320 | 347 | 374 | 401 | 428 | 455 | 482 | 509 | 536 | 563 | 590 | 617 | 644 | 671 | 698 | 725 | ||
C | 24 | 51 | 78 | 105 | 132 | 159 | 186 | 213 | 240 | 267 | 294 | 321 | 348 | 375 | 402 | 429 | 456 | 483 | 510 | 537 | 564 | 591 | 618 | 645 | 672 | 699 | 726 | ||
F | A | 25 | 52 | 79 | 106 | 133 | 160 | 187 | 214 | 241 | 268 | 295 | 322 | 349 | 376 | 403 | 430 | 457 | 484 | 511 | 538 | 565 | 592 | 619 | 646 | 673 | 700 | 727 | |
B | 26 | 53 | 80 | 107 | 134 | 161 | 188 | 215 | 242 | 269 | 296 | 323 | 350 | 377 | 404 | 431 | 458 | 485 | 512 | 539 | 566 | 593 | 620 | 647 | 674 | 701 | 728 | ||
C | 27 | 54 | 81 | 108 | 135 | 162 | 189 | 216 | 243 | 270 | 297 | 324 | 351 | 378 | 405 | 432 | 459 | 486 | 513 | 540 | 567 | 594 | 621 | 648 | 675 | 702 | 729 |
Note that a theme can only apply to a whole document; it is not possible to selectively style different tables within the same document differently using different themes, as we appear to have done here (but it can be done with custom styling, which is how it was done).
options(ttt.theme="default") # Change back to the "default" theme
As mentioned in the introduction, changing the table’s appearance is accomplished using CSS. In order to make this possible, ttt
places “hooks” in the table in the form of class
attributes on various HTML elements.
The first thing to know is that the whole table is enclosed in a <div class="Rttt">
element. The allows specific formatting to be applied to tables output by ttt
without interfering with other tables in the same document.
The next thing is that all row labels have the class Rttt-rl
, and all column labels have the class Rttt-cl
. Furthermore, there are different classes for each level or nesting: Rttt-rl-lvl1
for the first (i.e. innermost) level or row labels, Rttt-rl-lvl2
for the second level, and so on, and similarly for the column labels with cl
instead of rl
.
Finally, it is possible to add a class
attribute or id
attribute to the whole table, so that it may be targetted with specific CSS selectors. We can also pass CSS code directly to the ttt()
function to be included with the table.
For example, can can specify that our table has the ID bigtable
, and then give it a particular (and particularly weird) style:
<- '
css #bigtable {
font-family: "Lucida Console", Monaco, monospace;
}
#bigtable td {
background-color: #eee;
}
#bigtable th {
color: blue;
background-color: lightblue;
}
#bigtable th, #bigtable td {
border: 2px dashed orange;
}
#bigtable .Rttt-rl {
background-color: #fff;
font-style: italic;
font-weight: bold;
}
#bigtable .Rttt-rl-lvl1 {
font-size: 12pt;
color: pink;
background-color: yellow;
}
#bigtable .Rttt-rl-lvl2 {
font-size: 14pt;
color: green;
}
#bigtable .Rttt-rl-lvl3 {
font-size: 18pt;
color: red;
}
'
ttt(x ~ R3 + R2 + R1 | C1 + C2 + C3, data=bigtable, id="bigtable", css=css)
R3 | R2 | R1 | P | Q | R | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
M | N | O | M | N | O | M | N | O | |||||||||||||||||||||
J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | J | K | L | |||
G | D | A | 1 | 28 | 55 | 82 | 109 | 136 | 163 | 190 | 217 | 244 | 271 | 298 | 325 | 352 | 379 | 406 | 433 | 460 | 487 | 514 | 541 | 568 | 595 | 622 | 649 | 676 | 703 |
B | 2 | 29 | 56 | 83 | 110 | 137 | 164 | 191 | 218 | 245 | 272 | 299 | 326 | 353 | 380 | 407 | 434 | 461 | 488 | 515 | 542 | 569 | 596 | 623 | 650 | 677 | 704 | ||
C | 3 | 30 | 57 | 84 | 111 | 138 | 165 | 192 | 219 | 246 | 273 | 300 | 327 | 354 | 381 | 408 | 435 | 462 | 489 | 516 | 543 | 570 | 597 | 624 | 651 | 678 | 705 | ||
E | A | 4 | 31 | 58 | 85 | 112 | 139 | 166 | 193 | 220 | 247 | 274 | 301 | 328 | 355 | 382 | 409 | 436 | 463 | 490 | 517 | 544 | 571 | 598 | 625 | 652 | 679 | 706 | |
B | 5 | 32 | 59 | 86 | 113 | 140 | 167 | 194 | 221 | 248 | 275 | 302 | 329 | 356 | 383 | 410 | 437 | 464 | 491 | 518 | 545 | 572 | 599 | 626 | 653 | 680 | 707 | ||
C | 6 | 33 | 60 | 87 | 114 | 141 | 168 | 195 | 222 | 249 | 276 | 303 | 330 | 357 | 384 | 411 | 438 | 465 | 492 | 519 | 546 | 573 | 600 | 627 | 654 | 681 | 708 | ||
F | A | 7 | 34 | 61 | 88 | 115 | 142 | 169 | 196 | 223 | 250 | 277 | 304 | 331 | 358 | 385 | 412 | 439 | 466 | 493 | 520 | 547 | 574 | 601 | 628 | 655 | 682 | 709 | |
B | 8 | 35 | 62 | 89 | 116 | 143 | 170 | 197 | 224 | 251 | 278 | 305 | 332 | 359 | 386 | 413 | 440 | 467 | 494 | 521 | 548 | 575 | 602 | 629 | 656 | 683 | 710 | ||
C | 9 | 36 | 63 | 90 | 117 | 144 | 171 | 198 | 225 | 252 | 279 | 306 | 333 | 360 | 387 | 414 | 441 | 468 | 495 | 522 | 549 | 576 | 603 | 630 | 657 | 684 | 711 | ||
H | D | A | 10 | 37 | 64 | 91 | 118 | 145 | 172 | 199 | 226 | 253 | 280 | 307 | 334 | 361 | 388 | 415 | 442 | 469 | 496 | 523 | 550 | 577 | 604 | 631 | 658 | 685 | 712 |
B | 11 | 38 | 65 | 92 | 119 | 146 | 173 | 200 | 227 | 254 | 281 | 308 | 335 | 362 | 389 | 416 | 443 | 470 | 497 | 524 | 551 | 578 | 605 | 632 | 659 | 686 | 713 | ||
C | 12 | 39 | 66 | 93 | 120 | 147 | 174 | 201 | 228 | 255 | 282 | 309 | 336 | 363 | 390 | 417 | 444 | 471 | 498 | 525 | 552 | 579 | 606 | 633 | 660 | 687 | 714 | ||
E | A | 13 | 40 | 67 | 94 | 121 | 148 | 175 | 202 | 229 | 256 | 283 | 310 | 337 | 364 | 391 | 418 | 445 | 472 | 499 | 526 | 553 | 580 | 607 | 634 | 661 | 688 | 715 | |
B | 14 | 41 | 68 | 95 | 122 | 149 | 176 | 203 | 230 | 257 | 284 | 311 | 338 | 365 | 392 | 419 | 446 | 473 | 500 | 527 | 554 | 581 | 608 | 635 | 662 | 689 | 716 | ||
C | 15 | 42 | 69 | 96 | 123 | 150 | 177 | 204 | 231 | 258 | 285 | 312 | 339 | 366 | 393 | 420 | 447 | 474 | 501 | 528 | 555 | 582 | 609 | 636 | 663 | 690 | 717 | ||
F | A | 16 | 43 | 70 | 97 | 124 | 151 | 178 | 205 | 232 | 259 | 286 | 313 | 340 | 367 | 394 | 421 | 448 | 475 | 502 | 529 | 556 | 583 | 610 | 637 | 664 | 691 | 718 | |
B | 17 | 44 | 71 | 98 | 125 | 152 | 179 | 206 | 233 | 260 | 287 | 314 | 341 | 368 | 395 | 422 | 449 | 476 | 503 | 530 | 557 | 584 | 611 | 638 | 665 | 692 | 719 | ||
C | 18 | 45 | 72 | 99 | 126 | 153 | 180 | 207 | 234 | 261 | 288 | 315 | 342 | 369 | 396 | 423 | 450 | 477 | 504 | 531 | 558 | 585 | 612 | 639 | 666 | 693 | 720 | ||
I | D | A | 19 | 46 | 73 | 100 | 127 | 154 | 181 | 208 | 235 | 262 | 289 | 316 | 343 | 370 | 397 | 424 | 451 | 478 | 505 | 532 | 559 | 586 | 613 | 640 | 667 | 694 | 721 |
B | 20 | 47 | 74 | 101 | 128 | 155 | 182 | 209 | 236 | 263 | 290 | 317 | 344 | 371 | 398 | 425 | 452 | 479 | 506 | 533 | 560 | 587 | 614 | 641 | 668 | 695 | 722 | ||
C | 21 | 48 | 75 | 102 | 129 | 156 | 183 | 210 | 237 | 264 | 291 | 318 | 345 | 372 | 399 | 426 | 453 | 480 | 507 | 534 | 561 | 588 | 615 | 642 | 669 | 696 | 723 | ||
E | A | 22 | 49 | 76 | 103 | 130 | 157 | 184 | 211 | 238 | 265 | 292 | 319 | 346 | 373 | 400 | 427 | 454 | 481 | 508 | 535 | 562 | 589 | 616 | 643 | 670 | 697 | 724 | |
B | 23 | 50 | 77 | 104 | 131 | 158 | 185 | 212 | 239 | 266 | 293 | 320 | 347 | 374 | 401 | 428 | 455 | 482 | 509 | 536 | 563 | 590 | 617 | 644 | 671 | 698 | 725 | ||
C | 24 | 51 | 78 | 105 | 132 | 159 | 186 | 213 | 240 | 267 | 294 | 321 | 348 | 375 | 402 | 429 | 456 | 483 | 510 | 537 | 564 | 591 | 618 | 645 | 672 | 699 | 726 | ||
F | A | 25 | 52 | 79 | 106 | 133 | 160 | 187 | 214 | 241 | 268 | 295 | 322 | 349 | 376 | 403 | 430 | 457 | 484 | 511 | 538 | 565 | 592 | 619 | 646 | 673 | 700 | 727 | |
B | 26 | 53 | 80 | 107 | 134 | 161 | 188 | 215 | 242 | 269 | 296 | 323 | 350 | 377 | 404 | 431 | 458 | 485 | 512 | 539 | 566 | 593 | 620 | 647 | 674 | 701 | 728 | ||
C | 27 | 54 | 81 | 108 | 135 | 162 | 189 | 216 | 243 | 270 | 297 | 324 | 351 | 378 | 405 | 432 | 459 | 486 | 513 | 540 | 567 | 594 | 621 | 648 | 675 | 702 | 729 |
A render
function can actually add a html.class
attribute to its return value. The value of this attribute will be assigned to the resulting HTML element’s class
attribute, allowing you to target that element with specific formatting.
For example, suppose we have a data.frame
that contains some numeric values, and we want to put them in a table:
<- expand.grid(row=LETTERS[1:5], column=LETTERS[1:5])
dat $value <- rnorm(nrow(dat))
dat
ttt(value ~ row | column, data=dat, render=round_pad, digits=2)
row | A | B | C | D | E |
---|---|---|---|---|---|
A | -0.56 | 1.72 | 1.22 | 1.79 | -1.07 |
B | -0.23 | 0.46 | 0.36 | 0.50 | -0.22 |
C | 1.56 | -1.27 | 0.40 | -1.97 | -1.03 |
D | 0.07 | -0.69 | 0.11 | 0.70 | -0.73 |
E | 0.13 | -0.45 | -0.56 | -0.47 | -0.63 |
Furthermore, suppose we want the cells that contain negative values to be red, and those that contain positive values to be green. (Note: this can actually be easily accomplished using JavaScript, but that’s not the point of this example). Let’s define a render
function for this:
<- function(x, ...) {
rndr <- round_pad(x, 2)
y attr(y, "html.class") <- ifelse(x < 0, "neg", "pos")
y }
(since there are no zeros in this example, the code here cheats and treats zero as positive; if you don’t like this, think of it as non-negative).
The render
function sets the desired class on the elements. Now, we can add some CSS code to obtain the desired colors:
.neg {
color: #990000;
background-color: #ff000030;
}.pos {
color: #007700;
background-color: #00ff0030;
}
Finally, we generate the table:
ttt(value ~ row | column, data=dat, render=rndr)
row | A | B | C | D | E |
---|---|---|---|---|---|
A | -0.56 | 1.72 | 1.22 | 1.79 | -1.07 |
B | -0.23 | 0.46 | 0.36 | 0.50 | -0.22 |
C | 1.56 | -1.27 | 0.40 | -1.97 | -1.03 |
D | 0.07 | -0.69 | 0.11 | 0.70 | -0.73 |
E | 0.13 | -0.45 | -0.56 | -0.47 | -0.63 |
A non-exhaustive list includes: flextable, kableExtra, huxtable, htmlTable, tableHTML, ztable, formattable, pixiedust, basictabler, mmtable2, gt, DT, tables, xtable.↩︎