Presentation as Code

Create modern presentations using ORG mode and reveal.js

2022-01 Victor Dorneanu

1. Motivation

  • because I was sick of Powerpoint
    • but also Latex was/is at some point way to much for a simple presentation
  • ORG file should be single source of truth
    • you can export to multiple formats
      • PDF
      • HTML
      • Markdown/Asciidoc etc.
      • but also reveal.js presentations
  • reveal.js looks awesome
  • highly inspired by Reveal my Asciidoc - A deep dive into presentation-as-code
    • but I wanted to do it without asciidoc
    • “purely” in Emacs and ORG mode

2. Navigation

These keyboard shortcuts are available:

  • ?: to see the help menu
  • navigation:
    • l: next slide
    • h: previous slide
    • k: navigate up
    • j: navigate down
  • m: to toggle menu
    • you can switch between themes
    • you can jump directly to slides
  • ESC / O: slide overview
  • CTRL+SHIFT F: search in presentation

3. Features

  • this presentation uses CDN to fetch required (JavaScript) libraries
    • no need to checkout reveal.js repository
    • if you want to use your own theme, then you’ll need to have the CSS files somewhere on your disk
  • you can easily embed nice looking charts and diagrams
    • I like c3js for charts and plantuml for diagrams
    • but you can add your libraries (check #REVEAL_HEAD_PREAMBLE at the beginning of the reveal.org file)
  • diagrams are embedded as inline PNG (encoded as base64) in the resulting HTML document
    • I use a hook to transform each PNG into base64 on export
    • This hook is part of the project variables defined in .dir-locals.el
  • I distinguish between content and generated HTML/CSS content (available at public)

4. Where to start?

For the beginning I’d recommend you the following steps:

5. What if you don’t use ORG and Emacs?

  • Don’t worry!
  • You can still use plain HTML to create your reveal.js presentation (not really recommended)
  • You could use markdown
  • Have a look at asciidoctor (asciidoc syntax) and asciidoctor reveal.js
    • asciidoc syntax is really simple
    • you have great support for charts, source code listings and many other things
    • also checkout Zenika’s adoc presentation model repository for a full-featured example
  • you can also export from ORG to asciidoctor using org-asciidoc
    • recently I’ve submitted an issue for better literals support

6. Showcase

Now it’s time for some demos

  • Charts using C3.js
  • Diagrams using PlantUML
  • Literate programming

7. C3.js

Awesome D3.js based chart library. Basic usage in the ORG file:

#+begin_export html
<div id="chart_example"></div>
var chart = c3.generate({
    bindto: '#chart_example',
    size: {
      width: <svg width>,
      height: <svg height>,
    },
    data: {
     <Your data>
    }
});
<script>
#+end_export

All charts are interactive. So make sure you use your mouse! And have a look at all examples.

7.1. Basic line chart

#+begin_export html
<div id="chart"></div>
<script>
var chart = c3.generate({
    bindto: '#chart',
    size: {
      width: 800,
      height: 550,
    },
    data: {
      columns: [
        ['data1', 30, 200, 100, 400, 150, 250],
        ['data2', 50, 20, 10, 40, 15, 25]
      ]
    }
});
</script>
#+end_export

7.2. Pie chart

#+begin_export html
<div id="chart2"></div>
<script>
var chart = c3.generate({
    bindto: '#chart2',
    size: {
      width: 600,
      height: 550,
    },
    data: {
        columns: [
            ['data1', 30],
            ['data2', 120],
            ["setosa", 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.2, 0.5, 0.2, 0.2, 0.4, 0.2, 0.2, 0.2, 0.2, 0.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.6, 0.4, 0.3, 0.2, 0.2, 0.2, 0.2],
            ["versicolor", 1.4, 1.5, 1.5, 1.3, 1.5, 1.3, 1.6, 1.0, 1.3, 1.4, 1.0, 1.5, 1.0, 1.4, 1.3, 1.4, 1.5, 1.0, 1.5, 1.1, 1.8, 1.3, 1.5, 1.2, 1.3, 1.4, 1.4, 1.7, 1.5, 1.0, 1.1, 1.0, 1.2, 1.6, 1.5, 1.6, 1.5, 1.3, 1.3, 1.3, 1.2, 1.4, 1.2, 1.0, 1.3, 1.2, 1.3, 1.3, 1.1, 1.3],
            ["virginica", 2.5, 1.9, 2.1, 1.8, 2.2, 2.1, 1.7, 1.8, 1.8, 2.5, 2.0, 1.9, 2.1, 2.0, 2.4, 2.3, 1.8, 2.2, 2.3, 1.5, 2.3, 2.0, 2.0, 1.8, 2.1, 1.8, 1.8, 1.8, 2.1, 1.6, 1.9, 2.0, 2.2, 1.5, 1.4, 2.3, 2.4, 1.8, 1.8, 2.1, 2.4, 2.3, 1.9, 2.3, 2.5, 2.3, 1.9, 2.0, 2.3, 1.8],
        ],
        type : 'donut',
        onclick: function (d, i) { console.log("onclick", d, i); },
        onmouseover: function (d, i) { console.log("onmouseover", d, i); },
        onmouseout: function (d, i) { console.log("onmouseout", d, i); }
    },
    donut: {
        title: "Iris Petal Width"
    }
});
</script>
#+end_export

7.3. Combination of line and bar chart

#+begin_export html
<div id="chart3"></div>
<script>
var chart = c3.generate({
    bindto: '#chart3',
    data: {
        columns: [
            ['data1', 30, 20, 50, 40, 60, 50],
            ['data2', 200, 130, 90, 240, 130, 220],
            ['data3', 300, 200, 160, 400, 250, 250],
            ['data4', 200, 130, 90, 240, 130, 220],
            ['data5', 130, 120, 150, 140, 160, 150],
            ['data6', 90, 70, 20, 50, 60, 120],
        ],
        type: 'bar',
        types: {
            data3: 'spline',
            data4: 'line',
            data6: 'area',
        },
        groups: [
            ['data1','data2']
        ]
    },
    size: {
      width: 800,
      height: 550,
    }
});
</script>
#+end_export

7.4. Custom data colors

#+begin_export html
<div id="chart4"></div>
<script>
var chart = c3.generate({
    bindto: '#chart4',
    size: {
      width: 700,
      height: 550,
    },
    data: {
        columns: [
            ['data1', 30, 20, 50, 40, 60, 50],
            ['data2', 200, 130, 90, 240, 130, 220],
            ['data3', 300, 200, 160, 400, 250, 250]
        ],
        type: 'bar',
        colors: {
            data1: '#ff0000',
            data2: '#00ff00',
            data3: '#0000ff'
        },
        color: function (color, d) {
            // d will be 'id' when called for legends
            return d.id && d.id === 'data3' ? d3.rgb(color).darker(d.value / 150) : color;
        }
    }
});
</script>
#+end_export

8. Diagrams

I like to express myself through pictures/diagrams. A picture is still worth a thounsand words. That’s why I use them:

  • to visualize
    • software architecture
    • (cloud) infrastructure
    • depedencies between some components
    • mind maps
  • to document
    • architectural decisions
    • overall project state

8.1. Plantuml

Let me quote Wikipedia:

PlantUML is an open-source tool allowing users to create diagrams from a plain text language. Besides various UML diagrams, PlantUML has support for various other software development related formats (such as Archimate, Block diagram, BPMN, C4, Computer network diagram, ERD, Gantt chart, Mind map, and WBD), as well as visualisation of JSON and YAML files.

The language of PlantUML is an example of a domain-specific language. Besides its own DSL, PlantUML also understands AsciiMath, Creole, DOT, and LaTeX. It uses Graphviz software to layout its diagrams and Tikz for LaTeX support. Images can be output as PNG, SVG, LaTeX and even ASCII art. PlantUML has also been used to allow blind people to design and read UML diagrams.

Just give it a try. You won’t regret it! Also check out real-worl-plantuml.com for some real examples.

Basic usage in ORG:

#+begin_src plantuml :noweb-ref <id> <options>
@startuml
...
@enduml
#+end_src

8.1.1. Components

@startuml
scale 720 width
skinparam dpi 300
skinparam backgroundcolor transparent
note as n
	ActiveRecord
	("save yourself")
end note

note left of Ballot
	Ballot ballot = new Ballot( ... );
	ballot.save();
end note
@enduml


8.1.2. Components

@startuml
scale 720 width
skinparam dpi 300
skinparam backgroundcolor transparent
note as n
	ActiveRecord
	("save yourself")
end note

class DAO{
	{static} Entity find(id)
	{static} List<Entity> findBy(criteria for select)
	update(Entity)
	save(Entity)
	delete(Entity)
	{static} Finder
}

Ballot --|> DAO

note left of Ballot
	Ballot ballot = new Ballot( ... );
	ballot.save();
end note
@enduml


8.1.3. Sequence diagram

@startuml
scale 720 width
skinparam dpi 300
skinparam backgroundcolor transparent

skinparam Shadowing false


Alice -> Bob: Authentication Request
Bob -> RequestHandler: validated Authenticated Request
RequestHandler --> Bob: Authenticated Response (OK)
Bob --> Alice: Authentication Response (OK)
@enduml


8.1.4. Display JSON data

@startjson
#highlight "lastName"
#highlight "address" / "city"
#highlight "phoneNumbers" / "0" / "number"
{
  "firstName": "John",
  "lastName": "Smith",
  "isAlive": true,
  "age": 28,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    }
  ],
  "children": [],
  "spouse": null
}
@endjson


8.1.5. Same for YAML

@startyaml
#highlight "french-hens"
#highlight "xmas-fifth-day" / "partridges"

doe: "a deer, a female deer"
ray: "a drop of golden sun"
pi: 3.14159
xmas: true
french-hens: 3
calling-birds:
    - huey
    - dewey
    - louie
    - fred
xmas-fifth-day:
    calling-birds: four
    french-hens: 3
    golden-rings: 5
    partridges:
        count: 1
        location: "a pear tree"
    turtle-doves: two
@endyaml


8.1.6. Simple network diagrams

@startuml
scale 720 width
skinparam dpi 300
skinparam backgroundcolor transparent

nwdiag {
  network NETWORK_BASE {
   width = full
   dev_A   [address = "dev_A" ]
   dev_B [address = "dev_B" ]
  }
  network IntNET1 {
   width = full
   dev_B [address = "dev_B1" ]
   dev_M [address = "dev_M1" ]
  }
}
@enduml


8.1.7. C4 ACME Example


8.1.8. Source C4 ACME Example

@startuml
scale 720 width
skinparam dpi 300
skinparam backgroundcolor transparent

!include  <C4/C4_Context.puml>
!include <office/Users/user.puml>

LAYOUT_WITH_LEGEND()


title Top level Context diagram for ACME Global Widget Production


Person(AcmeProdOwner, Acme Production Owner , "<$user> \n Responsible for Production of widgets in ACME Production Site" )
Person(3rdProdOwner, 3rdParty Production Owner , "<$user> \n Responsible for Production of widgets in 3rdParty Production Site" )


System_Boundary(Remote, "Remote") {

    System(ProdSystemHost, "Production Host", "Drives widget Production\n Analyses widget Production data to create reports")
    System(Analytics, "Analytics", "Provides data analysis and a dashboard view data - including relevant Production data")
    System(Monitoring, "Monitoring", "Monitors Production Host\nUses AWS Services")
    System_Ext(SupplyChain, "SupplyChain", "Provides parts to make the widgets")
    System_Ext(InventoryTracking, "InventoryTracking", "Customer Reference")


}



Enterprise_Boundary(AcmeProd, "ACME Production Site") {

    System(AcmeWorkStation1, "WorkStation1", " Production setup for a group of widgets")
    System(AcmeWorkStation2, "WorkStation2", " Production setup for a group of widgets")
    System(AcmeWorkStationN, "WorkStationN", " Production setup for a group of widgets")

}


Enterprise_Boundary(3rdProd, "3rdParty Production Site") {


    System(3rdWorkStation1, "WorkStation1", " Production setup for a group of widgets")
    System(3rdWorkStation2, "WorkStation2", " Production setup for a group of widgets")
    System(3rdWorkStationN, "WorkStationN", " Production setup for a group of widgets")
}


Rel_U(AcmeWorkStation1, ProdSystemHost, "Sends Production report for widget")
Rel_U(AcmeWorkStation2, ProdSystemHost, "Sends Production report for widget")
Rel_U(AcmeWorkStationN, ProdSystemHost, "Sends Production report for widget")


Rel_U(3rdWorkStation1, ProdSystemHost, "Sends Production report for widget")
Rel_U(3rdWorkStation2, ProdSystemHost, "Sends Production report for widget")
Rel_U(3rdWorkStationN, ProdSystemHost, "Sends Production report for widget")





Rel_D(AcmeProdOwner, ProdSystemHost, "Reviews Acme and 3rdParty site Production reports")
Rel_D(3rdProdOwner, ProdSystemHost, "Reviews 3rdParty site Production reports")


Rel_D(Analytics, ProdSystemHost, "Data Analysis")
Rel_D(SupplyChain, ProdSystemHost, "Parts")
Rel_D(InventoryTracking, ProdSystemHost, "Tracking")
Rel_D(Monitoring, ProdSystemHost, "Monitoring")

footer %filename() rendered with PlantUML version %version()\nThe Hitchhiker’s Guide to PlantUML

@enduml

8.1.9. Additional resources

9. Literate programming

  • You can use ORG babel to execute code within ORG documents.
  • similar to IPython/Jupyter notebooks
  • you can use Babel to document your code and the results/output at the same place.

9.1. Shell

uname
Linux

9.2. HTTP requests

GET https://api.github.com/repos/zweifisch/ob-http/languages
Accept: application/vnd.github.moondragon+json
{
  "Emacs Lisp": 15327,
  "Shell": 139
}

ob-http is awesome!

9.3. Elisp

(directory-files ".")
("." ".." "2022-hexagonal-architecture.org" "2022-presentations-as-code.org" "2023-kubernetes.org" "images" "index.org" "notes-style.setup" "reveal.org" "revealjs-plugins-conf.js" "themes")

9.4. Golang

package main
import "fmt"

func main() {
    queue := make(chan string, 2)
    queue <- "one"
    queue <- "two"
    close(queue)

    for elem := range queue {
        fmt.Println(elem)
    }
}
one
two

9.5. Python

num = 8
num_sqrt = num ** 0.5
print('The square root of %0.3f is %0.3f'%(num ,num_sqrt))
The square root of 8.000 is 2.828

9.6. gnuplot

Ben 9.2 9.9
Tim 6.7 7.7
Tom 7.5 6.7
Dean 8.0 7.0
set title "Students' Grades"
set yrange[0:10]
set style data histogram
set terminal png size 400,300
plot data using 2:xtic(1) title 'Maths', '' using ($3) title 'Physics'


10. Conclusion

  • ORG mode is still one of the most powerful markup languages for text
  • if you don’t have the time (and motivation) to learn Emacs/ORG mode
    • have a look at asciidoctor and asciidoc
    • if you don’t like ruby and gems, check out AsciidoctorJ which is a library for running asciidoctor on the JVM
    • there are tons of extensions you can chose from
  • creating beautiful presentations for reveal.js is fun and doable just by writing (markup) code
  • convince yourself and have a look at the source of this presentation
    • text content and images at the same place
    • charts can be easily embedded via custom HTML code
    • all sorts of diagrams can be generated using PlantUML
    • you can focus on writing content rather than fixing your presentation’s layout
  • you can do way more with ORG

11. Contact

About
dornea.nu
Blog
blog.dornea.nu
Github
github.com/dorneanu
Twitter
@victordorneanu
LinkedIn
linkedin.com/in/victor-dorneanu
Threema
HCPNAFRD