load map detail on click using D3.js - javascript

I am trying to build a map from the USA. Once the map is displayed with it's states boundaries I want to display the county boundaries on click
This is how I display the map:
var width = 960,
height = 500,
centered;
var path = d3.geo.path();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.on("click", loadcounties);
var g = svg.append("g")
.attr("id", "states");
d3.json("readme.json", function(json) {
g.selectAll("path")
.data(json.features)
.enter().append("path")
.attr("d", path)
.on("click", loadcounties);
});
And here is the function I use to load the regions (only alabama in here):
function loadcounties (d) {
var id = d3.select(this).attr("name");
var bbox = this.getBBox();
if (id == "Alabama") {
d3.json("alabamacounties.json", function(json) {
g.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path);
});
}
}
When I try to display Alabama on its own it works but as a function it doesn't. Any idea of what I am doing wrong?thanks

This is how I solved it:
function loadstate(d) {
var g = svg.append("g")
.attr("id", "counties");
switch (d.id){
case "01" :
jsoncounty="countiesjson/01.json";
break;
Like this for every state and then:
d3.json(jsoncounty, function(json) {
g.selectAll("path")
.data(json.features, function(d,i) { return d+i; })
.enter()
.append("path")
.attr("d", path)
.on("click",text)
.append("title")
.text(function(d) { return d.properties.NAME; });
});

Related

Cannot append text to the d3.js force simulation circles

(function(){
//width and height
var width = 800,
height = 500;
//appending svg to the body and defining the canvas
var svg = d3.select("#chart")
.append("svg")
.attr("height", height)
.attr("width", width)
.append("g")
.attr("transform","translate(0,0)");
d3.queue()
.defer(d3.csv, "result1.csv")
.await(ready);
function ready(error, datapoints){
if(error){
console.log(error);
}else{
var color = d3.scaleLinear(datapoints)
.domain([1, 77])
.range(["#ffffff","#DD4B39"]);
var radiusScale = d3.scaleSqrt().domain([1, 10]).range([2,80]);
var simulation = d3.forceSimulation()
.force("x", d3.forceX(width/2).strength(0.05))
.force("y", d3.forceY(height/2).strength(0.05))
.force("center", d3.forceCenter().x(width * .5).y(height * .5))
.force("collide", d3.forceCollide(function(d){
return radiusScale(d.rad);
}));
var nodes = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(datapoints)
.enter()
.append("g")
.attr("transform", function(d, i) {
return "translate(" + width/12 + "," + height/12 + ")";
});
nodes.append("circle")
.attr("r", function(d){
return radiusScale(d.rad);
})
.attr("class","bubble")
.attr("stroke","#5e0000")
.attr("fill","red")
.attr("fill", function(d) {
return color(d.rad);
});
simulation.nodes(datapoints)
.on('tick',ticked);
function ticked(){
nodes
.attr("cx",function(d){return d.x})
.attr("cy",function(d){return d.y});
}
nodes.append("text")
.attr("class","system")
.attr("text-anchor", "middle")
.text(function(d) {
return d.rad;
});
}
}
})();
Above is my script. Im trying to append text the circles which has d3.js force simulations. I tried several methods but cannot append text to the circles. Please give me a solution for this. When i set simulation to the bubble class as
var nodes = d3.selectAll(".bubble");
, then it simulates only the circles. But text is invisible. plaese help.

D3 script failing to create points in the canvas after a certain limit

I am trying to draw check in information in a d3 canvas. I'm using this popular script to create the map and draw the points.
I can draw roughly 12000 points, after that the script refuses to draw anything on the canvas. Could someone point out what I might be doing wrong?
<script>
var width = 960,
height = 480;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var projection = d3.geo.equirectangular()
.scale(153)
.translate([width/2,height/2])
var path = d3.geo.path()
.projection(projection);
var graticule = d3.geo.graticule();
geo_data = [];
d3.csv("data/2008.csv", function(x){
console.log(x.length)
for (i = 12000; i < 24000; i++) {
geo_data.push([x[i].lat, x[i].long])
}
});
d3.json("https://gist.githubusercontent.com/abenrob/787723ca91772591b47e/raw/8a7f176072d508218e120773943b595c998991be/world-50m.json", function(error, world) {
svg.append("g")
.attr("class", "land")
.selectAll("path")
.data([topojson.object(world, world.objects.land)])
.enter().append("path")
.attr("d", path);
svg.append("g")
.attr("class", "boundary")
.selectAll("boundary")
.data([topojson.object(world, world.objects.countries)])
.enter().append("path")
.attr("d", path);
svg.append("g")
.attr("class", "graticule")
.selectAll("path")
.data(graticule.lines)
.enter().append("path")
.attr("d", path);
svg.selectAll("circle")
.data(geo_data)
.enter()
.append("circle")
.attr("cx", function (d) { return projection(d)[0]; })
.attr("cy", function (d) { return projection(d)[1]; })
.attr("r", "2px")
.attr("fill", "red")
});
</script>
The csv file contains information in this format
lat,long
-104.934812, 39.711152
-104.984703, 39.739154
-105.09543, 39.802002

parsing json to bar chart d3js

I'm trying to create a bar chart using the json url. With respect to impressions and time. I don't think I'm referencing the data correctly at .data(data) how do I access the impressions field from json file in d3?
var url = "https://script.google.com/macros/s/AKfycbwy56QiQwyfkkaLFWZ33QHVieAHhtLJYNa_AzKcCBr-J7Catgv2/exec?id=1vQsWQPUET20KcgeRKgs5NOOBngqLeUuNTHI1bWi5Et8&sheet=Sheet1";
d3.json(url, function(data) {
console.log(data.Sheet1[0]);
var canvas = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
canvas.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function(d) {
return d.Impressions
})
.attr("height", 45)
.attr("y", function(d, i) {
return i * 50
})
.attr("fill", "blue")
});
You have to pass an array to the function data(). Thus, since data is an object:
Object {Sheet1: Array[71]}
Your data should be data.Sheet1 instead. Check the demo:
var url = "https://script.google.com/macros/s/AKfycbwy56QiQwyfkkaLFWZ33QHVieAHhtLJYNa_AzKcCBr-J7Catgv2/exec?id=1vQsWQPUET20KcgeRKgs5NOOBngqLeUuNTHI1bWi5Et8&sheet=Sheet1";
d3.json(url, function (data) {
var scale = d3.scale.linear()
.domain([0, d3.max(data.Sheet1, function(d){ return d.Impressions})])
.range([0, 500]);
var canvas = d3.select("body").append("svg")
.attr("width",500)
.attr("height",500)
canvas.selectAll("rect")
.data(data.Sheet1)
.enter()
.append("rect")
.attr("width",function(d){return scale(d.Impressions)})
.attr("height", 6)
.attr("y",function(d,i){return i*7})
.attr("fill","blue")
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
PS: I added a scale to your code.

D3 - Load in and display data, row by row with set delay

I am trying to use time series data to plot bubbles on a map. What I would like to do is slowly plot these bubbles based on their date rather than all at once.
Something similar to:
http://www.nytimes.com/interactive/2014/upshot/mapping-the-spread-of-drought-across-the-us.html?_r=0
Here is some sample data:
date count code,country,lat,lon,counter
1/28/16 3 AND,Andorra,42.5,1.516667,0.577121255
1/29/16,146,ARE,United Arab Emirates,24.46666667,54.366667,2.264352856
1/30/16,13,AFG,Afghanistan,34.51666667,69.183333,1.213943352
Example of D3 Map
I have already looked at MB's tutorials on Path Transitions, Udacity's course on D3, and many questions on Stack Overflow.
I have previously tried using setInterval and setTimeout but most of the examples were with multiple data files. I would like to use one datafile line by line.
Code:
var width = 960,
height = 500;
var projection = d3.geo.mercator()
.center([0, 5 ])
.scale(200)
.rotate([-180,0]);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([0, 0])
.html(function(d) {
return "<strong>Frequency:</strong> <span style='color:white'>" + d.count + "</span>"+ "<br/>" + d.country;
})
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var path = d3.geo.path()
.projection(projection);
var g = svg.append("g");
// load and display the World
d3.json("world-110m2.json", function(error, topology) {
svg.call(tip)
// load and display the cities
d3.csv("cities2_or.csv", function(error, data) {
max = d3.max(data, function(d)
{return +d.counter})
coloring = d3.scale.linear()
.domain([0, max])
.range(["blue", "green"])
radiusing = d3.scale.linear()
.domain([0, max])
//.domain([0, 100])
.range([2, 30])
g.selectAll("circle")
.data(data)
.enter()
.append("circle")
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.attr("cx", function(d) {
return projection([d.lon, d.lat])[0];
})
.attr("cy", function(d) {
return projection([d.lon, d.lat])[1];
})
.style("r", function(d){
return radiusing(+d.counter)
;})
//.style("opacity", .5)
.style("fill", function(d){
return coloring(+d.counter);
})
});
Thanks for any help
I took #adilapapaya suggestions and tried using the delay function but I am only able to plot the first point.
Instead of the g.selectAll that I was using above I have replaced it with the following. This however only plots the first point in my csv file and then stops.
g.append("circle")
.data(data)
.attr("cx", function(d) {
return projection([d.lon, d.lat])[0];
})
.attr("cy", function(d) {
return projection([d.lon, d.lat])[1];
})
.style("r", 20)
.transition()
.duration(1)
.delay(function(d, i) { return i*1; })
.style("r",30)
.style("fill","green");
Thanks to Andrew Guy who helped find the JS fiddle example for me. Worked perfectly. My issue was not using the enter before hand. Here is the final code. Please respond if anyone has any questions.
var width = 960,
height = 500;
var projection = d3.geo.mercator()
.center([0, 5 ])
.scale(200)
.rotate([-180,0]);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([0, 0])
.html(function(d) {
return "<strong>Frequency:</strong> <span style='color:white'>" + d.count + "</span>"+ "<br/>" + d.country;
})
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var path = d3.geo.path()
.projection(projection);
var g = svg.append("g");
// load and display the World
d3.json("world-110m2.json", function(error, topology) {
svg.call(tip)
// load and display the cities
d3.csv("cities2_or.csv", function(error, data) {
max = d3.max(data, function(d)
{return +d.counter})
coloring = d3.scale.linear()
.domain([0, max])
.range(["blue", "green"])
radiusing = d3.scale.linear()
.domain([0, max])
//.domain([0, 100])
.range([2, 30])
g.selectAll("circle")
.data(data)
.enter()
.append("circle")
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.attr("cx", function(d) {
return projection([d.lon, d.lat])[0];
})
.attr("cy", function(d) {
return projection([d.lon, d.lat])[1];
})
// .style("r", function(d){
// return radiusing(+d.counter)
// ;})
//.style("opacity", .5)
.style("fill", function(d){
return coloring(+d.counter);})
.style("r",0)
.transition()
.duration(500)
.delay(function(d, i) { return i*200; })
.style("r",30);
});
g.selectAll("path")
.data(topojson.object(topology, topology.objects.countries)
.geometries)
.enter()
.append("path")
.attr("d", path)
});
// zoom and pan
var zoom = d3.behavior.zoom()
.on("zoom",function() {
g.attr("transform","translate("+
d3.event.translate.join(",")+")scale("+d3.event.scale+")");
g.selectAll("circle")
.attr("d", path.projection(projection));
g.selectAll("path")
.attr("d", path.projection(projection));
});
svg.call(zoom)

D3JS different image for each circle/node

So, I want to apply a different image in each circle in d3js.
One circle = one image different to others...
In my JSON data, i add a image path like this :
{"name":"Myriel","group":1,"icon": "images/01.png"},
{"name":"Napoleon","group":1,"icon": "images/10.png"}
the only solution I found for display images in circles in d3js is :
I declare refs and svg object.
for(var i=0;i<graph.nodes.length;i++){
var defs = svg.append('svg:defs');
defs.append('svg:pattern')
.data(graph.nodes)
.attr('id', "image"+i)
.attr('width', '1')
.attr('height', '1')
.append('svg:image')
.attr('xlink:href', function(d) { return(graph.nodes[i].icon); })
.attr('x', 0)
.attr('y', 0)
.attr('width', 120)
.attr('height', 120);
}
and I built my nodes/circles like that :
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 30)
.style("fill","url(#image1)")
.on("mouseover",function(){
var sel = d3.select(this)
sel.moveToFront();
})
.on("mouseout",function(){
var sel = d3.select(this);
sel.moveToBack();
});
If you want more explication, say me.
Sorry for my english...
Thank you in advance for helping!
This is the way I do it in my project (http://arda-maps.org/familytree/). I'm using png as image tough but it very similar if you just replace it with your ID from your svg path.
node
.append("svg:image")
.attr("class", "circle")
.attr("xlink:href", function (d) {
return "/pics/arda/creature/" + d.uniquename + "_familytree.png";
})
.attr("x", function (d) {
return familytree.posXY(d);
})
.attr("y", function (d) {
return familytree.posXY(d);
})
.attr("width", function (d) {
return familytree.sizeXY(d);
})
.attr("height", function (d) {
return familytree.sizeXY(d);
})
.on("error", function () {
d3.select(this).style("visibility", "hidden");
});
So you should test if this works for you.
.attr("xlink:href", function (d) {
return "url(#image1)";
})

Categories