Summary

This is just a demonstration of how I put graphs in my blog. I am using Hugo, the static site builder, org-mode, a file format for writing notes in emacs and org-babel, the builtin extension for org-mode for embedding code blocks in org files.

There is an emacs plugin called ox-hugo which allows you to export from org to markdown for hugo.

graphviz is the file format and tooling for designing graphs.

I am also using Graph::Easy, a perl module which renders graphs in ascii from the graphviz dot format.

org-babel

Babel allows you to embed code blocks into your org files and then run that code and see the results also embedded in the org file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#+BEGIN_SRC graphviz-dot -n :filter dot-digraph-ascii :async :results verbatim code
  "low-priority" [shape="doublecircle" color="orange"];
  "high-priority" [shape="doublecircle" color="orange"];

  "s1" -> "low-priority";
  "s2" -> "low-priority";
  "s3" -> "low-priority";

  "low-priority" -> "s4";
  "low-priority" -> "s5";
  "low-priority" -> "high-priority" [label="wait-time exceeded"];

  "high-priority" -> "s4";
  "high-priority" -> "s5";
#+END_SRC

+------------------------------------------------------+
|                                                      |
|  +----+     #==============#  wait-time exceeded   #===============#     +----+
|  | s1 | --> H              H --------------------> H high-priority H --> | s4 |
|  +----+     H              H                       #===============#     +----+
|             H              H                                               ^
|             H low-priority H ----------------------------------------------+
|             H              H
|  +----+     H              H                       +---------------+
|  | s2 | --> H              H <-------------------- |      s3       |
|  +----+     #==============#                       +---------------+
|               |
|               |
|               v
|             +--------------+
+-----------> |      s5      |
              +--------------+

dot-digraph-ascii

1
2
3
4
5
6
7
8
#!/bin/bash
export TTY

{
    echo "digraph Q {"
    awk1
    echo "}"
} | show-dot "$@"

show-dot

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/bin/bash
export TTY

( hs "$(basename "$0")" "$@" "#" "<==" "$(ps -o comm= $PPID)" 0</dev/null ) &>/dev/null

NOPRETTY=y
while [ $# -gt 0 ]; do opt="$1"; case "$opt" in
                                     "") { shift; }; ;;
                                     -pp|-pretty) {
                                         NOPRETTY=n
                                         shift
                                     }
                                                  ;;

                                     -np|-nopretty) {
                                                      NOPRETTY=y
                                                      shift
                                                  }
                                                    ;;

                                     *) break;
                                 esac; done

is_tty() {
    [[ -t 1 ]]
}

stdin_exists() {
    ! [ -t 0 ]
}

# This magically makes the UML into left-right istead of top-down
preprocess() {
    sed 's/shape="record"/\n&/'
}

postprocess() {
    #{
    #    sed 's/| \+{/| /' |
    #    sed 's/| }/|  /' |
    #    sed 's/|\([-+]\) /\n|---\n| \1 /'
    #} |
    if test "$NOPRETTY" = "y"; then
        cat
    else
        dot-pretty
    fi
}

if is_tty; then
    preprocess | graph-easy -- "$@" | postprocess | vs
else
    preprocess | graph-easy -- "$@" | postprocess
fi

graph-easy

1
2
3
4
5
6
7
8
9
#!/bin/bash
export TTY

( hs "$(basename "$0")" "$@" "#" "<==" "$(ps -o comm= $PPID)" 0</dev/null ) &>/dev/null

test -f "/usr/local/bin/graph-easy" && : "${bin:="/usr/local/bin/graph-easy"}"
test -f "$bin" || plf Graph::Easy &>/dev/null

"$bin" "$@"
1
2
# Install the Graph:Easy perl module
sudo cpanm --force Graph::Easy

More examples of graphviz diagrams

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#+BEGIN_SRC graphviz-dot -n :filter dot-digraph priority :async :results raw drawer
  "low-priority" [shape="doublecircle" color="orange"];
  "high-priority" [shape="doublecircle" color="orange"];

  "s1" -> "low-priority";
  "s2" -> "low-priority";
  "s3" -> "low-priority";

  "low-priority" -> "s4";
  "low-priority" -> "s5";
  "low-priority" -> "high-priority" [label="wait-time exceeded"];

  "high-priority" -> "s4";
  "high-priority" -> "s5";
#+END_SRC
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#+BEGIN_SRC graphviz-dot -n :filter dot-digraph-ascii-lr :async :results verbatim code
  "low-priority" [shape="doublecircle" color="orange"];
  "high-priority" [shape="doublecircle" color="orange"];

  "s1" -> "low-priority";
  "s2" -> "low-priority";
  "s3" -> "low-priority";

  "low-priority" -> "s4";
  "low-priority" -> "s5";
  "low-priority" -> "high-priority" [label="wait-time exceeded"];

  "high-priority" -> "s4";
  "high-priority" -> "s5";
#+END_SRC
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
โˆ˜โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โˆ˜
โ”ƒ                                                      โ”ƒ
โ”ƒ  โˆ˜โ”โ”โ”โ”โˆ˜     #==============#  wait-time exceeded   #===============#     โˆ˜โ”โ”โ”โ”โˆ˜
โ”ƒ  โ”ƒ s1 โ”ƒ โ”โ”> H              H โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”> H high-priority H โ”โ”> โ”ƒ s4 โ”ƒ
โ”ƒ  โˆ˜โ”โ”โ”โ”โˆ˜     H              H                       #===============#     โˆ˜โ”โ”โ”โ”โˆ˜
โ”ƒ             H              H                                               ^
โ”ƒ             H low-priority H โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โˆ˜
โ”ƒ             H              H
โ”ƒ  โˆ˜โ”โ”โ”โ”โˆ˜     H              H                       โˆ˜โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โˆ˜
โ”ƒ  โ”ƒ s2 โ”ƒ โ”โ”> H              H <โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”„โ”„โ”ƒ      s3       โ”ƒ
โ”ƒ  โˆ˜โ”โ”โ”โ”โˆ˜     #==============#                       โˆ˜โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โˆ˜
โ”ƒ               โ”ƒ
โ”ƒ               โ”ƒ
โ”ƒ               v
โ”ƒ             โˆ˜โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โˆ˜
โˆ˜โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”-> โ”ƒ      s5      โ”ƒ
              โˆ˜โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โˆ˜
1
2
3
4
5
6
7
8
9
"Back" [shape="egg" color="green" style="filled" fillcolor="yellow"];
"Forth" [shape="house" color="red"];
"Other" [shape="invtriangle" color="blue"];

"Back" -> "Forth" [color="orange" label="weee"];
"Forth" -> "Back" [color="purple" label="eeew"];

"Other" -> "Forth"
"Other" -> "Back"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
subgraph clusterEncoders {
    style = filled
    fillcolor = lightgrey
    node [style=filled,fillcolor=lightgrey,shape=circle];

    label = "Set of encoders"
    subgraph clusterEncoder1 {
        fillcolor = white
        label = "Encoder 1";
        f1[label="FFNN"]
        a1[label="Self-Attention layer"]
        a1 -> f1
    }
    subgraph clusterEncoder2 {
        fillcolor = white
        label = "Encoder 2";
        f2[label="FFNN"]
        a2[label="Self-Attention layer"]
        a2 -> f2
    }
    subgraph clusterEncoderN {
        fillcolor = white
        label = "Encoder N";
        etc [label="..."]
    }

    f1 -> a2 [label="list of 512D vectors"]
    f2 -> etc [label="list of 512D vectors"]
}

Sparse Matrix

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
node [shape=box]

/* add group 1 for vertical alignment */
Mt[ label = "Matrix", width = 1.5, style = filled, fillcolor = firebrick1, group = 1 ];

/* empty nodes, needed to override graphiz' default node placement */
e0[ shape = point, width = 0 ];
e1[ shape = point, width = 0 ];


//(^< ............ ............ ............ ............ ............ U S U A R I O S
/* groups added for vertical alignment */
U0 [label = "Estructuras"    pos = "5.3,3.5!" width = 1.5 style = filled, fillcolor = bisque1, group = 1 ];
U1 [label = "Redes"          width = 1.5 style = filled, fillcolor = bisque1, group = 1 ];
U2 [label = "Compiladores"   width = 1.5 style = filled, fillcolor = bisque1, group = 1 ];
U3 [label = "Investigacion"  width = 1.5 style = filled, fillcolor = bisque1, group = 1 ];
U4 [label = "Lenguajes"      width = 1.5 style = filled, fillcolor = bisque1, group = 1 ];

//(^< ............ Links
U0 -> U1;
U1 -> U0;
U1 -> U2;
U2 -> U1;
U2 -> U3;
U3 -> U2;
U3 -> U4;
U4 -> U3;

//(^< ............ ............ ............ ............ ............ A R C H I V O S
/* groups 2 to 6 added for vertical alignment */
A0 [label = "Josefina"   width = 1.5 style = filled, fillcolor = lightskyblue, group = 2 ];
A1 [label = "Alejandro"  width = 1.5 style = filled, fillcolor = lightskyblue, group = 3 ];
A2 [label = "Marco"      width = 1.5 style = filled, fillcolor = lightskyblue, group = 4 ];
A3 [label = "Julian"     width = 1.5 style = filled, fillcolor = lightskyblue, group = 5 ];
A4 [label = "Pamela"     width = 1.5 style = filled, fillcolor = lightskyblue, group = 6 ];

//(^< ............ Links
A0 -> A1;
A1 -> A0;
A1 -> A2;
A2 -> A1;
A2 -> A3;
A3 -> A2;
A3 -> A4;
A4 -> A3;

Mt -> U0;
Mt -> A0;

{ rank = same; Mt; A0; A1; A2; A3; A4; }

//(^< ............ ............ ............ ............ ............ P E R M I S O S
//(^< ............ ............ L E V E L   0
/* groups 2 to 6 added for vertical alignment */
N0_L0 [label = "Jose-Estr" width = 1.5, group = 2 ];
N1_L0 [label = "Marc-Estr" width = 1.5, group = 4 ];
N2_L0 [label = "Juli-Estr" width = 1.5, group = 5 ];

//(^< ............ ............ L E V E L   2
N0_L2 [label = "Marc-Comp" width = 1.5, group = 4 ];
N1_L2 [label = "Juli-Comp" width = 1.5, group = 5 ];

//(^< ............ ............ L E V E L   4
N0_L4 [label = "Marc-Leng" width = 1.5, group = 4 ];
N1_L4 [label = "Juli-Leng" width = 1.5, group = 5 ];
N2_L4 [label = "Pame-Leng" width = 1.5, group = 6 ];


//(^< ............ ............ ............ ............ ............ L I N K I N G
//(^< ............ ............ L E V E L   0

U0 -> N0_L0;
A0 -> N0_L0;
N0_L0 -> N1_L0;
N1_L0 -> N0_L0;
A2 -> N1_L0;
N1_L0 -> N2_L0;
N2_L0 -> N1_L0;
A3 -> N2_L0;

{ rank = same; U0; N0_L0;N1_L0;N2_L0; }
//(^< ............ ............ L E V E L   2

U2 -> N0_L2;
N0_L2 ->N1_L0;
N1_L0 ->N0_L2;
N0_L2 -> N1_L2;
N1_L2 -> N0_L2;
N1_L2 ->N2_L0;
N2_L0 ->N1_L2;

{ rank = same; U2; N0_L2;N1_L2; }
//(^< ............ ............ L E V E L   4

U4 -> N0_L4;
N0_L4 -> N0_L2;
N0_L2 -> N0_L4;
N0_L4 -> N1_L4;
N1_L4 -> N0_L4;
N1_L4 -> N1_L2;
N1_L2 -> N1_L4;
N1_L4 -> N2_L4;
N2_L4 -> N1_L4;

{ rank = same; U4; N0_L4;N1_L4;N2_L4; }

/* we divide the edge from A4 to N2_L4 into 'sub-edges',
   thus indirectly making sure that the U nodes stay in their place */
{ rank = same; U2; e0 }
{ rank = same; U3; e1 }
A4 -> e0 -> e1[ dir = none ];
e1 -> N2_L4;