Public
Edited
Mar 23, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
df2dot = function(df) {
const { operators } = df;
const edges = [];

for (const operator of operators) {
if ('parent' in operator) {
edges.push({
from: operator.parent.$ref,
to: operator.id,
kind: 'parent',
label: 'parent'
});
}
for (const [key, value] of Object.entries(operator.params ?? {})) {
if (value instanceof Object && '$ref' in value) {
edges.push({
from: value.$ref,
to: operator.id,
kind: 'param',
label: key
});
}
}
}

return `digraph {
rankdir = LR;
node [style=filled];
${operators
.map(operator => {
return `${operator.id} [label="${nodeLabel(
operator
)}"; fillcolor="${nodeFillColor(operator)}"]`;
})
.join(';\n ')};
${edges
.map(edge => {
return `${edge.from} -> ${edge.to} [label="${edge.label ??
""}"; color="${edgeColor(edge)}"; weight="${edgeWeight(edge)}"]`;
})
.join(';\n ')};
}`;
}
Insert cell
nodeLabel = function(operator) {
switch (operator.type) {
case 'scale':
return `${operator.scale}`;
case 'mark':
return `mark ${operator.params.markdef.marktype}`;
case 'sieve':
return operator.type;
case 'collect':
console.log(operator);
return operator.type;
case 'render':
return operator.type;
case 'encode':
return operator.type;
case 'bound':
return operator.type;
case 'viewlayout':
return operator.type;
case 'datajoin':
return `${operator.type}\n${
operator.params.key ? `key: ${operator.params.key.$field}` : ""
}`;
case 'proxy':
return operator.type;
case 'operator':
if (operator.root) {
return 'root';
}
return operator.signal;
case 'values':
return operator.type;
case 'extent':
return operator.type;
case 'aggregate':
return operator.type;
case 'axisticks':
return operator.type;
default:
console.log('not handled', operator);
return operator.type;
}
}
Insert cell
escapeText = function(text) {
return text.replaceAll('"', '\\\"')
}
Insert cell
nodeFillColor = function(operator) {
if (operator.data) {
return '#ffcccc';
}

if (operator.root || markTypes[operator.type]) {
return '#ccccff';
}

switch (operator.type) {
case 'scale':
return '#ccffcc';
case 'mark':
return '#ccccff';
case 'operator':
return '#dddddd';
case 'render':
return 'deepskyblue';
default:
return 'white';
}
}
Insert cell
edgeColor = function(edge) {
switch (edge.kind) {
case 'parent':
return 'black';
default:
return edge.label === 'pulse' ? 'black' : 'gray60';
}
}
Insert cell
edgeWeight = function(edge) {
return edge.label === 'pulse' ? 200 : 1;
}
Insert cell
markTypes = ({
datajoin: 1,
encode: 1,
mark: 1,
bound: 1,
overlap: 1,
sortitems: 1,
render: 1,
viewlayout: 1
})
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more