├── .gitignore ├── README.md ├── components ├── default │ ├── action.js │ ├── inline.js │ ├── fixed.js │ ├── slide.js │ ├── svg.js │ ├── aside.js │ ├── float.js │ ├── button.js │ ├── panel.js │ ├── waypoint.js │ ├── full-screen.js │ ├── link.js │ ├── text-input.js │ ├── preload.js │ ├── code-highlight.js │ ├── boolean.js │ ├── range.js │ ├── header.js │ ├── display.js │ ├── analytics.js │ ├── select.js │ ├── slideshow.js │ ├── radio.js │ ├── dynamic.js │ ├── table.js │ ├── index.js │ ├── chart.js │ ├── utils │ │ ├── container.js │ │ └── screen.js │ ├── gist.js │ ├── equation.js │ └── feature.js ├── probe.js ├── vega-plot.js ├── theta.js ├── barnes-hut.js ├── data-network.js ├── time-plot.js ├── error-plot.js ├── data-performance.js └── quadtree.js ├── package.json ├── styles.css ├── index.idl └── docs ├── index.html └── styles.css /.gitignore: -------------------------------------------------------------------------------- 1 | .idyll 2 | .DS_Store 3 | build/ 4 | node_modules 5 | npm-debug.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Interactive explanation of the Barnes-Hut approximation. 2 | 3 | [View online at https://jheer.github.io/barnes-hut/](https://jheer.github.io/barnes-hut/). 4 | 5 | Created with [Idyll](http://idyll-lang.org/), [D3](https://d3js.org/), 6 | and [Vega](https://vega.github.io/vega/). 7 | -------------------------------------------------------------------------------- /components/default/action.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | class Action extends React.PureComponent { 4 | render() { 5 | return ( 6 | {this.props.children} 7 | ); 8 | } 9 | } 10 | 11 | export default Action; 12 | -------------------------------------------------------------------------------- /components/default/inline.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | class Inline extends React.PureComponent { 4 | render() { 5 | return ( 6 |
Computers can serve as exciting tools for discovery, with which we can 18 | model and explore complex phenomena. For example, to test theories about 19 | the formation of the universe, we can perform simulations to predict 20 | how galaxies evolve. To do this, we could gather the estimated mass and 21 | location of stars and then model their gravitational interactions over time.
Another avenue for discovery is to visualize complex information to 22 | reveal structure and patterns. Consider this network diagram, showing 23 | connections between people in a social network. We can use such diagrams 24 | to examine community groups and identify people who bridge between them.
Though they may seem quite different at first, these two examples share 25 | a common need: they require computing forces that arise from pairwise 26 | interactions among a set of points, often referred to as an N-body problem. 27 | In the case of astronomical simulation, we seek to model the 28 | gravitational forces among stars. In the case of network visualization, 29 | we compute the layout using a similar physical simulation: 30 | nodes in the network act as charged particles that repel each other, while 31 | links act as springs that pull related nodes together.
To get a sense of how this force-directed layout works, drag the nodes or 32 | use the slider to adjust the force strength. Negative values indicate 33 | repulsive forces, while positive values indicate attractive forces.
Force Strength -30.00
A straightforward approach to computing N-body forces is to consider all 34 | pairs of individual points and add up the contributions of each 35 | interaction. This naïve scheme has quadratic complexity: as the number 36 | of points n increases, the running time grows proportionally 37 | to n2, quickly leading to intractably long calculations. 38 | How might we do better?
To accelerate computation and make large-scale simulations possible, the 39 | astronomers Josh Barnes and Piet Hut devised a clever scheme. 40 | The key idea is to approximate long-range 41 | forces by replacing a group of distant points with their center 42 | of mass. In exchange for a small amount of error, 43 | this scheme significantly speeds up calculation, with 44 | complexity n log n rather than n2.
Central to this approximation is a spatial index: a “map” of space 45 | that helps us model groups of points as a single center of mass. In 46 | two dimensions, we can use a quadtree 47 | data structure, which recursively 48 | subdivides square regions of space into four equal-sized quadrants. (In three dimensions, one can use an analogous octree that divides a cubic volume into eight sub-cubes.)
The Barnes-Hut approximation involves three steps:
49 | Let’s explore each step in turn. We will assume we are computing repulsive 50 | forces for the purposes of network layout. This setup is akin to modeling 51 | anti-gravity or electric forces with similarly-charged particles. While we 52 | will use the term “center of mass”, this could readily 53 | be replaced with “center of charge”.
As you read through, click the action links to update the diagram!We begin with a set of 54 | two-dimensional points as input. 55 | When we insert the first point into 56 | the quadtree, it is added to the top-level root cell of the tree.
Next we insert another point, 57 | which requires expanding the tree by subdiving the space. 58 | Upon each subsequent 59 | insertion, more fine-grained cells may be added until all points 60 | reside in their own cell.
Advance the slider to add each point and produce the full quadtree.
Inserted Points 0
After quadtree construction, we calculate centers of mass for each cell of the tree. 61 | The center of mass of a quadtree cell is simply the weighted 62 | average of the centers of its four child cells.
We visit the leaf node cells first and then visit subsequent parent 63 | cells, merging data as we pass upwards through the tree. 64 | Once the traversal completes, each cell has been updated with the 65 | position and strength of its center of mass.
Now we are ready to estimate forces!
To measure forces at a given 66 | point, let's add a "probe" to our diagram (). The purple 67 | line extending from the probe indicates the direction and magnitude of 68 | the total force at that location. (To promote visibility, 69 | the purple line is three times longer than the actual 70 | pixel distance the probe would be moved in a single timestep of 71 | the force simulation.) The dotted lines extending to the probe 72 | represent the force components exerted by individual points.
Move the probe (click or 73 | drag in the visualization) to explore the force field.
Ignoring the quadtree, we can naïvely calculate forces by summing the 74 | contributions of all individual points. Of course, we would instead like 75 | to use the quadtree to accelerate calculation and approximate long-range 76 | forces. Rather than compute interactions among individual 77 | points, we can compute interactions 78 | with centers of mass, using smaller quadtree cells for nearer points and 79 | larger cells for more distant points.
At this point we’ve skipped a critical detail: what constitutes 80 | “long-range” versus “short-range” forces? We consider both 81 | the distance to the center of a quadtree cell and that cell’s width. 82 | If the ratio width / distance falls below a chosen threshold 83 | (a parameter named theta), we treat the quadtree cell as a 84 | source of long-range forces and use its center of mass. 85 | Otherwise, we will recursively visit the child cells in the quadtree.
When theta = 1, a quadtree cell’s center of mass will be used — and its 86 | internal points ignored — if the distance from the sample point to the 87 | cell’s center is greater than or equal to the cell’s width.
Adjust the theta parameter to view its effect on force estimation. How does 88 | the number of considered points change based on the probe location and theta? 89 | How does the direction and magnitude of the total force vary with theta?
Theta 0.00
We can now perform force estimation for each individual point, using the 90 | Barnes-Hut approximation to limit the total number of comparisons!
To assess the performance of the Barnes-Hut approximation, let’s look at 91 | both the running time and accuracy of force estimation. We will compare 92 | naïve (n2) calculation to different settings of the theta 93 | parameter.
We will take measurements using different point sets, 94 | ranging from 500 to 10,000 points. For each point count, 95 | we average the results from 50 separate runs of force estimation, 96 | each time using a different set of points placed at uniformly 97 | random coordinates within a 900 x 500 pixel rectangle.
The running time results confirm that the Barnes-Hut 98 | approximation can significantly speed-up computation. 99 | As expected, the naïve approach 100 | exhibits a quadratic relationship, whereas increasing the theta parameter 101 | leads to faster calculations. A low setting of theta=0.5 102 | does not fare better than the naïve 103 | approach until processing about 6,000 points. Until that point, 104 | the overhead of quadtree construction and center of mass 105 | calculation outstrips any gains in force 106 | estimation. For theta=1 and theta=1.5, 107 | however, we see a 108 | significant improvement in running time, with similar 109 | performance for each.
To evaluate approximation error, we measure the average vector 110 | distance between the results of the naïve scheme and Barnes-Hut. 111 | In the context of a force-directed graph layout, this error 112 | represents the difference (in pixels) between node positions after 113 | applying the naïve and approximate methods.
Looking at the error results, we first see that the average 114 | error is relatively small: only ~5% of a single pixel in 115 | difference! However, we should take care in interpreting these 116 | results, as we use the average error per point and 117 | the maximum error may be substantially higher. While theta=1 and theta=1.5 exhibit similar running times, 118 | here we see notably higher error rates for theta=1.5 119 | versus theta=1 and theta=0.5.
These results suggest that a good default value for theta 120 | — with low running time and low approximation error 121 | — is around 1.0. Indeed, in practice it is common to see default 122 | settings slightly below 1. In 123 | visualization applications, where errors on the order of a few 124 | pixels are not a problem, even higher theta values may be used 125 | without issue.
The Barnes-Hut approximation has had a major impact on both physical 126 | simulation and network visualization, enabling n-body calculations 127 | to scale to much larger data sets than naïve force calculation permits.
Returning to our initial 128 | network diagram, we can use Barnes-Hut to efficiently compute 129 | repulsive forces at each timestep. For each animation frame, we perform the 130 | approximation anew, creating a new quadtree, accumulating centers of mass, 131 | and (approximately) estimating forces.
Want to learn more or apply Barnes-Hut in your own work?
132 | This article was created using Idyll, with 133 | visualizations powered by D3 134 | and Vega. 135 | The source code is available on GitHub.