Ein gutes Layout ist unerlässlich, um die inhärente Struktur in den verknüpften Daten aufzudecken. Hierarchische Layouts werden typischerweise verwendet, um Eltern-Kind-Beziehungen zwischen den Diagrammknoten anzuzeigen. Die standardmäßige D3.js-Implementierung des hierarchischen Layouts kann nicht für reale Daten verwendet werden, bei denen ein Kindknoten mehrere Elternknoten haben kann. Wir verwenden WebCola und D3.js, um ein hierarchisches Graphenlayout mit deklarativer Spezifikation von Einschränkungen in wenigen Zeilen Code zu zeichnen.
Die reale Welt ist reichlich vernetzt, und ich denke, dass unsere Benutzeroberflächen diese Verbindungen nachahmen sollten. Verbindungen in Netzwerken vermitteln Informationen. Ein flüchtiger Blick auf ein Netzwerk kann, wenn es richtig dargestellt wird, inhärente Strukturen aufdecken, die auf den ersten Blick nicht sichtbar sind. Angesichts der hochgradig vernetzten Daten unserer Kunden haben wir bei Alyne beschlossen, einige Zeit in eine skalierbare Visualisierung zu investieren, die die Daten und die Verbindungen zwischen ihnen auf intuitive Weise darstellt.
Einer der Anwendungsfälle, der bei Alyne am meisten genutzt wird, ist unsere Objektbibliothek. Wir ermöglichen unseren Kunden, ihre digitalen und physischen Assets in der Objektbibliothek in unserer Anwendung zu replizieren. Solche Assets sind in der Regel hierarchisch aufgebaut, und wir haben festgestellt, dass Netzwerkdiagramme ein gutes Werkzeug sein können, um den Kunden einen Überblick über ihre Objektlandschaft zu verschaffen.
Netzwerk-Visualisierung
Eine der einfachsten und leistungsfähigsten Methoden zur Visualisierung von Netzwerken ist ein kraftgerichtetes Netzwerk. Bei zwangsgerichteten Netzwerken werden die Knoten und Kanten so angeordnet, dass es nur minimale Knotenüberschneidungen und Kantenüberschneidungen gibt. Kraftgerichtete Layouts sind eine gute Darstellung der Netzwerke, da sie allgemeine Muster wie Knotencluster, Knoten mit hohem Grad, verbundene Komponenten usw. aufdecken, aber sie können hierarchische Informationen nicht auf einfache Weise darstellen.
Es gibt mehrere ausgezeichnete Bibliotheken wie D3, um die Positionsinformationen der Netzwerk-Layouts zu berechnen.
In diesem Beitrag konzentrieren wir uns insbesondere auf die hierarchische Darstellung der Daten. D3 bietet von Haus aus ein hierarchisches Layout, um die Positionen der Knoten auf hierarchische Weise zu berechnen. Das hierarchische Layout arbeitet jedoch mit Daten, die in einem baumartigen Format vorliegen (implizite Eltern-Kind-Struktur), mit der Einschränkung, dass ein Knoten nicht mehr als einen Elternteil haben darf. Daher können wir d3-hierarchy nicht verwenden, um baumartige Layouts zur Darstellung hierarchischer Informationen zu erstellen, wenn die Datenstruktur wie ein Graph aussieht.
Wir können dieses Problem lösen, indem wir das zwangsgerichtete D3-Layout nutzen, um nicht überlappende Knoten zu erreichen, und zusätzliche Beschränkungen für geometrische Knotenpositionen setzen, um ein hierarchisches Layout zu erreichen. Es kann rein in D3 erreicht werden, aber es ist ein bisschen mühsam, Einschränkungen in einfachen JavaScript zu schreiben.
Es gibt einen einfacheren Weg - WebCola.
WebCola bietet uns eine Möglichkeit, die Layout-Informationen in Form von geometrischen Einschränkungen zu spezifizieren. Darüber hinaus generiert es dynamisch Beschränkungen für das Flusslayout, nicht überlappende Knoten usw., um das Netzwerkdiagramm zu entrümpeln. Ich mag WebCola, weil es einfach und flexibel zu benutzen ist.
Beginnen wir mit einem einfachen d3 force layout Netzwerk mit den folgenden Daten. Wie Sie sehen können, gibt es keine inhärente Eltern-Kind-Struktur in diesen Daten. Um die Knoten hierarchisch anzuordnen, führen wir daher für jeden Knoten eine Ebeneneigenschaft ein, die die Position eines Knotens in einer Hierarchie angibt.
Wir werden ein vanilla force gerichtetes Layout für die folgenden Daten mit D3 force layout library anzeigen.
const nodes = [
{ id: 1, level: 1 }, { id: 2, level: 2 },
{ id: 3, level: 2 }, { id: 4, level: 2 },
{ id: 5, level: 3 }, { id: 6, level: 3 },
{ id: 7, level: 3 }, { id: 8, level: 3 },
{ id: 9, level: 3 }, { id: 10, level: 3 },
{ id: 10, level: 3 }, { id: 11, level: 4 },
{ id: 12, level: 4 }, { id: 13, level: 4 },
{ id: 14, level: 4 }, { id: 15, level: 4 },
{ id: 16, level: 4 }
];
const links = [
{ start: 1, end: 2 },
{ start: 1, end: 3 },
{ start: 1, end: 4 },
{ start: 2, end: 5 },
{ start: 2, end: 6 },
{ start: 3, end: 7 },
{ start: 3, end: 8 },
{ start: 3, end: 9 },
{ start: 4, end: 5 },
{ start: 4, end: 9 },
{ start: 4, end: 10 },
{ source: 5, target: 11 },
{ source: 5, target: 12 },
{ source: 7, target: 13 },
{ source: 8, target: 14 },
{ source: 10, target: 15 },
{ source: 10, target: 16 },
{ source: 9, target: 16 },
];
Aus Gründen der Übersichtlichkeit werden in der obigen Visualisierung die Knoten mit den gleichen level Attribut mit der gleichen Farbe, und wir stimmen den Radius des Knotens auf der Grundlage des level d.h. je höher der level Wert, desto kleiner der Radius.
Wie Sie im Diagramm sehen können, generiert das kraftgesteuerte Layout nur die Beschränkung für die nicht überlappenden Knoten mit Hilfe verschiedener Kräfte. Es gibt jedoch keine einfache Möglichkeit in D3, die Daten hierarchisch auf der Grundlage der exogenen Eigenschaft des Knotens anzuordnen.
Wir können WebCola nutzen, um die geometrischen Beschränkungen hinzuzufügen, um Knoten auf verschiedenen Ebenen auf der Grundlage ihrer Ebeneneigenschaft auszurichten.
WebCola-Zwänge
In WebCola gibt es verschiedene Kategorien von Beschränkungen, wie z. B. Ausrichtungs-, Gruppierungs- und Gleichheitsbeschränkungen usw. Wir werden die Ausrichtungsbeschränkungen und Ungleichheitsbeschränkungen verwenden, um die Knoten auf derselben Ebene entlang der y-Achse auszurichten. Diese können wie folgt in JSON angegeben werden:
{
"type": "alignment",
"axis": "y",
"offsets": [
{ "node": 1, "offset": 0 },
{ "node": 2, "offset": 0 },
{ "node": 3, "offset": 0 }
]
}
Die angegebene Bedingung würde die Knoten mit den Indizes 1, 2 und 3 entlang der y-Achse, d.h. horizontal, ausrichten. offset bezeichnet die Verschiebung des Knotenpunkts, die typischerweise bei Knoten mit variabler Größe verwendet wird.
Lassen Sie uns nun versuchen, unser Netzwerk als Baum anzuordnen. Wir benötigen zwei Arten von Beschränkungen wie folgt:
- Ausrichtungsbeschränkung - Wir wollen, dass die Knoten mit der gleichen Ebene Eigenschaft haben die gleiche
ykoordinieren - Gleichheitsbeschränkung - Die Knoten auf derselben Ebene sollten zur besseren Lesbarkeit links und rechts einen Rand haben.
In unserem Beispiel gruppieren wir die Knoten nach dem Attribut Ebene und geben für jeden Knoten in derselben Gruppe eine Ausrichtungsbeschränkung entlang der y-Achse an. Außerdem weisen wir in jeder Gruppe eine Positionsgleichheitsbeschränkung entlang der x-Achse mit einem Abstand von 50 Pixeln zu; dies hilft uns, die Knoten auf derselben Ebene zu entrümpeln. Der Lückenwert kann dynamisch auf der Grundlage der Größe des Knotens abgeleitet werden, aber das ist eine rendering-spezifische Entscheidung.
const constraints = [];
const { nodes, links } = loadData();
const groups = _.groupBy(nodes, "level");
for (const level of Object.keys(groups)) {
const nodeGroup = groups[level];
const constraint = {
type: "alignment",
axis: "y",
offsets: [],
};
let prevNodeId = -1;
for (const node of nodeGroup) {
constraint.offsets.push({
node: _.findIndex(nodes, (d) => d.id === node.id),
offset: 0,
});
if (prevNodeId !== -1) {
constraints.push({
axis: "x",
left: _.findIndex(nodes, (d) => d.id === prevNodeId),
right: _.findIndex(nodes, (d) => d.id === node.id),
gap: 50,
});
}
prevNodeId = node.id;
}
constraints.push(constraint);
}
d3Cola
.nodes(nodes)
.links(links)
.constraints(constraints)
.flowLayout("y", 80)
.linkDistance(50)
.symmetricDiffLinkLengths(40)
.avoidOverlaps(true)
.on("tick", ticked)
.start(10, 40, 50);
Die auf dem Level-Attribut des Knotens basierenden Constraints sind benutzerdefinierte Constraints. Zusätzlich zu diesen benutzerdefinierten Beschränkungen generiert WebCola dynamisch Beschränkungen zur Bestimmung der Länge der Verbindungen (linkDistance, flowLayout), nicht überlappende Beschränkungen (avoidOverlaps) usw.
Wir führen die Simulation durch, in der wir dynamisch generierte Beschränkungen für 10 Iterationen, benutzerdefinierte Beschränkungen für 40 Iterationen und beide Sätze von Beschränkungen zusammen für 50 Iterationen anwenden. Diese Zahlen können heuristisch variiert werden, je nach Anzahl der Knoten und Beschränkungen in der Simulation.
Mit diesen Einschränkungen erhalten wir ein baumähnliches Layout, indem wir die zwangsgerichtete Simulation verwenden, obwohl wir keine baumähnliche Datenstruktur haben. Sie können sehen, dass die Knoten mit dem gleichen Levelwert die gleiche Farbe haben und sich auf der gleichen Höhe befinden. Außerdem ist unsere Visualisierung stabil gegenüber mehreren Knoten mit mehreren Eltern.
Dies ist nur ein kleiner Einblick, wie WebCola verwendet werden kann, um verschiedene Layouts auf das Netzwerkdiagramm in ein paar Zeilen Code anzuwenden. Ich empfehle Ihnen, sich SetCola anzusehen, eine Hochsprache zur Erstellung von WebCola-Beschränkungen, mit der Sie mit wenigen Codezeilen komplexe Graphenlayouts erstellen können.
[content_block id=53166]
