Main Loop I
for (let vtx of left.neighbors) { leftCount[vtx.id]++; }
for (let vtx of right.neighbors) { rightCount[vtx.id]++; }
for (let vtx of vertices) {
if (!placed[vtx.id]) {
left = vtx;
right = vtx;
break;
}}
Apply matrix(1, 1, -1, 1, 5, 2)
Greedy Layout
Knuth Layout
Tidy Layout
Drawing general graphs
Draw a graph with the following adjacency lists
1: 6, 4, 7
2: 8, 5, 3
3: 6, 2, 4
4: 5, 3, 1
5: 4, 2, 7
6: 1, 3, 8
7: 5, 8, 1
8: 2, 6, 7
What might we want in a graph layout?
From Fruchterman and Reingold (1991):
Which graphs can be drawn without any edge crossings?
There are efficient algorithms for
Implementing one would make an awesome final project!
What about non-planar graphs? (Most graphs are not planar!)
Question. Can we efficiently draw graphs so as to minimize the number of edge crossings?
Answer. No!
More precisely. The following problem is NP-complete
Focus on heuristics
Framework from graph/DFS demos
Graph
object stores lists of vertices/edgesVertex
object stores adjacency list (neighbors
), has x
, y
Edge
object represents a pair of verticesGraphVisualizer
moderates interactions between site and Graph
instance
Previously:
Added:
lec15-graph-drawing.zip
Added event listener to each vertex element
elt.addEventListener("mouseover", (e) => {
this.muteAll();
this.unmuteVertex(vtx);
this.highlightVertex(vtx);
for (let nbr of vtx.neighbors) {
this.highlightVertex(nbr);
this.highlightEdge(this.graph.getEdge(vtx, nbr));
}
});
elt.addEventListener("mouseout", (e) => {
this.unmuteAll();
this.unhighlightAll();
});
Setup: Graph with $n$ vertices. How to set locations on a circle?
this.setLayoutCircle = function (cx, cy, r) {
let vertices = this.graph.vertices;
let n = vertices.length;
for (let i = 0; i < n; i++) {
vertices[i].x = r * Math.cos(2 * Math.PI * i / n) + cx;
vertices[i].y = r * Math.sin(2 * Math.PI * i / n) + cy;
}}
Now that we can draw vertices evenly around a circle, we can focus on the order in which to add vertices
Basic idea:
left
and right
setsleft
neighbors placed on left
side
right
sideleft
/right
setsleft
or right
:
right
neighbors) - (left
neighbors) for each vertexright
left
left
vertices on left side, right
on right side1: 2, 6, 3, 5
2: 1, 3, 5, 6
3: 1, 2, 6
4: 2, 5
5: 1, 2, 4
6: 1, 3
left
/right
setsleft
or right
:
right
neighbors) - (left
neighbors) for each vertexright
left
left
vertices on left side, right
on right side const vertices = this.graph.vertices;
const n = vertices.length;
const leftPlaced = [];
const rightPlaced = [];
const placed = new Array(n).fill(false);
const leftCount = new Array(n).fill(0);
const rightCount = new Array(n).fill(0);
let placedCount = 2;
vertices.sort((u, v) => {
return u.degree() - v.degree();
});
// two highest degree vertices go on left and right sides
let left = vertices[n-1];
leftPlaced.push(left);
placed[left.id] = true;
let right = vertices[n-2];
rightPlaced.push(right);
placed[right.id] = true;
for (let vtx of left.neighbors) { leftCount[vtx.id]++; }
for (let vtx of right.neighbors) { rightCount[vtx.id]++; }
for (let vtx of vertices) {
if (!placed[vtx.id]) {
left = vtx;
right = vtx;
break;
}}
// set right and left to be the vertices maximizing and
// minimizing (respectively) the quantity rightCount -
// leftCount
for (let vtx of vertices) {
if (/* most right - left nbrs */) {
right = vtx;
}
if (/* least right - left nbrs */) {
left = vtx;
}}
Assume graph has $n$ vertices, $m$
Adjacent Vertex Smallest Degree First
Idea:
1: 2, 6, 3, 5
2: 1, 3, 5, 6
3: 1, 2, 6
4: 2, 5
5: 1, 2, 4
6: 1, 3
const order = [];
const stack = [];
const vertices = this.graph.vertices;
const n = vertices.length;
const placed = new Array(n).fill(false);
vertices.sort((u, v) => {
return u.degree() - v.degree();
});
stack.push(vertices[0]);
while (stack.length > 0) {
let vtx = stack.pop();
if (!placed[vtx.id]) {
order.push(vtx);
placed[vtx.id] = true;
vtx.neighbors.sort((u, v) => {
return v.degree() - u.degree();
});
for (let nbr of vtx.neighbors) {
if (!placed[nbr.id]) { stack.push(nbr); }
}}}
Force-directed layout