I have a scatter plot in which I need to fit a line to the plot. I load the data with an ajax call as JSON.
I just can't seem to get the line to show. When I inspect elements I can see the path but nothing shows.
Here is a JSFiddle with the problem:
I've commented the ajax part out and hard coded the data I get back.
JSFiddle with missing line
And I am guessing the problem is somewhere around line 299-318 here:
linegroup = main.append('g')
.attr('transform', 'translate(0,0)')
.attr('class', 'main myline');
var line = d3.svg.line()
.x(function (d) {
return d.x;
})
.y(function (d) {
return d.y;
});
linegroup.selectAll("path")
.data([data.line])
.enter()
.append("path")
.attr("d", line)
.attr("fill", "none")
.attr("stroke", "#000")
.attr("stroke-width", 5);
What am I doing wrong?
I managed to figure it out, sorry to bother you.
The problem was I had forgot to add the scales to the line so it ended up way below the page ended.
var line = d3.svg.line()
.x(function (d) { return x(d.x); })
.y(function(d) { return y(d.y); });
Related
This is my code :
legend = svg.append("g")
.data(json.links)
.attr("class","legend")
.attr("transform","translate(50,30)")
.attr("data-legend", function(d){ return d.relation; })
.style("fill", function (d) { return color(d.group); })
.call(d3.legend);
It's work but only one relation appears in the lengend.
Can you help me ?
Thanks a lot !
I'm visualising voyages on a map with D3.js' path. My data is in a JSON file like the following format:
[{"begin_date":1519,"trips":[[-13.821772,14.294839],[-9.517688,-7.958521],[0.598434,-34.704567],[18.374673,-86.850335]]},
{"begin_date":1549,"trips":[[12.821772,-16.294839],[5.517688,-20.958521],[13.598434,-54.704567],[18.374673,-86.850335]]},
{"begin_date":1549,"trips":[[12.821772,-16.294839],[5.517688,-20.958521],[13.598434,-54.704567],[18.374673,-86.850335]]}]
As can be seen, sometimes there are multiple voyages for a year. The following recursive function works:
d3.json("data/output.json", function(error, trips) {
if (error) throw error
var nest = d3.nest()
.key(function(d){
return d.begin_date;
})
.entries(trips)
var trip = svg.selectAll(".voyage");
// Add the year label; the value is set on transition.
var label = svg.append("text")
.attr("class", "year label")
.attr("text-anchor", "end")
.attr("y", height - 400)
.attr("x", width+150)
.text(function(d) {return d});
var pnt = 0;
doTransition();
function doTransition() {
trip.data(nest[pnt].values).enter()
.append("path")
.attr("class", "voyage")
.style("stroke", colorTrips)
.attr('d', function(d) {label.text(d.begin_date); return lineGen(d.trips.map(reversed).map(projection))})
.call(function transition(path) {
path.transition()
.duration(500)
.attrTween("stroke-dasharray", tweenDash)
.each("end", function(d) {
d3.selectAll(".voyage")
.remove()
pnt++;
if (pnt >= nest.length){return;}
doTransition();
})
})
}
Some voyages plot as they should
However some of them, are never plotted (I can see in the log) and it jumps from year 1545-1569 despite there being data points in between. I suspect it is due to the recursive function calling itself before the transition is finished. But I am also not sure, in the slightest.
Hope it is sufficient, I am new to D3.js, and suddenly found myself out of depth.
I am trying to create a line graph using d3.js, which takes a csv input and converts it to a data array with the keys x1, x2, class. Using that data I create a perceptron decision boundary using weights and the gradient function which updates and transitions after each iteration.
This works nicely.
What I am struggling with is the area under the curve, as I want positive values to be blue and negative to be red. The areas move with the line correctly, but something is wrong with the x values as the width of the area doesn't cover the whole graph. It covers about half, and starts about a quarter of the way in (I can't post an image.)
Here is the code I'm using for all of these elements, but I thin I am misunderstanding the way area uses the x attribute;
lineFunction = d3.svg.line()
.x(function(d) { return widthScale(d.x1); })
.y(function(d) { return heightScale(((-d.x1 * w1) - w0)/w2); })
.interpolate("linear");
var area = d3.svg.area()
.x(function(d) { return widthScale(d.x1); })
.y0(xPos)
.y1(function(d) { return heightScale(((-d.x1 * w1) - w0)/w2); })
.interpolate("linear");
var area2 = d3.svg.area()
.x(function(d) { return widthScale(d.x1); })
.y0(heightAlter)
.y1(function(d) { return heightScale(((-d.x1 * w1) - w0)/w2); })
.interpolate("linear");
lineGraph = canvas.append("path")
.attr("d", lineFunction(lineData))
.attr("class", "autoLine")
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("fill", "none")
.attr("clip-path", "url(#clip)");
shadedArea = canvas.append("path")
.data([data])
.attr("d", area)
.attr("class", "area")
.attr("clip-path", "url(#clip)");
shadedAreaPos = canvas.append("path")
.data([data])
.attr("d", area2)
.attr("class", "area2")
.attr("clip-path", "url(#clip)");
Any help would be much appreciated.
I managed to find that the root of the problem was the way in which the data array was ordered. I do not fully understand what is happening behind the scenes, but by simply reordering the array in ascending order on the x1 values, it now works correctly. I hope this helps someone.
I have put together a D3 line chart and added threshold encoding using clip path / clipping. The only problem I am facing is I am not able to add tooltips to this chart. I want a tooltip when I hover anywhere in the chart and the corresponding y axis value on the chart shows up in the tooltip.
I have added threshold encoding using this example by Mike Bostock.
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return _config.xScale(d.vtc); })
.y(function(d) { return _config.yScale(d.values); });
svg.append("clipPath")
.attr("id", "clip-above")
.append("rect")
.attr("width", _config.width)
.attr("height", _config.yScale(55));
svg.append("clipPath")
.attr("id", "clip-below")
.append("rect")
.attr("y", _config.yScale(55))
.attr("width", _config.width)
.attr("height", _config.height - _config.yScale(55));
svg.selectAll(".line")
.data(["above", "below"])
.enter().append("path")
.attr("class", function(d) { return "line " + d; })
.attr("clip-path", function(d) { return "url(#clip-" + d + ")"; })
.datum(data)
.attr("d", line);
I didn't know how to go about adding a tooltip for this particular chart as there is clip rectangle over the path and the path is broken down into above and below segment to give the colour effects.
Do we have a unified way to add a tooltip to normal path and this one? If yes I would like to know some sources/links I can look at.
Something like this, but not that complicated (without any indicator on the line, just the tooltip)
My CODEPEN LINK
You can add mouseOver handler for the line and translate back the mouse y position to yAxis value using the .invert function of d3 linear scale. Now, you can dynamically add a tooltip text element and set the position, value to it
Here is the updated Codepen link
NOTE: You still need to increase the capture area of the line. This can be done by adding a transparent stroke to the line.
svg.selectAll(".line")
.data(["above", "below"])
.enter().append("path")
.attr("class", function(d) { return "line " + d; })
.attr("clip-path", function(d) { return "url(#clip-" + d + ")"; })
.datum(data)
.attr("d", line)
.on("mouseover", function() {
var mousePos = d3.mouse(this);
var yAxisValue = _config.yScale.invert(mousePos[1]);
svg.selectAll(".tooltip").data([mousePos])
.enter().append("text")
.classed("tooltip", true)
.attr("x", function(d) { return d[0]})
.attr("y", function(d) { return d[1]})
.text(yAxisValue);
})
.on("mouseout", function() {
svg.selectAll(".tooltip").data([]).exit().remove();
});
I have built a multi series line chart using the D3 library. I have been trying to work on animating the line chart so I can give out one line at a time and not all 5 of them together. Can anybody give me some ideas as to how I can go about with this? I have tried using transition() but I seem to be using it wrong. This is what I have done so far -
var city = svg.selectAll(".city")
.data(years)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line");`
d3.transition().selectAll(".line")
.duration(500)
.ease("linear")
.attr("d", function(d){return line(d.values); })
.style("stroke", function(d) {return color(d.name); })
.attrTween("d",pathTween);
function pathTween() {
var interpolate = d3.scale.quantile()
.domain([0,1])
.range(d3.range(1,years.length+1));
return function(t){
return line(data.slice(0,interpolate(t)));
};
D3 transitions have a .delay() method that allows you to set a delay before each transition starts. In your case (having each line start separately) it would look like this:
d3.transition().selectAll(".line")
.duration(500)
.delay(function(d, i) { return i * 500; })
.ease("linear")
.attr("d", function(d){return line(d.values); })
.style("stroke", function(d) {return color(d.name); });
This takes the index of each line (i) and offsets the start of the transition depending on that.