Skip to contents

codehover codehover hex sticker

Pipes are an excellent way to code. They make it easy to follow the code chain of transformations and their results.

The codehover aims to make it easy to create a HTML table with a simple hover effect (plain CSS and JavaScript, bundled with the package) that shows images beside or below the said table. Rows also react to tap and to the keyboard, so the result works on a phone and for keyboard users too.

This way one could set up pseudo-lines of code (show as text) in the table and a series of images showing the intermediate results of the code with a hovering interaction.

The package use is educational, a fast way of showing code actions.

I have to say that I begin with the ideia of the package without knowing about a simillar package based on Xaringan: flipbookr. In fact, I guess it was in my subconscious all along, for I follow Gina Reynolds work on Twitter for a long time. She made a wonderful job there, way more sophisticated than I even hope to implement here. codehover is aimed at a HTML page (through RMarkdown), with hover effect . By virtue of those simple differences I will keep the package online (until she implements the same functionality on flipbookr - granted that she already shows how to embed xaringan presentation into HTML(here)).

Installation

You can install the experimental version of codehover from github:

install.packages("devtools")
devtools::install_github("arthurwelle/codehover")

Since version 1.0.0 no set-up is needed: the object returned by ch_out() (and by ch_hover()) carries its own CSS and JavaScript as an htmltools dependency, so it renders in any R Markdown or Quarto document – and in the RStudio viewer – and the knitted HTML is self-contained.

Two RMarkdown Templates are installed with the package as a starting point (File -> New File -> R Markdown -> From Template): codehover for the automatic mode and codehover-manual for the hand-built tables shown below. They are convenience only – a plain .Rmd works just as well. As with any new template, it may take an RStudio restart to show up in the menu.

Workflow example

Load some libraries:

Let´s try to replicate the following graph (code and intermediate steps).

ggplot() +
  geom_point(data = cars,
             aes(x = speed, 
                 y = dist,
                 color = 'red')) +
  scale_y_continuous(limits = c(0,100)) +
  labs(title = 'A ggplot fot the rest of us',
       subtitle = 'Testing a way of explicit showing the R workflow') +
  theme_bw()
  

Save every step as an image.

# create IMG folted
dir.create("./IMG/")
#> Warning in dir.create("./IMG/"): '.\IMG' already exists


g <- ggplot2::ggplot() +
  geom_point(data = cars,
             aes(x = speed, 
                 y = dist))

ggplot2::ggsave("./IMG/1b.png", width = 4, height = 3) 

g <-  g + aes(color = "red")
ggplot2::ggsave("./IMG/2b.png", width = 4, height = 3) 

g <-  g + scale_y_continuous(limits = c(0,100))
ggplot2::ggsave("./IMG/3b.png", width = 4, height = 3) 
#> Warning: Removed 1 row containing missing values or values outside the scale range
#> (`geom_point()`).

g <-  g + labs(title = "A ggplot fot the rest of us")
ggplot2::ggsave("./IMG/4b.png", width = 4, height = 3) 
#> Warning: Removed 1 row containing missing values or values outside the scale range
#> (`geom_point()`).

g <-  g + labs(subtitle = "Testing a way of explicit showing the R workflow")
ggplot2::ggsave("./IMG/5b.png", width = 4, height = 3) 
#> Warning: Removed 1 row containing missing values or values outside the scale range
#> (`geom_point()`).

g <-  g + theme_bw()
ggplot2::ggsave("./IMG/6b.png", width = 4, height = 3) 
#> Warning: Removed 1 row containing missing values or values outside the scale range
#> (`geom_point()`).

codehover has three functions that should be used together in a pipe-like style: ch_int(), ch_row(), and ch_out().

ch_int() initiates the HTML table, one can choose if the hover effect will be incremental or for a single row of the table. You can pass a custom CSS class for the whole table here as well.

After that you can use multiple ch_row calls to make as many rows as you like in the HTML table. For every line you should pass a text (the pseudo code you want to show) and an image. By default codehover uses knitr to encode the image file as a base64 string, with that your final HTML is self-contain in just one file (the images would be inside it). With multiple images this can increase file size considerable, so it´s optional to pass an url (with url = TRUE) if you dont want the behavior of embeding images. This way you can host your images anywhere.

Note that the code (the pseudo-code as text) use some <tabs> and &nbsp; for indentation of the final text displayed. See more of that bellow.

Finally you show close the table with the function ch_out. Here you can indicate another image to be show before any hover interaction, as well as to pass another CSS class to the image holder to control its size and placement in the page.

With these three functions you create an object that is already renderable – its CSS and JavaScript come attached – so you just print it. (Up to version 0.0.1 the result was a plain string that had to be passed through htmltools::HTML(); that step is gone.) ch_out() also takes alt = for the image’s alternative text, caption = and aspect =.


result <- ch_int(type = "incremental") %>% 
          ch_row(text = 
                     "ggplot() + 
                      <br> <tab1> geom_point(data = cars, </tab1>
                      <br> <tab2> aes(x = speed, </tab2>
                      <br> <tab2> &nbsp; &nbsp; y = dist, </tab2>",
                   img ="./IMG/1b.png") %>% 
          ch_row(text = "<tab2> color = 'red')) + </tab2>",
                   img ="./IMG/2b.png") %>%   
          ch_row(text = "<tab1> scale_y_continuous(limits = c(0,100)) + </tab1>",
                   img ="./IMG/3b.png") %>% 
          ch_row(text = "<tab1> labs(title = 'A ggplot fot the rest of us', </tab1>",
                   img ="./IMG/4b.png") %>%   
          ch_row(text = "<tab2> subtitle = 'Testing a way of explicit showing the R workflow') + </tab2>",
                   img ="./IMG/5b.png") %>% 
          ch_row(text = "<tab1>  theme_bw()</tab1> ",
                   img ="./IMG/6b.png") %>%
          ch_out(img = "./IMG/1b.png") 
  

Since version 1.0.0 the object returned by ch_out() is already renderable (its CSS and JavaScript are attached automatically) – just print it.

result
ggplot() +
geom_point(data = cars,
aes(x = speed,
    y = dist,
color = 'red')) +
scale_y_continuous(limits = c(0,100)) +
labs(title = 'A ggplot fot the rest of us',
subtitle = 'Testing a way of explicit showing the R workflow') +
theme_bw()
codehover plot

Writing style (bits and quirks)

Quotes

From Quotes we see than “single quotes are normally only used to delimit character constants containing double quotes”. This is the exactlly use here, we have to use single quotes in the R code that we want to pass as text for the HTML table.

For exemple, if we want to pass a ggplot2 title we could interchangebly use labs(title = “A Title”) or labs(title = ‘A Title’), but if we want to pass this as text to codehover we should use single quotes.

ch_row(text = “labs(title = ‘A Title’)”)

Indentation

You can use the <br> tag to initiate new lines.

And to proper indent your text, as you would like to do to a code, you can use the HTML non-breaking spaces.

&nbsp; a single non-breaking space;

&ensp; = it is equal to two &nbsp;

&emsp; = it is equal to four &nbsp;

Alternatively the codehover CSS has the classes ch-tab1 to ch-tab16 to denote 1 to 16 indentation levels (each level is --codehover-tab, 2em by default). To use them you enclose the text in a span. For example:

ch_row(text = “<span class=‘ch-tab7’>theme_bw()</span>”)

The bare <tab1> … <tab16> tags used up to version 0.0.1 are still styled, so older documents keep working.

Under the hood

There is no jQuery and no script to copy any more. Each row is written as <tr data-link="...">, and the vanilla JavaScript shipped inside the package (inst/assets/codehover.js, attached automatically) listens for hover, tap, focus and arrow keys, then swaps the src of the image holder. Everything is scoped under the .codehover class, so it cannot collide with the rest of your page.

You can restyle it with the CSS custom properties exposed by the package:

.codehover {
  --codehover-highlight: #F1D95A;   /* row highlight             */
  --codehover-font: monospace;      /* code font                 */
  --codehover-font-size: 0.9em;
  --codehover-tab: 2em;             /* width of one indent level */
}

Reference

The codehover hex sticker was made using the R package hexSticker.