Add script to generate concept maps using Graphviz
This commit is contained in:
parent
495185139b
commit
1b9d4a4a93
|
@ -0,0 +1,177 @@
|
|||
SIMPLE_DOT=$(cat <<'EOF'
|
||||
BEGIN {
|
||||
edge = "->"
|
||||
properties_separator = ";"
|
||||
open_blocks = "{"
|
||||
close_blocks = "}"
|
||||
hyperedge_property = "_he"
|
||||
uuid_command = "uuidgen"
|
||||
|
||||
blocks = 0
|
||||
processed_line = 0
|
||||
|
||||
# Print the graph header.
|
||||
#print "digraph {"
|
||||
}
|
||||
|
||||
# Firstly, we process blocks.
|
||||
NF == 1 && $1 == open_blocks {
|
||||
# open block
|
||||
blocks++
|
||||
}
|
||||
|
||||
NF == 1 && $1 == "}" {
|
||||
# close block
|
||||
blocks--
|
||||
}
|
||||
|
||||
# Secondly, we process "special rules".
|
||||
## Nodes.
|
||||
NF > 1 && $2 != edge {
|
||||
printf ($1 "\t")
|
||||
label = get_label($0)
|
||||
get_properties($0, properties)
|
||||
properties_str = generate_properties(label, properties)
|
||||
if (length(properties_str)) {
|
||||
print properties_str
|
||||
}
|
||||
|
||||
processed_line = 1
|
||||
}
|
||||
|
||||
## Edges.
|
||||
NF > 3 && $2 == edge {
|
||||
printf ($1 FS $2 FS $3)
|
||||
label = get_label($0)
|
||||
get_properties($0, properties)
|
||||
properties_str = generate_properties(label, properties)
|
||||
if (length(properties_str)) {
|
||||
printf "\t"
|
||||
print properties_str
|
||||
}
|
||||
|
||||
processed_line = 1
|
||||
}
|
||||
|
||||
# Thirdly, we do general treatment for every line.
|
||||
{
|
||||
if (!processed_line) {
|
||||
print $0
|
||||
}
|
||||
processed_line = 0
|
||||
}
|
||||
|
||||
END {
|
||||
# Print the closing curly brace.
|
||||
print "}"
|
||||
}
|
||||
|
||||
function get_label(_line, _field, _out, _split, _len) {
|
||||
_field = 2
|
||||
if ($2 == edge) {
|
||||
_field = 4
|
||||
}
|
||||
|
||||
# Special case: there isn't label, but there are properties.
|
||||
_len = split($(_field), _split, properties_separator)
|
||||
if ((_len > 1) && !_split[1]) {
|
||||
# There is a properties_separator in the field, and no label.
|
||||
return
|
||||
}
|
||||
|
||||
for (_field; _field <= NF; _field++) {
|
||||
_len = split($(_field), _split, properties_separator)
|
||||
if (_len > 1) {
|
||||
_out = !(_out) ? _split[1] : (_out FS _split[1])
|
||||
return _out
|
||||
} else {
|
||||
_out = !(_out) ? $(_field) : (_out FS $(_field))
|
||||
}
|
||||
}
|
||||
return _out
|
||||
}
|
||||
|
||||
function get_properties(_line, _split, _field, _len, _uuid) {
|
||||
delete _split
|
||||
_len = split(_line, _split, properties_separator)
|
||||
if (!_len) {
|
||||
return
|
||||
}
|
||||
|
||||
for (_field = 2; _field <= _len; _field++) {
|
||||
if (_split[_field] == hyperedge_property) {
|
||||
uuid_command | getline _uuid
|
||||
_split[_field] = hyperedge_property "=\"" _uuid "\""
|
||||
close(uuid_command)
|
||||
}
|
||||
_split[_field - 1] = _split[_field]
|
||||
}
|
||||
delete _split[_len]
|
||||
return
|
||||
}
|
||||
|
||||
function generate_properties(_label, _properties, _out, _len, _type_label) {
|
||||
_type_label = "label"
|
||||
for (p in _properties) {
|
||||
if (match(hyperedge_property, _properties[p])) {
|
||||
_type_label = "xlabel"
|
||||
}
|
||||
}
|
||||
if (_label) {
|
||||
_out = (_type_label "=\"" _label "\"")
|
||||
}
|
||||
|
||||
_len = length(_properties)
|
||||
for (i = 1; i <= _len; i++) {
|
||||
_out = !(_out) ? _properties[1] : (_out "," _properties[i])
|
||||
}
|
||||
|
||||
return (!(_out) ? "" : ("[" _out "]"))
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
HYPERGRAPH_PROCESSOR=$(cat <<'EOF'
|
||||
// An attempt to reproduce what was reported in https://gitlab.com/graphviz/graphviz/-/issues/1911#note_473279838
|
||||
|
||||
E [ _he ] {
|
||||
// Creates the node representing the hyper-edge, if it already doesn't exist.
|
||||
node_t hyperedge = isNode($G, $._he);
|
||||
if (!hyperedge) {
|
||||
hyperedge = node($G, $._he);
|
||||
hyperedge.shape = "point";
|
||||
hyperedge.fillcolor = "red";
|
||||
if ($.label) {
|
||||
/*
|
||||
hyperedge.label = $.label;
|
||||
hyperedge.shape = "none";
|
||||
*/
|
||||
hyperedge.xlabel = $.label;
|
||||
}
|
||||
}
|
||||
|
||||
// Creates the edges to and from hyperedge, if it already doesn't exist.
|
||||
if (!isEdge_sg($G, $.tail, hyperedge, "")) {
|
||||
edge_t new_out = edge_sg($G, $.tail, hyperedge, "");
|
||||
new_out.arrowhead = "none";
|
||||
}
|
||||
if(!isEdge_sg($G, hyperedge, $.head, "")) {
|
||||
edge_t new_in = edge_sg($G, hyperedge, $.head, "");
|
||||
}
|
||||
|
||||
// Removes the current edge (with attribute "_he") because edges to "hyperedge" are added.
|
||||
delete($G, $);
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
# Process the input files and produce a SVG.
|
||||
cat <(echo "digraph {") ~/src/scripts/concept-style.dot <(awk -f <(echo "${SIMPLE_DOT}") $*) |
|
||||
gvpr -c -f <(echo "${HYPERGRAPH_PROCESSOR}") |
|
||||
dot -Tsvg
|
||||
|
||||
## DEAD-CODE
|
||||
## awk -f ~/tmp/graphviz/concept.awk $* |
|
||||
## gvpr -c -f ~/tmp/graphviz/hypergraph.gvpr |
|
||||
## xsel -ib
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Style taken, and modified, from https://mostlymaths.net/2023/07/concept-maps-helper.html/
|
||||
layout=dot
|
||||
margin=1
|
||||
bgcolor="#ffffff00"
|
||||
rankdir=TB
|
||||
fontname="Sans-Serif"
|
||||
nodesep=0.5
|
||||
overlap=scale
|
||||
compound=true
|
||||
node [
|
||||
fontname = "Sans-Serif"
|
||||
style="rounded,filled"
|
||||
labelloc=c
|
||||
margin="0.3,0.15"
|
||||
splines=true
|
||||
shape=rect
|
||||
fontsize=15
|
||||
];
|
||||
edge [
|
||||
minlen=3
|
||||
penwidth=2
|
||||
color="#33333388"
|
||||
fontname="Sans-Serif"
|
||||
fontsize=14
|
||||
arrowhead=normal // Latest papers about cmaps have recovered heads
|
||||
];
|
||||
graph [
|
||||
//margin=8
|
||||
style="rounded,dotted"
|
||||
];
|
||||
fontsize=24
|
||||
labelloc="t"
|
Loading…
Reference in New Issue