score:6

Since you have a data array with the `x` and `y` positions ("I have the x,y pairs for the source and target points"), you'll have to convert them to `angle` and `radius`. Let's see how to do it.

Firstly, let's see an example with fixed coordinates. For instance, suppose you have this data array, with the `x` and `y` positions:

``````var data = [{
source: {y: 150,x: 75
},
target: {y: 300,x: 0
}
}, {
source: {y: 150,x: 75
},
target: {y: 0,x: 0
}
}, {
source: {y: 150,x: 75
},
target: {y: 150,x: 150
}
}, ];
``````

``````var link = d3.linkHorizontal()
.x(function(d) {
return d.y;
})
.y(function(d) {
return d.x;
});
``````

... you'll have a chart like this:

``````var data = [{
source: {
y: 150,
x: 75
},
target: {
y: 300,
x: 0
}
}, {
source: {
y: 150,
x: 75
},
target: {
y: 0,
x: 0
}
}, {
source: {
y: 150,
x: 75
},
target: {
y: 150,
x: 150
}
}, ];

var svg = d3.select("svg");

.x(function(d) {
return d.y;
})
.y(function(d) {
return d.x;
});

svg.selectAll(null)
.data(data)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", "blue")
``````<script src="https://d3js.org/d3.v4.js"></script>
<svg></svg>``````

How can we convert this to a data set that can be used with `d3.linkRadial()`?

One option is iterating with each object, using basic trigonometry to populate the `angle` and `radius` properties:

``````var radialData = data.map(function(d) {
return {
source: {
x: 0,
y: 0
},
target: {
x: Math.atan2(d.target.y - d.source.y, d.target.x - d.source.x) - Math.PI,
y: Math.sqrt((d.target.x - d.source.x) * (d.target.x - d.source.x) + (d.target.y - d.source.y) * (d.target.y - d.source.y))
}
};
});
``````

``````var linkRadial = d3.linkRadial()
.angle(function(d) {
console.log(d)
return d.x;
})
return d.y;
});
``````

We'll have this:

``````var data = [{
source: {
y: 150,
x: 75
},
target: {
y: 300,
x: 0
}
}, {
source: {
y: 150,
x: 75
},
target: {
y: 0,
x: 0
}
}, {
source: {
y: 150,
x: 75
},
target: {
y: 150,
x: 150
}
}, ];

var svg = d3.select("svg");

return {
source: {
x: 0,
y: 0
},
target: {
x: Math.atan2(d.target.y - d.source.y, d.target.x - d.source.x) - Math.PI,
y: Math.sqrt((d.target.x - d.source.x) * (d.target.x - d.source.x) + (d.target.y - d.source.y) * (d.target.y - d.source.y))
}
};
});

var g = svg.append("g")
.attr("transform", "translate(150,75)")

.angle(function(d) {
return d.x;
})
return d.y;
});

g.selectAll(null)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", "red")
``````<script src="https://d3js.org/d3.v4.js"></script>
<svg></svg>``````

Now both generators together, for comparison:

``````var data = [{
source: {
y: 150,
x: 75
},
target: {
y: 300,
x: 0
}
}, {
source: {
y: 150,
x: 75
},
target: {
y: 0,
x: 0
}
}, {
source: {
y: 150,
x: 75
},
target: {
y: 150,
x: 150
}
}, ];

var svg = d3.select("svg");

.x(function(d) {
return d.y;
})
.y(function(d) {
return d.x;
});

svg.selectAll(null)
.data(data)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", "blue")

return {
source: {
x: 0,
y: 0
},
target: {
x: Math.atan2(d.target.y - d.source.y, d.target.x - d.source.x) - Math.PI,
y: Math.sqrt((d.target.x - d.source.x) * (d.target.x - d.source.x) + (d.target.y - d.source.y) * (d.target.y - d.source.y))
}
};
});

var g = svg.append("g")
.attr("transform", "translate(150,75)")

.angle(function(d) {
return d.x;
})
return d.y;
});

g.selectAll(null)
``````<script src="https://d3js.org/d3.v4.js"></script>