# Chapter 05Radial Lines

D3.js defines a radial line as a line about an origin where each point p on the line is characterized by the distance from p to the origin (a radius) and the angle at the origin subtended by the arc between the positive y-axis and p.

D3.js provides d3.lineRadial(), a radial line generator, much like `d3.line`, that can be used to produce a path descriptor for SVG `path` element and for rendering a path in a `canvas` element.

By default, the line generator expects a dataset consisting of an array of arrays, where each inner array is an angle and radius pair. For each angle/radius pair, t, in the dataset, a point is generated such that the angle at the origin subtended by the arc between the positive y-axis and the point is given by t[0] and the distance from the origin to the point is given by t[1].

In Figure 1 we render a radial line using the following dataset.

```var data = [
[0, 10],
[Math.PI * .25, 20],
[Math.PI * .5, 35],
[Math.PI * .75, 55],
[Math.PI, 60],
[Math.PI * 1.25, 65],
[Math.PI * 1.5, 70],
[Math.PI * 1.75, 75],
[Math.PI * 2, 80]];
```

After creating a radial line generator we append a `path` element to the `g` element in the `svg` and set its `d` attribute to the path description created by the radial line generator.

``` var lineRadial = d3.lineRadial();

d3.select("#demo1")
.select("g")
.append("path")
.attr("fill", "none")
.attr("stroke", "black");
```
```<script>
var data = [
[0, 10],
[Math.PI * .25, 20],
[Math.PI * .5, 35],
[Math.PI * .75, 55],
[Math.PI, 60],
[Math.PI * 1.25, 65],
[Math.PI * 1.5, 70],
[Math.PI * 1.75, 75],
[Math.PI * 2, 80]];

d3.select("#demo1")
.select("g")
.append("path")
.attr("fill", "none")
.attr("stroke", "black");

</script>

<svg id="demo1" width="200" height="200">
<g transform="translate(100,100)"></g>
</svg>```

Note that the origin is at (0,0) in the element in which the line is drawn. In order to position the radial line in the middle of the screen, we add a `g` element to our `svg`, translate it into the middle, then draw the line inside the `g` element.

## Accessor Methods

The radial line generator has two methods that can be called to assign custom angle and radius accessor methods to the radial line generator.

• lineRadial.angle([angle]) - sets or gets the angle accessor. If angle is provided, it must be a number or a function that returns a number representing an angle in radians. If angle is not provide, returns the current angle accessor function.

• lineRadial.radius([radius]) - sets or gets the radius accessor. If radius is provided, it must be a number or a function that returns a number. If radius is not provide, returns the current radius accessor function.

When `lineRadial.angle` and `lineRadial.radius` are passed functions (or lambda expressions), the functions are called for each element in the dataset and when called, are passed the current data element d, the index of the current element i, and the array of data on which the generator is invoked, data.

When `lineRadial.angle` and `lineRadial.radius` are called without an argument, the methods return the radial line generator’s current accessor.

In Figure 2 the dataset consists of an array of objects, each having an `angle` and `radius` property. To use these properties when computing the x and y positions for the points, we provide the radial line generator with custom angle and radius accessor methods.

```var data = [
{angle: 0, radius: 10},
{angle: Math.PI * .25, radius: 20},
{angle: Math.PI * .5, radius: 35},
{angle: Math.PI * .75, radius: 55},
{angle: Math.PI, radius: 60},
{angle: Math.PI * 1.25, radius: 65},
{angle: Math.PI * 1.5, radius: 70},
{angle: Math.PI * 1.75, radius: 75},
{angle: Math.PI * 2, radius: 80}];

.angle((d) => d.angle)
```
```<script>
var data = [
{angle: 0, radius: 10},
{angle: Math.PI * .25, radius: 20},
{angle: Math.PI * .5, radius: 35},
{angle: Math.PI * .75, radius: 55},
{angle: Math.PI, radius: 60},
{angle: Math.PI * 1.25, radius: 65},
{angle: Math.PI * 1.5, radius: 70},
{angle: Math.PI * 1.75, radius: 75},
{angle: Math.PI * 2, radius: 80}];

.angle((d) => d.angle)

d3.select("#demo2")
.select("g")
.append("path")
.attr("fill", "none")
.attr("stroke", "black");
</script>

<svg id="demo2" width="200" height="200">
<g transform="translate(100,100)"></g>
</svg>```

## Using Bound Data

We can also compute the `d` attribute of a `path` element, not by invoking the radial line generator directly, but rather, by joining the data to the `path` element and then passing the radial line generator as the second argument of `selection.attr` when setting the `d` attribute.

```d3.select("#demo3")
.select("g")
.append("path")
.data([data])
.attr("fill", "none")
.attr("stroke", "black");
```

Note that the dataset is passed to `selection.data` inside an array and the `lineRadial` function, not the string returned by `lineRadial`, is passed to `selection.attr`.

```<script>
var data = [
{angle: 0, radius: 10},
{angle: Math.PI * .25, radius: 20},
{angle: Math.PI * .5, radius: 35},
{angle: Math.PI * .75, radius: 55},
{angle: Math.PI, radius: 60},
{angle: Math.PI * 1.25, radius: 65},
{angle: Math.PI * 1.5, radius: 70},
{angle: Math.PI * 1.75, radius: 75},
{angle: Math.PI * 2, radius: 80}];

.angle((d) => d.angle)

d3.select("#demo3")
.select("g")
.append("path")
.data([data])
.attr("fill", "none")
.attr("stroke", "black");
</script>

<svg id="demo3" width="200" height="200">
<g transform="translate(100,100)"></g>
</svg>```

## Excluding Points

Sometimes we may want to exclude certain points on the line. To do this we can set the defined accessor function by calling lineRadial.defined([defined]) on our line generator.

When the radial line generator computes points, it invokes the defined accessor for each element in the dataset, passing it the current data element `d`, the index of the current element `i`, and the array of data on which the generator is invoked, `data`. If the defined accessor evaluates to true, a point is generated for the data element, otherwise the element is ignored. By default, the defined accessor returns true for all elements in the dataset.

In Figure 4 we exclude the points that have angles between 0 and PI by passing a lambda expression to `line.defined`.

```<script>
var data = [
{angle: 0, radius: 10},
{angle: Math.PI * .25, radius: 20},
{angle: Math.PI * .5, radius: 35},
{angle: Math.PI * .75, radius: 55},
{angle: Math.PI, radius: 60},
{angle: Math.PI * 1.25, radius: 65},
{angle: Math.PI * 1.5, radius: 70},
{angle: Math.PI * 1.75, radius: 75},
{angle: Math.PI * 2, radius: 80}];

.angle((d) => d.angle)
.defined((d) => d.angle >= Math.PI);

d3.select("#demo4")
.select("g")
.append("path")
.attr("fill", "none")
.attr("stroke", "black");
</script>

<svg id="demo4" width="200" height="200">
<g transform="translate(100,100)"></g>
</svg>```

## Curving the Line

To create a curve we need to change the way that the points are interpolated. For this we can call lineRadial.curve([curve]) passing it a predefined curve factory. D3.js provides several curve factories which we discuss in the section on curves.

If `lineRadial.curve` is called without an argument, the current curve factory is returned, which by default is the d3.curveLinear curve factory.

Figure 5 sets the line generator’s curve factory to `d3.curveBasis` producing a cubic basis spline.

```var lineRadial = d3.lineRadial()
.angle((d) => d.angle)
.curve(d3.curveBasis);
```
```<script>
var data = [
{angle: 0, radius: 10},
{angle: Math.PI * .25, radius: 20},
{angle: Math.PI * .5, radius: 35},
{angle: Math.PI * .75, radius: 55},
{angle: Math.PI, radius: 60},
{angle: Math.PI * 1.25, radius: 65},
{angle: Math.PI * 1.5, radius: 70},
{angle: Math.PI * 1.75, radius: 75},
{angle: Math.PI * 2, radius: 80}];

.angle((d) => d.angle)
.curve(d3.curveBasis);

d3.select("#demo5")
.select("g")
.append("path")
.attr("fill", "none")
.attr("stroke", "black");
</script>

<svg id="demo5" width="200" height="200">
<g transform="translate(100,100)"></g>
</svg>```

## Rendering Lines to a Context

We can render the line in a `canvas` element’s `context` by using lineRadial.context([context]).

If no argument is passed to `lineRadial.context`, the method returns the current context, which by default is null. If, however, a context is passed to `lineRadial.context`, the line will be rendered in the context when the line generator is invoked.

In Figure 6, we retrieve the context of the canvas element, then create the line generator and call `line.context` to set the context.

```var context = d3.select("#demo6").node().getContext("2d");

.angle((d) => d.angle)
.context(context);
```

We then render the line by invoking the line generator, setting the stroke color, and calling `context.stroke`.

```context.translate(100,100);
context.stroke();
```
```<script>
var data = [
{angle: 0, radius: 10},
{angle: Math.PI * .25, radius: 20},
{angle: Math.PI * .5, radius: 35},
{angle: Math.PI * .75, radius: 55},
{angle: Math.PI, radius: 60},
{angle: Math.PI * 1.25, radius: 65},
{angle: Math.PI * 1.5, radius: 70},
{angle: Math.PI * 1.75, radius: 75},
{angle: Math.PI * 2, radius: 80}];

var context = d3.select("#demo6").node().getContext("2d");