Part I — make a basic slide deck

Arindam Basu

… in which I discuss a workflow where you can start writing your contents on a jupyter notebook, create a reveal.js slide deck, and host it on github for presentations. This is for a very simple presentation that you can fully control yourself

A first simple slide deck

Part I: Basic slide deck
Part II: Basic slide deck using remarkjs
Part III: Advanced techniques

Step by step

Set up a github repo and add a submodule

Step 1. Start with creating a github repository for hosting your slide deck. To do this, visit https://www.github.com and start a repository and you will also need to install git. I have used a hosted instance on Vultr and it came with a preinstalled git. If you use Windows, Mac, or Linux, you may want to install git or check in your terminal that you have git installed by issuing something like:

git --version
Click on the + sign to add a repository

Step 2. Add a repository. For example, I have created a repository named myJupyterSlides, see the screenshot below:

Created an empty repository to host jupyter notebook based slides

Step 3. (While still using the web interface) It’s a good idea to create an index.md file in the master branch and write that you will keep your slides here in this repository. You can also use a “README.md” for that purpose. Let’s create a file now. Below you can see the file was created:

Step 4. (While still using the web interface), using the web interface, create a new ‘branch’ named gh-pages (see the screenshot below as to how to create the gh-pages branch)

Create gh-pages branch

Once you create the gh-pages branch, github automatically creates a website for you. If you click “Settings” on your github repository (“github repo”), it will show that your site is published. For example, if here is the screenshot that shows where my site is published from my github repo:

Your site is published!

If I were to click on the link, it would show a simple webpage.

You have now set up a site where your slides will be published. In the next steps, we will make available to our computer (it could be local computer machine or an instance or a virtual machine) a folder using this git repo where we will build the files for our slide deck. Here are the steps:

Step 5. Now on your terminal, ‘clone’ the git repo. First, make a directory (or folder). For example, I made a directory named “jupyterslides”. I changed from my current directory to this directory (1). Then initialise a git folder (2). After this add your github repo to this folder as a subfolder (3). You will see that a folder is added whose name is same as your github repo name.

~$ cd jupyterslides (1)
~$ git init (2)
~$ git submodule add <your github https repo address> (3)

Start a Jupyter Notebook/Jupyter Lab and add content

Step 6. Now that you have set up a github repo and you have added that repo as a submodule to your computer or instance, let’s start building the contents of the slide deck. By the time you will complete this tutorial, you will build a simple presentation from the Jupyter notebook that will be displayed over the web. Later, you will see you can build interactivity to this presentation and more advanced features. Unlike Keynote, Powerpoint, or OpenOffice/LibreOffice Impress, you will not use any point and click based system to build such content; you will, instead use plain text tools to build your presentation. Therefore,

  • the first step is develop the content in Jupyter notebook.
  • The second step is convert this notebook programmatically to a markdown document
  • The third step is to use ‘pandoc’ (a universal document converter, a.k.a. Swiss Army Knife of document conversion) to convert the document to a set of slide decks
  • The fourth step is to ‘push’ the contents to the github repo for display over the Internet

Step 7: create content in Jupyter notebook. — For this tutorial, let’s create a five slide-deck presentation (this is for illustration) containing:

  • A title slide (we will add the title slide later)
  • A slide that contains bullet points
  • A slide that contains an image
  • A slide that contains a link
  • A slide that contains a table

I will later show you that you can use these four elements (bullet points, image, link, and table) are basic constituents to create different types of presentations. I will also show you how you can add interactivity to these elements. You can create images, and tables in Jupyter notebooks using markdown or codes written in R or Python or Julia (and indeed in many other languages). So this is a good time to launch into four related issues: how to author contents in markdown, what is reveal.js and why we use it (and there are others as well), and guidance on slide making.

How to author contents in markdown

Markdown is a content authoring system designed to write structured documents on the web. The following elements of a document make up markdown syntax:

The following is an example of a table written in Markdown and will be rendered as a table in github flavoured markdown| Element of text    | Equivalent Markdown syntax        |
|--------------------|-----------------------------------|
| Heading levels | Usually with ## |
| First level header | # Example of a first level header |
| Second level header| ## Second level header |
| Paragraphs | Text separated by two line spaces |
| Unnumbered list | * this is an element |
| Numbered list | 1. This is the first element |
| Tables | This is a markdown table |
| Formula | $formula$ |
| Images | ![image alt](image URL) |
| Hyperlinks | [Link text](URL to be linked) |
| References | [@bibtex_entry_ID] |
| Codes | backticks (`code goes here`) |
| Italic | *text to be italicised* |
| Bold | **text to be in bold font** |
| Underline | _text to be underlined_ |
| Blockquote | > Text to be blockquoted |

In the code block above, I have provided you with a list of commonly used markdown conventions. For a longer list and cheatsheet of github flavoured markdown, see the following link

In a Jupyter notebook, you can author documents in markdown. Jupyter notebooks use github flavoured markdown and this is what we will use as well. Besides, if you want to use references and citations and if you would like to transfer the documents to other formats that include citations and list of references in it, I recommend you use pandoc to transfer the document from a markdown format to the desired format. You can learn more about pandoc and how to transfer documents using pandoc here. The following youtube video provides you more information about pandoc:

How to use pandoc, a video you can use to learn more about pandoc

We will cover how to use pandoc to create slide decks in a separate section of this document. For now, we will use markdown to write our slides. We will use next reveal.js to style our slides.

What is reveal.js and why you will use it

Think of reveal.js as a tool that you will use to render the slides you have created. Revealjs consists of three elements:

  • A CSS (cascading style sheet that renders the appearance of the document)
  • A javascript engine (that renders the slide decks), and
  • An HTML5 document that you will create that will be shown as slides

Think of each ‘slide’ that you will show to be included within the <section> and <section> elements. So, it goes like as follows:

<html>
CSS statements
<section>
Your slide data will go here ...
</section>
<javacript file>
</html>

This is the basic structure. There are other tools and frameworks as well, please check them out. In this tutorial we will cover revealjs, and in subsequent tutorials, I will cover several of them. Some common and popular frameworks are:

I will cover these in subsequent posts, so this is the one where we are going to focus on revealjs.

What do you need to do to get revealjs up and running

Step 8. Obtain a copy of reveal.js from their github repo and use wget command in your terminal in Jupyter notebook like so:

~$ cd myjupyterslides (1)
~$ wget https://github.com/hakimel/reveal.js/archive/master.zip (2)
~$ unzip master.zip (3)
# this will create a folder named 'reveal.js-master'
# rename the folder to 'revealjs' with:
~$ mv reveal.js-master revealjs (4)

Explanation of the above code block:

  1. cd myjupyterslides (1) . — You will change directory to get into myjupyterslides where myjupyterslides is the github repository you created earlier and therefore when you added the git submodule, this was added as a folder to your present directory
  2. wget <URL> (2) wget is a utility which helps you to download web contents, in this case the master branch of the revealjs repository
  3. unzip master.zip (3) is self-explanatory, it will unzip the file and add a folder ‘reveal.js-master’ to the current directory
  4. mv reveal.js-master revealjs is a way to ‘rename’ a folder so now your folder is renamed revaljs.

At the end of this step, you are set to use revealjs to create a local copy of your slide decks. But before we start putting together contents, let’s learn a few points about good practices on creating slide decks and data visualisation. This is a HIGHLY condensed version of what I will discuss in subsequent articles in this series, but will serve our purpose for this tutorial.

Notes about creating slide decks and data visualisations

A few things about creating slide decks and data visualisations is in order.

First, keep in mind the five laws of data ink from Edward Tufte,

  1. Above all else, show the data
  2. Maximise the data ink ratio (more data per ink flow)
  3. Erase non-data ink
  4. Erase redundant data ink
  5. Revise and edit

For a more detailed explanation of the above concepts, please review the following source:

Some other tips include:

  • Craft a story with a beginning, a middle and an end
  • Use storyboards to develop your ideas (see work by Garr Reynolds and Cliff Atkinson)

How to use Jupyter notebooks to draw diagrams, plots, and tables from data

Let’s create a simple five slide presentation in jupyter notebook. The syntax is simple and we will create something like as follows (you can see how it looks as a jupyter notebook like by visiting this link )

## This is the first slide (1)
- We will create simple set of slides
- Let's analyse some data
- Create a figure from the data
- Create a table
library(tidyverse) (2)mtcars1 <- mtcars %>% (3)
head()
mtcars1 # produces the first five rows in the form of a table
mtcars %>% (4)
ggplot(aes(x = disp, y = mpg)) +
geom_point() +
geom_smooth(method = "loess", colour = "blue", se = FALSE) +
geom_smooth(method = "lm", colour = "red", se = FALSE) +
labs(x = "Engine size",
y = "Miles per gallon",
title = "Relationship between engine size and milage for cars") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank()) +
ggsave("test5.png")

Explanation of the above code:

(1) This is the first slide written in a markdown block. You can move around the blocks so you can in essence have a storyboard built in Jupyter
(2) This is written in a code window and calls the tidyverse library in R
(3) mtcars1 is a data subset created from mtcars, a large data set on cars; we will use this to demonstrate creation of tables programmatically
(4) We use this code to generate a plot programmatically

Step 9. After we generate these figures and tables using jupyter notebook and using R within Jupyter notebook, we then export this jupyter notebook to a markdown document. We could use jupyter notebook itself to create a reveal.js set of slide decks, but exporting first to markdown provides you more control on some aspects of the elements o slide creation. You use the following code to convert a jupyter notebook to a markdown document:

~$ jupyter nbconvert -t markdown mynotebook.ipynb (1)
# generates mynotebook.md (2)

Explanation:

(1) mynotebook.ipynb is the name of the jupyter notebook I want to convert
(2) This will generate mynotebook.md markdown document

Now our markdown document looks like as follows:

## This is the first slide
- We will create simple set of slides
- Let's analyse some data
- Create a figure from the data
- Create a table
```R
library(tidyverse)
```
── [1mAttaching packages[22m ─────────────────────────────────────── tidyverse 1.2.1 ──
[32m✔[39m [34mggplot2[39m 3.1.1 [32m✔[39m [34mpurrr [39m 0.3.2
[32m✔[39m [34mtibble [39m 2.1.3 [32m✔[39m [34mdplyr [39m 0.8.1
[32m✔[39m [34mtidyr [39m 0.8.3 [32m✔[39m [34mstringr[39m 1.4.0
[32m✔[39m [34mreadr [39m 1.3.1 [32m✔[39m [34mforcats[39m 0.4.0
── [1mConflicts[22m ────────────────────────────────────────── tidyverse_conflicts() ──
[31m✖[39m [34mdplyr[39m::[32mfilter()[39m masks [34mstats[39m::filter()
[31m✖[39m [34mdplyr[39m::[32mlag()[39m masks [34mstats[39m::lag()
```R
mtcars1 <- mtcars %>%
head()
mtcars1 # produces the first five rows in the form of a table
```
<table>
<caption>A data.frame: 6 × 11</caption>
<thead>
<tr><th></th><th scope=col>mpg</th><th scope=col>cyl</th><th scope=col>disp</th><th scope=col>hp</th><th scope=col>drat</th><th scope=col>wt</th><th scope=col>qsec</th><th scope=col>vs</th><th scope=col>am</th><th scope=col>gear</th><th scope=col>carb</th></tr>
<tr><th></th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th></tr>
</thead>
<tbody>
<tr><th scope=row>Mazda RX4</th><td>21.0</td><td>6</td><td>160</td><td>110</td><td>3.90</td><td>2.620</td><td>16.46</td><td>0</td><td>1</td><td>4</td><td>4</td></tr>
<tr><th scope=row>Mazda RX4 Wag</th><td>21.0</td><td>6</td><td>160</td><td>110</td><td>3.90</td><td>2.875</td><td>17.02</td><td>0</td><td>1</td><td>4</td><td>4</td></tr>
<tr><th scope=row>Datsun 710</th><td>22.8</td><td>4</td><td>108</td><td> 93</td><td>3.85</td><td>2.320</td><td>18.61</td><td>1</td><td>1</td><td>4</td><td>1</td></tr>
<tr><th scope=row>Hornet 4 Drive</th><td>21.4</td><td>6</td><td>258</td><td>110</td><td>3.08</td><td>3.215</td><td>19.44</td><td>1</td><td>0</td><td>3</td><td>1</td></tr>
<tr><th scope=row>Hornet Sportabout</th><td>18.7</td><td>8</td><td>360</td><td>175</td><td>3.15</td><td>3.440</td><td>17.02</td><td>0</td><td>0</td><td>3</td><td>2</td></tr>
<tr><th scope=row>Valiant</th><td>18.1</td><td>6</td><td>225</td><td>105</td><td>2.76</td><td>3.460</td><td>20.22</td><td>1</td><td>0</td><td>3</td><td>1</td></tr>
</tbody>
</table>
```R
mtcars %>%
ggplot(aes(x = disp, y = mpg)) +
geom_point() +
geom_smooth(method = "loess", colour = "blue", se = FALSE) +
geom_smooth(method = "lm", colour = "red", se = FALSE) +
labs(x = "Engine size",
y = "Miles per gallon",
title = "Relationship between engine size and milage for cars") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank()) +
ggsave("test5.png")
```
Saving 6.67 x 6.67 in image![png](test5_files/test5_3_1.png)```R```

Step 10. We will work on this document and make it ‘slide worthy’ using the tips and principles from the following two documents:

It's possible to write your slides using Markdown. To enable Markdown, add the data-markdown attribute to your <section>elements and wrap the contents in a <textarea data-template> like the example below. You'll also need to add the plugin/markdown/marked.js and plugin/markdown/markdown.js scripts (in that order) to your HTML file.<section data-markdown>
<textarea data-template>
## Page title

A paragraph with some text and a https://towardsdatascience.com/how-to-create-data-driven-presentations-with-jupyter-notebooks-reveal-js-e7a42a1fb7d7?source=rss----7f60cf5620c9---4(http://hakim.se).
</textarea>
</section>

We will see that Pandoc will do that for us. But the documentation goes on,

Special syntax (through HTML comments) is available for adding attributes to Markdown elements. This is useful for fragments, amongst other things.<section data-markdown>
<script type="text/template">
- Item 1 <!-- .element: class="fragment" data-fragment-index="2" -->
- Item 2 <!-- .element: class="fragment" data-fragment-index="1" -->
</script>
</section>

This part needs a bit of explanation. Here, revealjs developers are directing your attention to the ‘markdown elements’ you decide to include within the slide deck, and gives an example of a list element. There are other elements as well (note the list above). You can control each of those elements with these sort of class definitions. But then there are issues around behaviours of entire slides in the deck. This is where they talk about controlling elements like changing background colours, adding a background image as opposed to an image with a title, and so on. Here is the relevant documentation:

Slide AttributesSpecial syntax (through HTML comments) is available for adding attributes to the slide <section> elements generated by your Markdown.<section data-markdown>
<script type="text/template">
<!-- .slide: data-background="#ff0000" -->
Markdown content
</script>
</section>

We will make use of this information later in the series to generate pretty slides with interactivity. For now, we will let Pandoc generate what it can. Here is more information from pandoc documentation:

From pandoc documentation, note:

By default, the slide level is the highest heading level in the hierarchy that is followed immediately by content, and not another heading, somewhere in the document. In the example above, level-1 headings are always followed by level-2 headings, which are followed by content, so the slide level is 2. This default can be overridden using the --slide-level option.The document is carved up into slides according to the following rules:
* A horizontal rule always starts a new slide.
* A heading at the slide level always starts a new slide.
* Headings below the slide level in the hierarchy create headings within a slide.
* Headings above the slide level in the hierarchy create “title slides,” which just contain the section title and help to break the slide show into sections. Non-slide content under these headings will be included on the title slide (for HTML slide shows) or in a subsequent slide with the same title (for beamer).
* Headings above the slide level in the hierarchy create “title slides,” which just contain the section title and help to break the slide show into sections. Non-slide content under these headings will be included on the title slide (for HTML slide shows) or in a subsequent slide with the same title (for beamer).
* A title page is constructed automatically from the document’s title block, if present. (In the case of beamer, this can be disabled by commenting out some lines in the default template.)

Following these rules, it is possible to construct a series of slides that can be modified to suit most of our needs. In this tutorial we will create a simple set of slide deck so we will not into depth of the different options. In subsequent articles, we will explore many ways to ‘tweak’ the appearance of the slide deck and add interactivity to the slides.

Here, in brief, at the least:

  • We willl add a title page
  • We will insert some slide dividers
  • We will remove the code blocks

After these changes were put into place, the resulting markdown document looked like this:

--- (1)
title: A first simple slide deck
author: Me Myself
date: 9th August, 2019
---
## This is the first slide (2)
- We will create simple set of slides
- Let's analyse some data
- Create a figure from the data
- Create a table
---------- (3)
<table>
<caption>A data.frame: 6 × 11</caption>
<thead>
<tr><th></th><th scope=col>mpg</th><th scope=col>cyl</th><th scope=col>disp</th><th scope=col>hp</th><th scope=col>drat</th><th scope=col>wt</th><th scope=col>qsec</th><th scope=col>vs</th><th scope=col>am</th><th scope=col>gear</th><th scope=col>carb</th></tr>
<tr><th></th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th><th scope=col>&lt;dbl&gt;</th></tr>
</thead>
<tbody>
<tr><th scope=row>Mazda RX4</th><td>21.0</td><td>6</td><td>160</td><td>110</td><td>3.90</td><td>2.620</td><td>16.46</td><td>0</td><td>1</td><td>4</td><td>4</td></tr>
<tr><th scope=row>Mazda RX4 Wag</th><td>21.0</td><td>6</td><td>160</td><td>110</td><td>3.90</td><td>2.875</td><td>17.02</td><td>0</td><td>1</td><td>4</td><td>4</td></tr>
<tr><th scope=row>Datsun 710</th><td>22.8</td><td>4</td><td>108</td><td> 93</td><td>3.85</td><td>2.320</td><td>18.61</td><td>1</td><td>1</td><td>4</td><td>1</td></tr>
<tr><th scope=row>Hornet 4 Drive</th><td>21.4</td><td>6</td><td>258</td><td>110</td><td>3.08</td><td>3.215</td><td>19.44</td><td>1</td><td>0</td><td>3</td><td>1</td></tr>
<tr><th scope=row>Hornet Sportabout</th><td>18.7</td><td>8</td><td>360</td><td>175</td><td>3.15</td><td>3.440</td><td>17.02</td><td>0</td><td>0</td><td>3</td><td>2</td></tr>
<tr><th scope=row>Valiant</th><td>18.1</td><td>6</td><td>225</td><td>105</td><td>2.76</td><td>3.460</td><td>20.22</td><td>1</td><td>0</td><td>3</td><td>1</td></tr>
</tbody>
</table>
------ (4)![Relationship between milage and engine](test5_files/test5_3_1.png)

Explanation for this code block:

(1) This is the preamble. Pandoc will look for this block first of all and if it cannot find, it will raise a warning. Include at least a title, and a date information, and an author’s name
(2) This is the first slide deck with two hashes, states that it is a second level header and as this is followed by content, therefore this is deemed that the base level is 2
(3) A separator that will post a table in the next slide
(4) A separator that will post a figure in the next slide

Step 11. This document is saved as ‘test5.md’. We will now convert this markdown document to an html using pandoc. For this, we type the following code (assuming that you are in the correct folder):

~$ pandoc -t revealjs -s -o {output filename.html} {input markdown file name} -V revealjs-url={file or absolute URL}

So, in our case:

  • pandoc is the programme
  • revealjs = revealjs
  • output file name.html = test5.html
  • input file name = test5.md
  • revealjs-url = ./revealjs (that is the folder where revealjs resides)

Hence, we have:

~$ pandoc -t revealjs -s -o test5.html test5.md -V revealjs-url=./revealjs

If everything goes OK, this will produce the test5.html file.

Step 12. Now we connect our folder to git and commit the folder to our github repository. For this we do:

~$ git checkout -b gh-pages (1)
~$ git add . (2)
~$ git commit -m "added the slide deck files" (3)
~$ git push origin gh-pages (4)

Explanation:
(1) git checkout is the command you use to switch to the gh-pages branch you created earlier that allowed you to host your slides
(2) git add . is the command you use to add EVERYTHING in the git folder
(3) git commit -m signals that you add a text to indicate what did you do at that point: this is your version control
(4) git push origin gh-pages signifies that you added the files to your gh-pages branch from where they will be published

If everything goes OK, your site will now be live after a lag of about a minute (sometimes, it takes longer and patient is a virtue). Assuming that your username is ‘someusername’ and you created a github repository named ‘jupyterslidedeck’, your site will be live at:

https://someusername.github.io/jupyterslidedeck/test5.html

It will look like as follows:

Your first set of deck

Summary

So now you have created a slide deck. It is still far from complete as you will see that the table does not look alright, the figure shows the image but it can be better aligned, and so on. You may also want to add additional slides to it, and more interactions. We will address these in the next article in the series. So at least to summarise what we have done:

  1. Start a github repository that will contain your slides, say ‘myslides’
  2. Add a submodule to this github repository to your ‘instance’ or your machine (Mac/Linux/Windows) using the terminal; this will create a folder named ‘myslides’
  3. Change directory (cd) into myslides
  4. Get a copy of revealjs git repo zipped (master.zip) in this folder using wget command and then unzip everything with unzip command and then, rename the reveal.js folder to revealjs (optional)
  5. In the myslides folder start a jupyter notebook file and write the slide document with graphs and tables and lists and text
  6. Convert the ipynb file to markdown file format using jupyter nbconvert --to markdown
  7. Open the resulting markdown file in Jupyter itself and add a title block, add separators, remove (or you can retain) code blocks and so on
  8. Use pandoc to convert the markdown file to html using pandoc -t revealjs -s -o whatever.html whatever.md -V revealjs-url=./revealjs
  9. Of course step 8 assumes that whatever.md was your markdown file name, and revealjs was the folder where you downloaded and unzipped the master.zip file from revealjs git repo
  10. Now switch to the gh-pages branch, add the files to git repo, commit the changes, and push to your git repo. Your slide decks will be live

From now on, for any changes that you will make to the slides, you can either make them directly to the markdown file and work from there, OR you can make them in the jupyter notebook and re-run steps 6 through 10 in the above list.