Reputation: 4845
Suppose I have an array of values with corresponding dates, [{date: d1, value: v1}, ..., {date: dn, value: vn}]
, that I'd like to visualize using d3.js. As long as subsequent measurements are within a certain time range, for example not more than a week apart, I am happy with d3 interpolating between the measurements.
However, when subsequent records are farther apart, I don't want d3 to connect them. What would be the easiest way to achieve this?
Upvotes: 3
Views: 856
Reputation: 102188
Your question is not exactly clear: by "interpolate", I believe you mean "connecting the dots".
If you use a time scale for your x axis, D3 will automatically connect the dots for you and create a line (an SVG path
element), regardless the time separation in the data points. But there is a way for making "gaps" in that line: using line.defined()
. According to the API:
If defined is specified, sets the defined accessor to the specified function or boolean and returns this line generator.
The problem is, for this approach to work, you'll have to set a given value (let's say, null
) in your dataset, between the dates in which you don't want to draw the line (that is, the dates that are not close enough, as you say in your question). You can do this manually or using a function.
This is a working demo: in my dataset, my data jumps from 7-Oct to 17-Oct (more than 1 week). So, I just created a null
value in any date between these two (in my demo, 16-Oct). Then, in the line generator, the line jumps this null
value, using defined
:
d3.line().defined(function(d){return d.value != null;})
The result is that the line jumps from 7-Oct to 17-Oct:
var data = [{date: "1-Oct-16",value: 14},
{date: "2-Oct-16",value: 33},
{date: "3-Oct-16",value: 12},
{date: "4-Oct-16",value: 43},
{date: "5-Oct-16",value: 54},
{date: "6-Oct-16",value: 71},
{date: "7-Oct-16",value: 32},
{date: "16-Oct-16",value: null},
{date: "17-Oct-16",value: 54},
{date: "18-Oct-16",value: 14},
{date: "19-Oct-16",value: 34},
{date: "20-Oct-16",value: 32},
{date: "21-Oct-16",value: 56},
{date: "22-Oct-16",value: 24},
{date: "23-Oct-16",value: 42},
{date: "24-Oct-16",value: 52},
{date: "25-Oct-16",value: 66},
{date: "26-Oct-16",value: 34},
{date: "27-Oct-16",value: 62},
{date: "28-Oct-16",value: 48},
{date: "29-Oct-16",value: 51},
{date: "30-Oct-16",value: 42}];
var parseDate = d3.timeParse("%d-%b-%y");
data.forEach(function (d) {
d.date = parseDate(d.date);
});
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 200);
var xScale = d3.scaleTime().range([20, 480]);
var yScale = d3.scaleLinear().range([180, 10]);
xScale.domain(d3.extent(data, function (d) {
return d.date;
}));
yScale.domain([0, d3.max(data, function (d) {
return d.value;
})]);
var xAxis = d3.axisBottom(xScale).tickFormat(d3.timeFormat("%d"));
var yAxis = d3.axisLeft(yScale);
var baseline = d3.line()
.defined(function(d){return d.value != null;})
.x(function (d) {
return xScale(d.date);
})
.y(function (d) {
return yScale(d.value);
});
svg.append("path") // Add the valueline path.
.attr("d", baseline(data))
.attr("fill", "none")
.attr("stroke", "teal");
svg.append("g")
.attr("transform", "translate(0,180)")
.call(xAxis);
svg.append("g")
.attr("transform", "translate(20,0)")
.attr("class", "y axis")
.call(yAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>
Upvotes: 3
Reputation: 6243
If you're trying to draw a broken line chart, then I don't think interpolation is what you're looking for. Building a custom SVG path is probably the way to go. See an example here:
https://bl.ocks.org/joeldouglass/1a0b2e855d2bedc24c63e396b04c8e36
Upvotes: 0