Updating D3 data doesn't remove old data from faux-3d example - javascript

I am working on extending the example found here. I have a data source that will pull in data for different periods of time. The data is as expected and draws well individually. I added a timer to iterate through the result set. The following code is in the original example. There are three calls points, flyers, arcLines (only flyers is shown below)
svg.append("g").attr("class","flyers")
.selectAll("path").data(links)
.enter().append("path")
.attr("class","flyer")
.attr("d", function(d) { return swoosh(flying_arc(d)) })
I changed the code to this to allow updates and they kind of work. The lines/points/flyers are removed and only the data from the time interval are displayed.
var flyer_data = svg_flyers
.selectAll("path").data(links);
flyer_data
.exit().remove();
flyer_data
.enter().append("path")
.attr("class", "flyer")
.attr("d", function(d) {
return swoosh(flying_arc(d))
});
Now the data isn't displayed correctly when the points and lines are supposedly in focus. Only data that is right on the horizon is displayed before its clipped. There is another side effect of the above code. The bound data structure is changed correctly but the SVG gets more and more points/lines/arcs which are not displayed. This last observation is particular baffling with the ever growing SVG definitions. It slows down the browser after a few minutes.
I have created a gist with enough code to demonstrate the issue. The Gist can be found here.

Your link to gist isn't working.
However, depending on your situation you can select your object (in this case your path) by class or id. In the example I've provided you can give your path an id and refer to it.
var lineData = [ { "x": 1, "y": 5}, { "x": 20, "y": 20},
{ "x": 40, "y": 10}, { "x": 60, "y": 40},
{ "x": 80, "y": 5}, { "x": 100, "y": 60}];
var lineData2 = [ { "x": 5, "y": 1}, { "x": 20, "y": 20},
{ "x": 10, "y": 40}, { "x": 40, "y": 60},
{ "x": 5, "y": 80}, { "x": 60, "y": 100}];
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
d3.select("svg")
.append("path")
.attr("id", "MyUniqueId")
.attr("d", lineFunction(lineData));
d3.select("#MyUniqueId")
.transition()
.duration(5000)
.attr("d", lineFunction(lineData2));
See js fiddle:
http://jsfiddle.net/3M54q/3/

Related

Plotting nodes and links from JSON files with SVG

I'm new to D3 and I'm having trouble visualising my json file. I'm supposed to plot the locations (sites) as circles with their radius equal to the "amount". I'm extremely confused about how to work with the nodes and links. I have provided an example of the JSON code as well. Please help me understand where I am going wrong with the coding
<html>
<head>
<title>D3 Visualisation </title>
<h1> Trading Data </h1>
<style>
.svgCanvas {
border: solid 1px
}
</style>
</head>
<body>
<svg></svg>
<script src="https://d3js.org/d3.v4.min.js"></script> <script>
window.onload = function(){
var width = 800;
var height = 300;
var thisCanvas = d3.select("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "svgCanvas");
d3.json("data.json", function(d){
console.log(d);
var svgCanvas.selectAll("circle")
.data(d).enter()
.append("circle")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return d.amount; } )
.style("fill", “lightgreen”); })
})
}
</script>
</body>
</html>
The Json code example is as follows:
{
"nodes": [
{
"id": "site09",
"x": 317.5,
"y": 282.5
},
{
"id": "site01",
"x": 112,
"y": 47
},
{
"id": "site03",
"x": 69.5,
"y": 287
}
],
"links": [
{"node01": "site05", "node02": "site08", "amount": 10},
{"node01": "site05", "node02": "site02", "amount": 120},
{"node01": "site05", "node02": "site03", "amount": 50}
]
}
Here you can get the working solution. Just replace the data object with json.
https://playcode.io/324480?tabs=console&script.js&output

Creating line chart with d3 getting error

In the following example I am using a lineFunction for plotting co-ordinates for the path. I hope to enter code correctly, still facing error. Can someone help?
SNIPPET:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>
<script>
$(document).ready(function(){
//our basic data
var customData = [
{"x": 100, "y": 100},
{"x": 200, "y": 50},
{"x": 300, "y": 150},
{"x": 400, "y": 20}
];
//the line function for path
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
//Main svg container
var mySVG = d3.select("svg");
//defining the lines
var path = mySVG.append("path");
//plotting lines
path
.attr("d", lineFunction(customData))
.attr("stroke",function() { return "hsl(" + Math.random() * 360 + ",100%,50%)"; })
.attr("stroke-width", 2)
.attr("fill", "none");
});
</script>
</head>
<body>
<svg width="500px" height="500px"></svg>
</body>
</html>
ERROR:
var lineFunction = d3.svg.line() //error here ...
Looks like versioning issue for me take look at this -
$(document).ready(function(){
//our basic data
var customData = [
{"x": 100, "y": 100},
{"x": 200, "y": 50},
{"x": 300, "y": 150},
{"x": 400, "y": 20}
];
//the line function for path
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
//Main svg container
var mySVG = d3.select("svg");
//defining the lines
var path = mySVG.append("path");
//plotting lines
path
.attr("d", lineFunction(customData))
.attr("stroke",function() { return "hsl(" + Math.random() * 360 + ",100%,50%)"; })
.attr("stroke-width", 2)
.attr("fill", "none");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="//d3js.org/d3.v3.min.js"></script></script>
<svg width="500px" height="500px"></svg>
As Chetan already mentioned, it's a version problem of your included D3 file. You are including D3 V4 but using the syntax of D3 V3.
Within V4 they removed d3.svg. So everything you have to do is to change d3.svg.line() to d3.line() and it should work.
Ref: d3.svg.line() error: Uncaught TypeError: Cannot read property 'line' of undefined
EDIT-1: try this code Snippet
var svg;
//The data for our line
var lineData = [ { "x": 1, "y": 5}, { "x": 20, "y": 20},
{ "x": 40, "y": 10}, { "x": 60, "y": 40},
{ "x": 80, "y": 5}, { "x": 100, "y": 60}];
//This is the accessor function we talked about above
var lineFunction = d3.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; });
//The SVG Container
var svgContainer = d3.select("body").append("svg:svg")
.attr("width", 200)
.attr("height", 200);
//The line SVG Path we draw
var lineGraph = svgContainer.append("path")
.attr("d", lineFunction(lineData))
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "none");

D3.js svg.diagonal issue

I have this little issue : I'm not able to draw a curved line with json data.
Here's go my code
var diagonal = d3.svg.diagonal();
groupe.selectAll("path")
.data([data])
.enter()
.append("path")
.attr("d",diagonal
.source({x:250, y:500})
.target({x:400, y:300}))
.attr("fill", "none")
.attr("stroke", "#000")
.attr("stroke-width","2");
Here I put some data, but when i try with
.source({'x':function(d) {return d.x},'y':function(d) {return d.x})
I habve an error in the console and I'm not able to draw the lines
Do you know where is my error ?
My data looks like this
var data = [
{"x":250,"y":500,"width": 100, "height": 100, "nx":400, "ny":300, "class":"brief", "name": "Prise de Brief"},
{"x":400,"y":300,"width": 150, "height": 150, "nx":600, "ny":450, "class":"conception", "name": "Conception"},
{"x":600,"y":450,"width": 150, "height": 150, "nx":900, "ny":500, "xI":600,"yI":450,"wI": 50, "hI": 50, "xlink": "img/hexagone_plein.svg", "class":"crea", "name": "Création graphique", "id": "crea"},
{"x":900,"y":500,"width": 150, "height": 150, "nx":1150, "ny":350, "class":"dev", "name": "Développements techniques"},
{"x":1150,"y":350,"width": 100, "height": 100, "nx":1300, "ny":500, "class":"recette", "name": "Recette"},
{"x":1300,"y":500,"width": 100, "height": 100, "nx":1500, "ny":650, "class":"mel", "name": "Mise en ligne"},
{"x":1500,"y":650,"width": 100, "height": 100, "nx":1500, "ny":650, "class":"garantie", "name": "Garantie"}
];
I think you have the syntax wrong for source functions, as well as the data already being an array, maybe this will work?
var diagonal = d3.svg.diagonal();
groupe.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("d",diagonal
.source(function(d){ return {"x":d.x, "y":d.y};})
.target({x:400, y:300}))
.attr("fill", "none")
.attr("stroke", "#000")
.attr("stroke-width","2");

Accessing JSON values in D3

I'm trying to populate each group with a circle for "Forehand" / "Backhand" and "BH slice" but i'm having difficulties accessing these values. I have nested the elements in a way that the "Direction" is the Key so the related values will eventually influence the position and the size of each circle.
In a way it is similar to https://github.com/mbostock/d3/wiki/Selections#data the matrix example I guess but the data structure is different ?
JSbin of the current code here: http://jsbin.com/gahul/1
I have the following data:
var JSONdata = [
{
"Direction": "Crosscourt",
"Total": 118,
"Forehand": 75,
"Backhand": 41,
"BH slice": 2
}, {
"Direction": "Down_middle",
"Total": 50,
"Forehand": 34,
"Backhand": 9,
"BH slice": 7
}, {
"Direction": "Down_line",
"Total": 21,
"Forehand": 8,
"Backhand": 11,
"BH slice": 2
}, {
"Direction": "Inside_out",
"Total": 118,
"Forehand": 25,
"Backhand": 5,
"BH slice": 0
}, {
"Direction": "Inside_in",
"Total": 9,
"Forehand": 9,
"Backhand": 0,
"BH slice": 0
},
];
And the following d3 code:
var query1 = d3.nest()
.key(function(d){
return d.Direction;
})
.sortKeys(d3.ascending)
.entries(JSONdata)
var h = 420;
var w = 500;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var group = svg.selectAll("g")
.data(query1)
.enter()
.append("g")
.attr("class", function(d){ return d.key })
var pop_directions = group.selectAll("circle")
.data(query1)
.enter()
.append("circle")
.attr("r", 30 )
.attr("cx", 100)
the values of your new object are in an array with one element, which you have to adress, for instance:
d.values[0].Forehand
gives you the forehand-value, while you can access your key-value by
d.key
see http://jsbin.com/hakamoga/1/edit for a simple example using the forehand-value as radius and title.

Refactoring d3js: multiple arcs & text blocks into tidy js functions

I am building a simple animated nav element with use of d3 (for practice).
However my code is horribly verbose because I am creating the same arc (with a few exceptions) 3 times and hard coding each one. As a beginner I am struggling to clean this up with javascript. Working verbose code here: http://tributary.io/inlet/7919286
In order to do so I created JSON object to represent the characteristics unique to each arc.
var data = {
"arcs": [
{
"id": 1,
"innerRadius": 100,
"outerRadius": 150,
"x": 45,
"dy": 45,
"text": "About"
},
{
"id": 2,
"innerRadius": 160,
"outerRadius": 210,
"x": 45,
"dy": -15,
"text": "Github"
},
{
"id": 3,
"innerRadius": 220,
"outerRadius": 270,
"x": 45,
"dy": -75,
"text": "Contact"
}
]
}
I have tried unsuccessfully to call data with here: http://tributary.io/inlet/8408617 , but it's broken and I need help. Thank you.
The idea is to, instead of appending elements explicitly, use the .selectAll(...).data(...).enter().append(...) pattern to do that. That means that you need to replace all the code where you're currently explicitly appending elements with this. For the paths, that would look like this:
canvas.selectAll("path.arc").data(data.arcs)
.enter().append("path")
.attr("class", "arc")
.attr("id", function(d, i) { return "path" + (i+1); });
The rest is a bit tedious, but not too difficult -- simply repeat for everything else. The result is here.

Categories