*Authored by Steven Hall*

This week I have been busy exploring the generation of fractals using D3. The image above is a "fractal fern" composed of 150,000 tiny SVG circles generated using some surprisingly simple JavaScript. Fractals are everywhere in the nature world and can be stunningly beautiful, but they are also useful for efficiently generating complex graphics in games and mapping applications. In my own work I like to cast a wide net and checkout new data visualization tools and techniques - you never know when it may come in handy. Some knowledge of fractals is definitely a good thing to have in your toolbox.

There are three parts to this post. The first part will be light introduction to fractals in general with a few links that I found useful. Next, I put together three examples that explore generating fractal ferns using JavaScript and provide some insight into how a simple algorithm repeated many times can produce such a stunning final result.

The last part deals with scaling an SVG to fit the browser window which often comes up in doing responsive design work with D3 visualizations. The solution presented here can really be applied to any data visualization project. If you look closely at the examples, they are being generated to an SVG element that is initially 2px high by 2px wide, yet scale to a large size in the browser window without the need to re-generate the graphic using code as the window size changes.

## Code Examples in this Post

You can look at each of examples by clicking on the links and viewing the code in the browser or you can download the code for all three examples in one shot from this github repository.

### Example 1

This example generates a basic fractal fern with 30,000 points. The resulting image is not as detailed as the one in example 3 but it generates quickly in the browser. The code is identical for the two examples except for the number of iterations.

**You can view the example here.**

### Example 2

This example generates the fractal fern one point at a time, so you can see it gradually build the image. It also colors the individual points according to which set of coefficients it belongs to. The coloring helps understand how the fractal emerges from the different sets of coefficients in the code which are chosen with a given probability.

**You can view the example here.**

### Example 3

This example generates a "higher resolution" version of the fractal fern. It has 150,000 individual points. It takes a moment to appear in the browser, but you can more clearly see the self-similar, recursive pattern as each individual leaf is revealed to be a miniature replica of the whole.

**You can view the example here.**

## What are Fractals?

Fractal geometry describes how how visual complexity can be created from simple rules. It's a relatively recent invention largely because it depends on the ability to carry out a large number of iterations on a set of simple rules - something that is ideally suited for computers. The word fractal was coined by the creator of fractal geometry, Benoit Mandelbrot, in 1975 to describe the fractured looking forms that are often seen in the nature world in everything from plants to mountain ranges.

If you are interested in a good non-technical introduction to fractals, this 2008 Nova documentary on YouTube is a good place to start. Highly recommended.

Fractals are mathematical entities that display self-similar patterns - they can be examined at many levels of magnification and look identical (or at least similar) because of their repeating, recursive nature. Here we are looking at fractal ferns and this video does an excellent job of showing how this type of fractal, given a sufficient number of points, can be zoomed into infinitely (theoretically) and will continue to repeat the same pattern. Fractal ferns, also known as Barnsley Ferns, are just one of many well documented fractals out there that can be produced in a similar iterative fashion. Julia sets are one of the other types of fractals I considered using for this first post on fractals.

## Fractal Fern with D3.JS

Coding the fractal fern turned out to be surprisingly easy. The three examples all depend on the same basic code and then make a few small modifications to achieve the desired results. It may help to take a quick look at the ferns.js file that contains the key functions before stepping through the code. In all three examples the ferns.js file is loaded and then a few lines of JavaScript code are added inside a script tag in the HTML. Those lines are the only things changing from example to example.

The key for generating the fractal fern is the getCoords function and a helper function, random, for generating random numbers between an upper and lower bound:

// I REMOVED WHITE SPACE HERE TO KEEP THE CODE FROM WRAPPING

// SEE THE FERN.JS FILE FROM THE EXAMPLES

function getCoords(x, y) {

var p = random(1,1000);

return p <=701 ? {c: 0, x: 0.81*x+0.07*y+0.12, y: -0.04*x+0.84*y+0.195}:

p <=851 ? {c: 1, x: 0.18*x-0.25*y+0.12, y: 0.27*x+0.23*y+0.02}:

p <=980 ? {c: 2, x: 0.19*x+0.275*y+0.16, y: 0.238*x-0.14*y+0.12}:

{c: 3, x: 0.0235*x+0.087*y+0.11, y: 0.045*x+0.1666*y};

}

function random(min, max) {

return min + Math.floor(Math.random() * (max - min + 1));

}

The basic idea is that we want to generate each successive point based on the coordinates of the point that comes before it. In the getCoords function the coordinates (x, y) of the current (or base) point are passed in the and the coordinates for the new point are returned. The only trick is that we have four sets of different coefficients that we want to be applied with a certain probability. We want to the first set 70.1% of the time, the second set 15%, the third set 12.9%, and the fourth set just 2% of the time. Random parameter p takes care of selecting the correct set of coefficients. If you really want to understand the coefficients at a deeper level you can read the wikipedia page on Barnsley Ferns. There is also some discussion of how to tweak the coefficients to achieve different types of ferns.

You'll notice that the object that is returned from the getCoords function has three properties: c, x, and y. For now you can ignore the c property. It is just flagging which set of coefficients was selected to do the coloring of the points in the second example. It is not needed to construct the basic fractal fern with a single color.

Two other functions also probably need some explanation:

VIZ.addPoint = function (colors) {

var xy = getCoords(basePoint.x, basePoint.y); //A

basePoint = xy; // B

if (colors) { // C

renderPoint({c: xy.c, x: xy.x + width / 5, y: xy.y + height / 10}, 1);

} else {

renderPoint({c: xy.c, x: xy.x + width / 5, y: xy.y + height / 10}, 0);

}

}

function renderPoint(data, flag) {

svg.append("circle")

.attr("class", "fractalPoint")

.style("fill", flag ? colors[0]: colors[data.c])

.style("opacity", .6)

.attr("cx", data.x)

.attr("cy", data.y)

.attr("r", .002)

}

In all the examples the addPoint function is called repeatedly to create the points. The function calls out to the getCoords function using the current base point's coordinates (A) and then resets the base point to the new point's coordinates (B) for the next iteration. The "colors" flag (C) is really only needed for these examples, so it can be ignored if you just want to generate the basic fractal. The final step is to call renderPoint using the coordinates received from the getCoords function. You'll notice that I am applying one last tweak based on the height and width to the point's X and Y values to get the visualization positioned correctly within the SVG.

The renderPoint function is using d3.js in a somewhat unorthodox way. Outside of these examples you probably would want to generate the entire dataset and send it to d3 in one shot to be rendered. Better yet, if you wanted to simply display a fractal fern on a page it would make sense to generate the data and save it to a file rather than generate the data on the fly. In my case I wanted to be able to show a bit more of how the process works so I am just using D3 to append each point (circle) as it is created to a "g" element in the main SVG. This allows me to use the same basic code across all three examples.

## Resizing the SVG

The points that get returned by the getCoords function are very tightly bounded. Plotting the raw coordinates into pixels fits the entire image with a 2px by 2px SVG element. Translating those coordinates to the appropriate size in pixels for the page could be done using d3's scales to translate from one coordinate to system to another, but I decided to do this in another way since using scales has been pretty well covered out there. As an added benefit, this method also allows the visualization to be "responsive" as well - scaling up and down based on the size of the browser window.

The key to make the graphic resize according to the window size is adding the "viewBox" attribute to the SVG. You can see how this is done in the ferns.js file here...

var svg = d3.select("#svg-container")

.append("svg")

.attr("id", "thesvg")

.attr("width", width)

.attr("height", height)

.attr("viewBox", "0 0 " + width + " " + height)

.append("g");

The viewBox attribute allows you designate that a group of elements will stretch to fit a container element. You can get the full low down from the W3C here. The circles are appended to a "g" element and when the browser resizes it will apply a transformation automatically to keep the visualization scaled correctly to fit the container element (the SVG in this case).

So the only thing we need to do is use some JQuery to resize the parent SVG both when the page loads initially and anytime the browser is resized. You'll see in all the HTML files a call to the onResize function:

// In the script tag in the HTML files

VIZ.onResize(); // Call when page loads to fit to window

$(window).on("resize", function() {

VIZ.onResize() // Call when browser window changes size

});

// The onResize function from ferns.js

VIZ.onResize = function () {

var aspect = height / width, chart = $("#thesvg");

var targetWidth = chart.parent().width();

chart.attr("width", targetWidth);

chart.attr("height", targetWidth / aspect);

}

Pretty cool trick. And you can use this on any chart or map that is rendered in SVG.