# Graphing Calculator, Part 1

Welcome! I am teaching myself d3.js and have decided to create a rudimentary graphing calculator as a proof of concept. I'm detailing the learning process as I go so there will be pitfalls and backtracks — in other words, this is more of a whiteboard demo than a tutorial.

I am not starting from scratch — I went through Scott Murray's excellent d3 tutorial to familiarize myself with d3, and will build on that. This demo assumes familiarity with the concepts covered in his tutorial, so if you haven't gone through that yet, please do. I'll wait here.

## Setting Up the Basics

Let's get started by setting up an SVG element.

```
var svg = d3.select('body').append('svg:svg'),
w = 500, h = 250;
svg.attr('width', w).attr('height', h);
```

This is just a blank canvas. Let's put some axes and scales on [1]:

```
var padding = 20,
xMax = 100,
yMax = 10,
xScale = d3.scale.linear()
.domain([0, xMax])
.range([padding, w - padding]),
yScale = d3.scale.linear()
.domain([0, yMax])
.range([h - padding, padding]);
xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom'),
yAxis = d3.svg.axis()
.scale(yScale)
.orient('left');
svg.append('svg:g')
.attr('class', "axis")
.attr('transform', "translate(0," + (h - 20) + ")")
.call(xAxis);
svg.append('svg:g')
.attr('class', "axis")
.attr('transform', "translate(20,0)")
.call(yAxis);
```

and style them:

```
<style type="text/css">
svg .axis path, svg .axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
svg .axis text {
font-family: sans-serif;
font-size: 11px;
text-anchor: middle;
}
</style>
```

(Note that the minimums and maximums for the axes are hardcoded. This will change shortly when we start to enter data.)

## Adding a Function

Scott's final example displays random points which change each time you load the page. I want to adapt that to display
the points along the curve of a mathematical function. I'm going to use `Math.sqrt` since it's easy to display and
fits nicely with the domains I hardcoded for the axes.

```
var plotfunc = Math.sqrt,
plotdata = [];
var lowX = 0, highX = 100, dX = 1;
for (var i=lowX; i<highX; i+= dX) {
plotdata.push([i, plotfunc(i)]);
}
// check that points were entered correctly
for (var i=0; i<plotdata.length; i+=10) {
console.log("(" + plotdata[i][0] + ", " + plotdata[i][1] + ")");
}
// console output:
(0, 0)
(10, 3.1622776601683795)
(20, 4.47213595499958)
(30, 5.477225575051661)
(40, 6.324555320336759)
(50, 7.0710678118654755)
(60, 7.745966692414834)
(70, 8.366600265340756)
(80, 8.94427190999916)
(90, 9.486832980505138)
```

Looks like our data are valid. Now let's display them. Since I just finished Scott's scatterplot tutorial [2], I have the code left to display circles at x/y coordinates, so I will just adapt that for now.

```
svg.selectAll('circle')
.data(plotdata)
.enter()
.append('svg:circle')
.attr('cx', function(d, i) { return xScale(d[0]); })
.attr('cy', function(d, i) { return yScale(d[1]); })
.attr('r', 2);
```

Very nice!

## Dys-function

Let's try it with a different function to see how extensible it is:

```
var plotfunc = Math.exp,
...
```

Oops! What's happening here? Let's try a function which doesn't grow quite as quickly.

```
var plotfunc = function(x) { return x; },
...
```

Aha, I see what's happening. Looks like my hardcoded domains of 0-100 for x and 0-10 for y aren't sufficient for a function whose y-value gets greater than 10. Fortunately, changing the maximums on the domains is easy.

```
...
xMax = d3.max(plotdata, function(d) { return d[0]; }),
yMax = d3.max(plotdata, function(d) { return d[1]; }),
...
```

There it is. I am going to change the function back to `sqrt` for the remainder of this exercise — the dynamic
maximums for my x and y domains should still work fine.

## Getting In Line

The last thing I want to do today is change the way the function is plotted from a series of points to a series of lines. This seems pretty straightforward but as you will see there are some snags.

Whereas the SVG `circle` element requires three plot attributes (`cx`, `cy`, and `r`), the `line` element
takes four: `x1`, `y1`, `x2`, `y2`. This makes sense: it's a simple line segment which is defined by two (x, y)
endpoints, just like in freshman geometry.

Let's use item `n` in `plotdata` as point 1 and item `n + 1` as point 2. This will obviously cause problems when
item `n` is the final item in `plotdata`, so let's simply exclude that item from our `data()` call:

```
// Replace svg.selectAll('circle') and its chain with:
svg.selectAll('line')
.data(plotdata.slice(0, plotdata.length - 1))
.enter()
.append('svg:line')
.attr("x1", function(d, i) { return xScale(d[0]); })
.attr("y1", function(d, i) { return yScale(d[1]); })
.attr("x2", function(d, i) { return xScale(plotdata[i+1][0]); })
.attr("y2", function(d, i) { return yScale(plotdata[i+1][1]); });
.style('stroke', "rgb(6, 120, 155)")
.style('fill', "rgb(6, 120, 155)");
```

Note that I also added `stroke` and `fill` styles to liven up the plot a bit. I could also have done this in the
CSS block, which is arguably more correct because it generates less SVG code.

Huh? What happened here? I do indeed have a line now, but only the points with x > 20 are being plotted. But the only thing I changed was the plot elements, from circles to lines. What is going on?

It turns out that the problem is with `svg.selectAll('line')`. d3's `selectAll()` uses CSS-style selectors to select
everything inside the parent element which matches the pattern, similar to jQuery. However, there are already `line`
elements inside the `svg` element. They are the ticks for the axes — 10 each. (The axes themselves are `path`
elements so are not selected.)

Thus, when d3 performs `svg.selectAll('line')` and gets a preĆ«xisting set of 20 line segments, its `enter()`
method excludes those and only begins appending elements which it considers to be new. [3]

The solution is simple, like most riddles when you see the answer. Since we don't expect the initial selector to return
anything more than the empty set anyway, change it to something guaranteed not to exist inside the `<svg>` element.

```
svg.selectAll('#line_not_in_axis_tick')
.data(plotdata.slice(0, plotdata.length - 1))
...
```

And there it is! Our prettily-plotted square root curve.

## Wrapping Up

The full code for this demo can be found here. There is
plenty yet to do — for example, SVG provides a `path` element which is better suited to drawing
continuous line segments than `line` is.
I also need to work with making the domain and range even more dynamic. Look for part 2 coming soon!

### Footnotes

[1] | Refreshers from Scott's tutorial on axes and scales. |

[2] | Scatterplot tutorial is at http://alignedleft.com/tutorials/d3/making-a-scatterplot/. |

[3] | selectAll() and enter() really confused me when I started working with d3. I didn't get deconfused until
I read Mike Bostock's Thinking With Joins. |