Im currently trying to wrap my head around connecting points around the map and animating them like - HERE:
http://www.tnoda.com/flightanimation
I want the points to connect using information in my CSV File:
Specifically 'where' field which will tell us is the place a destination or an origin of the flight:
code,city,country,lat,lon,where
ZNZ,ZANZIBAR,TANZANIA,-6.13,39.31,dest
TYO,TOKYO,JAPAN,35.68,139.76,dest
AKL,AUCKLAND,NEW ZEALAND,-36.85,174.78,orgin
BKK,BANGKOK,THAILAND,13.75,100.48,orgin
DEL,DELHI,INDIA,29.01,77.38,orgin
SIN,SINGAPORE,SINGAPOR,1.36,103.75,orgin
BSB,BRASILIA,BRAZIL,-15.67,-47.43,orgin
RIO,RIO DE JANEIRO,BRAZIL,-22.90,-43.24,orgin
YTO,TORONTO,CANADA,43.64,-79.40,orgin
IPC,EASTER ISLAND,CHILE,-27.11,-109.36,orgin
SEA,SEATTLE,USA,47.61,-122.33,orgin
(I know i spelled origin wrong its intentionally like that)
Now this is my HTML Code:
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.min.js"></script>
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<style>
path {
stroke: limegreen;
stroke-width: 0.25px;
fill: black;
margin: 0 auto;
}
body {
background-color:darkgrey;
margin: 0 auto;
}
.packet {
max-height: height: 50px;
max-width: 50px;
fill: limegreen;
}
</style>
<body>
<script type="text/javascript" src="http://gc.kis.v2.scr.kaspersky-labs.com/3F7B1EB8-32BF-7449-968C-CB1318D27635/main.js" charset="UTF-8"></script><link rel="stylesheet" crossorigin="anonymous" href="http://gc.kis.v2.scr.kaspersky-labs.com/53672D8131BC-C869-9447-FB23-8BE1B7F3/abn/main.css"/><script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v0.min.js"></script>
<script>
var width = 960,
height = 500;
var projection = d3.geo.mercator()// Creating our projection for our map
var svg = d3.select("body").append("svg")//Append svg to body
.attr("width", width)
.attr("height", height);
var path = d3.geo.path()//create a path for the projection
.projection(projection);
var g = svg.append("g"); //create an empty space to append
var packet = svg.append("path")
.attr("width","50px")
.attr("d", "M612.074,132.141v-2.38c0-8.849-4.016-19.26-11.229-26.473l-0.818-0.818c0,0-0.818,0-0.818-0.818 c-1.636-1.636-3.198-2.38-4.833-4.016c-0.818,0-0.818-0.818-1.636-0.818c-1.636-0.818-4.016-1.636-5.652-2.38 c-0.818,0-0.818-0.818-1.636-0.818c-2.38-0.818-4.833-1.636-7.213-1.636c-0.818,0-0.818,0-1.636,0c-2.38,0-5.651-0.818-8.849-0.818 H43.427c-3.198,0-6.395,0-9.667,0.818c-0.818,0-1.636,0-2.38,0.818c-2.38,0.818-4.834,0.818-6.395,1.636 c-0.818,0-0.818,0.818-1.636,0.818c-1.636,0.818-4.016,1.636-5.652,2.38l-0.818,0.818c-1.636,0.818-3.198,2.38-4.834,3.198 c-0.818,0.818-1.636,1.636-2.38,2.38C4.016,110.428,0.818,117.715,0,125.746c0,0.818,0,0.818,0,1.636v357.384 c0,0.818,0,0.818,0,1.636c1.636,11.229,7.213,20.896,15.244,26.473c7.213,4.833,16.062,8.031,26.473,8.031H569.39c0,0,0,0,0.818,0 l0,0c2.38,0,5.651,0,8.031-0.818c0.818,0,0.818,0,1.636,0c2.38-0.818,4.834-0.818,6.395-1.636h0.818 c17.698-6.395,24.911-21.714,24.911-36.14v-2.38v-0.818v-0.818V134.521c0-0.818,0-0.818,0-1.636 C612.074,132.959,612.074,132.959,612.074,132.141z M560.69,120.913l-252.98,246.51l-57.854-56.218l0,0L51.459,120.838H560.69 V120.913z M29.819,475.099V140.991l187.095,179.882L29.819,475.099z M299.679,491.905H56.292l182.336-149.393l58.597,57.036 c2.38,2.38,4.834,3.198,7.213,4.016h0.818c0.818,0,0.818,0,1.636,0l0,0c0.818,0,1.636,0,1.636,0h0.818 c2.38-0.818,5.651-1.636,7.213-4.016l55.4-53.838l183.079,146.196H299.679z M582.329,475.843L394.417,324.07L582.329,140.99 V475.843z");
var route = svg.append("path");
// load and display the World
d3.json("world-110m2.json", function(error, topology) {//Load in the world map ( LOW RES)
g.selectAll("path")
.data(topojson.object(topology, topology.objects.countries)
.geometries)
.enter()
.append("path")//append path
.attr("d", path)//path is d3.geo.path which is the projection
//Loading the countries inside the world load display function to speed up the loading on local server and faster or client
//Loading the countries here also prevents the dots to be under the map instead on top of it!
d3.csv("countries.csv", function(error, data) {
g.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return projection([d.lon, d.lat])[0];
})
.attr("cy", function(d) {
return projection([d.lon, d.lat])[1];})
.attr("r", 5)
.style("fill", "red");
//Writing out the Cities name
g.selectAll("text")
.attr("class","names")
.data(data)
.enter()
.append("text") // append text
.attr("x", function(d) {
return projection([d.lon, d.lat])[0];
})
.attr("y", function(d) {
return projection([d.lon, d.lat])[1];
})
.attr("dy", -7) // set y position of bottom of text
.style("fill", "limegreen") // fill the text with the colour black
.attr("text-anchor", "middle") // set anchor y justification
.text(function(d) {return d.city;}); // define the text to display
//Test
route.selectAll("path")
.datum({type: "LineString", coordinates:
[
function(d) {
if (d.where === origin){
return projection(d.lat,d.lon)
}},
function(d) {
if (d.where === dest){
return projection(d.lat,d.lon)
}}
]
})
.attr("class", "route")
.attr("d", path);
});
//Animating path
// Map Zooimng
var zoom = d3.behavior.zoom()
.on("zoom",function() {
g.attr("transform","translate("+
d3.event.translate.join(",")+")scale("+d3.event.scale+")");
g.selectAll("path")
.attr("d", path.projection(projection));
});
svg.call(zoom)
});
function transition(packet, route) {
var l = route.node().getTotalLength();
packet.transition()
.duration(5000)
.attrTween("transform", delta(route.node()));
}
function delta(path) {
var l = path.getTotalLength();
return function(i) {
return function(t) {
var p = path.getPointAtLength(t * l);
return "translate(" + p.x + "," + p.y + ")";
}
}
}
transition(packet, route);
</script>
</body>
</html>
Also if anyone can tell me why is my SVG element not resizing that would be great but i'd say i will be able to figure it out.
If someone can explain to me why is the code not working - point out my mistake in my logic and correct me it would be really helpful.
I'm doing this because Data Visualisation has conquered my interest now.
Cheers!
Also hope my comments can be helpful for people that might have had the same problem and are trying to wrap their head around the code!
The following is my code. Yet when I run it I get a blank page. Why is this the case ? Also how can I use data from hundreds of columns to make a simple interactive visual using d3 ? I would like to add that the following csv file "LoanStats3a.csv" is in the same folder.
<html>
<title>Loans</title>
<link href="../css/jquery-ui.css" rel="stylesheet" />
<script src="../Scripts/jquery-1.12.4"></script>
<script src="../Scripts/jquery-1.12.4.js"></script>
<script src="../Scripts/jquery-ui.js"></script>
<script src="http://d3js.org/d3.v3.js" charset="utf-8"></script>
<style>
#LoanStats3a{
color: blueviolet;
}
</style>
<body>
<script>
d3.csv("LoanStats3a", function (file1){
var bg = d3.select("body").append("svg")
.attr("width", 5000)
.attr("height", 5000);
bg.selectAll("rect")
.data(file1)
.enter()
.attr("width", function(d){return d.loan_amnt / 100;})
.attr("height", function(d) {return d.term;})
.attr("y", function (d,i) {return i *50;})
.attr("fill", function (d){"red","blue";});
}
</script>
</body>
This is because after binding the data to your empty selection, you have to append a rect element for each data.
Also, your attribute "fill" is incorrect.
bg.selectAll("rect")
.data(file1)
.enter()
.append("rect") // <= You need to create a rect for each data
.attr("width", function(d){return d.loan_amnt / 100;})
.attr("height", function(d) {return d.term;})
.attr("y", function (d,i) {return i *50;})
.attr("fill", "blue");
If you want to change the color depending on the data, create a function and return something.
// For example
.attr("fill", function(d){return d.loan_amnt > 25000 ? "blue" : "red"});
Here's a JsFiddle with random data : DEMO
EDIT : If it's still not working, it's probably a problem with your data because the only thing different between our code is that I used custom data in the JsFiddle.
I notice that your csv file doesn't have the extension .csv, it's just LoanStats3a ?
You should do a console.log(file1), to check if your data are correct.
Take a look at D3 CSV for how to load a csv file.
You are missing a closing ) at the end:
.attr("fill", function (d){"red","blue";});
}
// ^ Here should be a )
</script>
It helps if you have proper indent:
<script>
d3.csv("LoanStats3a", function(file1) {
var bg = d3.select("body").append("svg")
.attr("width", 5000)
.attr("height", 5000);
bg.selectAll("rect")
.data(file1)
.enter()
.attr("width", function(d) {
return d.loan_amnt / 100;
})
.attr("height", function(d) {
return d.term;
})
.attr("y", function(d, i) {
return i * 50;
})
.attr("fill", function(d) {
"red", "blue"; // What is going on here?
// Did you for to return?
// return "blue";
});
});
</script>
I have the following problem. I created a graph in D3. I added a dropdown menu where the nodes of the graph get resized according to the chosen category. To do that I wrote a function that re-runs the javascript code every time I choose an option in the dropdown menu.
However, the updated graph appears at the end of my website. Is there a way to keep the graph at its original position ?
I tried to put it in a div and fix the position, but that didn't work out. I hope my problem is clear.
Find in the following a toy example of my code.
Cheers!
<html lang="en">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script>
<style type="text/css">
</style>
</head>
<body>
<select onchange="change(this)">
<option value="rad1">Option 1</option>
<option value="rad2">Option 2</option>
</select>
<p> This is some text above the plot </p>
<script type="text/javascript">
change('rad1')
function change(dd) {
update(dd.value)
}
function update(rad) {
var current = rad;
d3.selectAll('svg').remove();
var w = 500;
var h = 300;
var dataset = {
nodes: [
{ name:'Node 1',rad1: 1.31, rad2: 2.32 },
{ name:'Node 2',rad1: 2.12, rad2: 5.00 },
{ name:'Node 3',rad1: 40.30, rad2: 20.40 }
],
edges: [
{ source:0, target:0,rad1: 3.31 },
{ source:0, target:1,rad1: 3.31},
{ source:1, target:2,rad1: 20.31}
]
};
var force = d3.layout.force()
.nodes(dataset.nodes)
.links(dataset.edges)
.size([w, h])
.linkDistance([100])
.charge([-300])
.start();
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var edges = svg.selectAll("line")
.data(dataset.edges)
.enter()
.append("line")
.style("stroke", "#808080")
.style("stroke-width", 1)
.style("stroke-opacity", 0.1);
var nodes = svg.selectAll("circle")
.data(dataset.nodes)
.enter()
.append("circle")
.attr("r", function(d) {
if( current == "rad1") {
return d.rad1;
} else {
return d.rad2;
}
})
.style("fill", function(d, i) {
return '#000000';
})
.call(force.drag)
.on("click", function(d) {
console.log("Name: " + d.name);
});
force.on("tick", function() {
edges.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
nodes.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
}
</script>
<p> Here is more text below the plot </p>
</body>
</html>
The problem is that you are appending the SVG to the body, thus it will always show at the very end of the page. The correct way is creating a div (or anything else) with an ID (which are unique):
<div id="svghere"></div>
And then appending the SVG:
var svg = d3.select("#svghere")
.append("svg")
.//the rest of the code
I am using D3.js to draw some circles inside a div but for some reason no data is displayed in the bottom third of the did even though the specified size of the canvas is equivalent to the size of the of the div.
var data = d3.csv('circles.csv', function(data){
var canvas = d3.select('.cell').append("svg");
canvas.selectAll("circles")
.attr("width", 300)
.attr("height", 250)
.data(data)
.enter()
.append("circle")
.attr("cx", function(d){return (+d.x)})
.attr("cy", function(d){return (+d.y)})
.attr("r", function(d){return (+d.radius)})
.attr("fill", "green");
});
I set a code snippet for what it looks like if no svg size specified. So if ur case is like this, the data point at the bottom may be just go out the SVG viewport area.
var canvas = d3.select('.cell').append("svg")
// if u did not specify size
//.attr("width", 400).attr("height", 400);
canvas.selectAll("circle").data([0])
// .attr("width", 300)
// .attr("height", 250)
// .data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return 150;
})
.attr("cy", function(d) {
return 125;
})
.attr("r", function(d) {
return 125;
})
.style("fill", "green");
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
</head>
<body>
<div class="cell" style="width:500px; height:500px;"></div>
</body>
</html>