graph = {
let header = `
rankdir = "TB";
ranksep = "0.2";
nodesep = "0.1";
concentrate = "true";
outputorder = "edgesfirst";
ratio = "auto";
size = "16,10";
edge[arrowsize="0.75", penwidth="0.25"]
graph[bgcolor = "transparent" ]`
let nodestyle = `node [
shape="box", margin="0.1,0", style="filled,rounded,bold",
color="#e17892", fillcolor="white", labelfontcolor="white",
fontcolor="#000000", fontname= Arial
]`
let edgestyle = `edge [color="#dddddd", style="", fontname= Arial]`
let years = Array.from(nodes.values())
let range = [
2 * Math.floor(Math.min(...years.map(d=>d.first)) / 2),
2 * Math.ceil(Math.max(...years.map(d=>d.last)) / 2)
]
let groups = Object.entries(
Object.groupBy(
Array.from(nodes.entries()),
d => Math.round(d[1].mid)
)
).sort((a,b)=>parseFloat(a[0]) -parseFloat(b[0]))
// selected years
range = [
parseInt(groups.at(0)[0]),
parseInt(groups.at(-1)[0])
]
let timeline = `node [fontsize=20, shape = box, fontname= Arial, fontsize = 14]; edge [/*style=invis*/penwidth=4];` //
timeline = timeline + "\n" +
Array.from({length:range[1]-range[0]},(_,i)=>' '+(i+range[0]) + ' -> ' + (i+range[0]+1)).join("\n")
// code for 'half years' -> needs rounded groups also (see above)
// Array.from({length:(range[1]-range[0])*2},(_,i)=>' "'+((i/2)+range[0]) + '" -> "' + ((i/2)+range[0]+0.5)+'"')
//.map((d,i,f)=> !/\.5"$/.test(f[i-1]) ? d + 'node [style=""]' : d + 'node [style=invis]' )
//.join("\n")
let filtered = coWordEdges
.filter((d) => nodes.has(d.src) && nodes.has(d.tgt))
//.filter(d=> d.till <= nodes.get(d.tgt).first && d.from <= nodes.get(d.src).last)
let edgelist =
// prune edges using group slicing
Object.values(Object.groupBy(filtered,d=>d.src)).map(d=>d.slice(0,4)).flat()
.map((d) => ` "${d.src}" -> "${d.tgt}" [weight=${Math.pow(d.weight,0.5)}, penwidth=${Math.pow(d.weight,0.25)}, opacity=0.1, dir=none]`)
.join("\n")
return `digraph timeline {
${header}
${timeline}
${nodestyle}
${groups.map((d) => `{ rank=same; ${[d[0], d[1].map((d) => '"' + d[0] + '"').join(" ")].join(" ")}; }`).join("\n")}
${edgestyle}
${edgelist}
${''/*
"Gardner" -> "Lambert" [weight=2.8284271247461903, penwidth=1.6817928305074292, opacity=0.1, dir=none, label="Influenced"]
"Gardner" -> "Scarcella" [weight=3, penwidth=1.7320508075688772, opacity=0.1, dir=none, label="Mentorship"]
"Lambert" -> "Carroll" [weight=2, penwidth=1.414213562373095, opacity=0.1, dir=none, label="Collaboration"]
"Selinker" -> "Scarcella" [weight=3, penwidth=1.7320508075688772, opacity=0.1, dir=none, label="Foundational Work"]
"Hatch" -> "Scarcella" [weight=3.4641016151377544, penwidth=1.8612097182041991, opacity=0.1, dir=none, label="Key Collaboration"]
"Krashen" -> "Scarcella" [weight=7.483314773547883, penwidth=2.735564799734761, opacity=0.1, dir=none, label="Major Influence"]
"Dulay" -> "Burt" [weight=4.123105625617661, penwidth=2.0305431848689306, opacity=0.1, dir=none, label="Shared Research"]
"Schumann" -> "Seliger" [weight=1.7320508075688772, penwidth=1.3160740129524924, opacity=0.1, dir=none, label="Theoretical Alignment"]
"Swain" -> "Scarcella" [weight=2.449489742783178, penwidth=1.5650845800732873, opacity=0.1, dir=none, label="Conceptual Contribution"]
"Fröhlich" -> "Scarcella" [weight=1.7320508075688772, penwidth=1.3160740129524924, opacity=0.1, dir=none, label="Direct Influence"]*/}
}`.replaceAll('\n','')
}