I have created two GeoJSON objects, and when I inspect the element I can see them both listed. I have looked through numerous transition tutorials on d3.js and am still lost as to how to draw one, then transition to the other.
I have tried to implement the exit().remove() function within the second geoJSON object, but have failed to make this work. I am very much lost, and cannot seem to make anything I have found work.
I understand that the code below is very basic, but all the things I have tried have failed beyond this point.
<head>
<meta charset="utf-8">
<title>Cartogram 1</title>
<style>
</style>
<svg width="100" height="2"></svg>
<script type="text/javascript" src="js/d3.v3.js"></script>
<script>
var svg = d3.select("body").append("svg")
.attr("width", 1500)
.attr("height", 1500)
var projection = d3.geo.equirectangular();
var world1 = d3.json("world2.json", function (data) {
svg.selectAll("g")
.data(data.features)
.enter()
.append("g")
.append("path")
.attr("d", path)});
var world2 = d3.json("goldatt2.json", function (data) {
svg.selectAll("h")
.data(data.features)
.enter()
.append("h")
.append("path")
.attr("d", path)});
path = d3.geo.path().projection(projection);
</script>
This has been changed to:
var svg = d3.select("body").append("svg")
.attr("width", 1500)
.attr("height", 1500)
var projection = d3.geo.equirectangular()
var path = d3.geo.path().projection(projection);
d3.json("world2.json", function (data) {
svg.selectAll("g")
.data(data.features)
.enter()
.append("g")
.append("path")
.attr("d", path)
});
d3.json("goldq.json", function (data) {
var sel = svg.selectAll("g")
.data(data.features);
sel.enter()
.append("g")
.append("path");
sel.transition().duration(1000).attr("d", path)
sel.exit().remove();
});
Which results in the following:
http://www.geos.ed.ac.uk/~s1227289/world/lars.html
What am I missing?
You need to update the path once you've drawn it:
var path = d3.geo.path().projection(projection);
d3.json("world2.json", function (data) {
svg.selectAll("g")
.data(data.features)
.enter()
.append("g")
.append("path")
.attr("d", path)
});
d3.json("goldatt2.json", function (data) {
var sel = svg.selectAll("g")
.data(data.features);
sel.enter()
.append("g")
.append("path");
sel.attr("d", path);
sel.exit().remove();
});
A few general notes. There is no h element. In the code above, the order of execution is not guaranteed as d3.json is asynchronous. You need to make sure that it executes in the order you want yourself, for example by nesting the calls to d3.json.
Related
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
I am trying to draw the states of India map (with disputed territories ) by D3 Map. I successfully generate the topojson file which looks good in http://www.mapshaper.org/
And the json link is https://dl.dropboxusercontent.com/s/wk9qd47wn1nhsjm/dddtopo.json
But I failed to draw the map. The link http://jsfiddle.net/sEFjd/47/ is how I did under jsfiddle.
var topoJsonUrl = "https://dl.dropboxusercontent.com/s/wk9qd47wn1nhsjm/dddtopo.json";
var width = 360,
height = 360;
d3.json(topoJsonUrl, function(error, mx) {
var projection = d3.geo.mercator();
// create the path
var path = d3.geo.path().projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
console.log(mx);
var geoPaths = svg.append("g")
.attr("class", "municipalities")
.selectAll("path")
.data(topojson.feature(mx, mx.objects.india).features);
geoPaths.enter().append("path")
.attr("d", path);
var p= svg.append("path")
.datum(topojson.mesh(mx, mx.objects.india))
.attr("d", path)
.attr("class", "state-boundary");
geoPaths.style("fill", function(d) {
return Math.random() > 0.5 ?'gray' : 'blue';
});
});
The code works well with other countries(Germany, Mexico) Not sure why it does not work this time. Any help will be very appreciated.
The us.json loaded, but when i try to add Label name i can't make it work. I don't see the name property in .json file so how can i add each state name? I'm really new to this framework.
I try different Tutorial on Google and Stackoverflow, but none of them work for me. Here is the link to couple tutorial i tried, that i think is worthy.
Add names of the states to a map in d3.js
State/County names in TopoJSON or go back GeoJSON?
The concerns I have:
I think I'm missing name property in us.json file. (if that's the issue, is there any other .json file that includes state name? And how to use the state name with that file?)
Is the US state name included in http://d3js.org/topojson.v1.min.js?
.html File (Framework Loaded)
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
.js File:
var width = 1500,
height = 1100,
centered;
var usData = ["json/us.json"];
var usDataText = ["json/us-states.json"];
var projection = d3.geo.albersUsa()
.scale(2000)
.translate([760, height / 2]);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("body").append("svg")
.style("width", "100%")
.style("height", "100%");
svg.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.on("click", clicked);
var g = svg.append("g");
d3.json(usData, function(unitedState) {
g.append("g")
.attr("class", "states-bundle")
.selectAll("path")
.data(topojson.feature(unitedState, unitedState.objects.states).features)
.enter()
.append("path")
.attr("d", path)
.attr("class", "states")
.on("click", clicked);
});
Thank you everyone in advanced. I also appreciate if you tell me where did you learn d3.js.
As you stated your us.json doesn't have state names in it. What it has, though, are unique ids and luckily, Mr. Bostock has mapped those ids to names here.
So, let's fix up this code a bit.
First, make the json requests to pull the data:
// path data
d3.json("us.json", function(unitedState) {
var data = topojson.feature(unitedState, unitedState.objects.states).features;
// our names
d3.tsv("us-state-names.tsv", function(tsv){
// extract just the names and Ids
var names = {};
tsv.forEach(function(d,i){
names[d.id] = d.name;
});
Now add our visualization:
// build paths
g.append("g")
.attr("class", "states-bundle")
.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("d", path)
.attr("stroke", "white")
.attr("class", "states");
// add state names
g.append("g")
.attr("class", "states-names")
.selectAll("text")
.data(data)
.enter()
.append("svg:text")
.text(function(d){
return names[d.id];
})
.attr("x", function(d){
return path.centroid(d)[0];
})
.attr("y", function(d){
return path.centroid(d)[1];
})
.attr("text-anchor","middle")
.attr('fill', 'white');
....
Here's a working example.
I have overlayed two datasets, a boundary map and a point map in d3.js. I want to be able to zoom both datasets at the same time. With the current code, only the point map responds to the zoom. How can I zoom both datasets at the same time
The code is shown below
var canvas = d3.select("body").append("svg")
.attr("width",260)
.attr("height",400)
d3.json("/Maps/iowastate.json",function (data){
var group = canvas.selectAll("g")
.data(data.features)
.enter()
.append("g")
var projection =d3.geo.mercator()
.scale(250)
//.translate([0,0]);
var path = d3.geo.path().projection(projection);
var areas = group.append("path")
.attr("d", path)
.attr("class","area")
.attr("fill","black");
d3.csv("/Maps/detectors.csv",function (d){
var group = canvas.selectAll("g")
.data(d)
.enter()
.append("circle")
.attr("cx", function(d) {
return projection([d.StartLong,d.StartLat])[0];
})
.attr("cy", function(d,i) {
return projection([d.StartLong,d.StartLat])[1];
})
.attr("r", 0.1)
.style("fill", "red");
//console.log(projection(d[0].StartLat))
var zoom = d3.behavior.zoom()
.on("zoom",function(){
group.attr("transform","translate("+
d3.event.translate.join(",")+")scale("+d3.event.scale+")");
group.selectAll("path")
.attr("d", path.projection(projection));
});
canvas.call(zoom)
})
var zoom = d3.behavior.zoom()
.on("zoom",function(){
group.attr("transform","translate("+
d3.event.translate.join(",")+")scale("+d3.event.scale+")");
group.selectAll("path")
.attr("d", path.projection(projection));
});
canvas.call(zoom)
})
You are applying the right modifications, but twice to the same set of elements instead of the two different layers. To make it work, keep a reference to the other group (e.g. by using different variable names) and apply the transformations to both groups.
I have a topojson which contains state's paths. I want the user to be able to hover over a state and the state to appear in a different svg. So far, I've tried to extract the geometry out of the topojson (d.geometry , d.geometry.coordinates etc) But I'm not able to do it.
Maybe I need to draw a polygon out of that, but some states are of type "Polygon" and some of them are of type "MultiPolgyon".
Any ideas/suggestions?
Edit : Here's my code
var svg = d3.select("#india-map")
.append("svg")
.attr("width",width).attr("preserveAspectRatio", "xMidYMid")
.attr("viewBox", "0 0 " + width + " " + height)
.attr("height", height)
var stateSvg = d3.select("#state-map")
.append("svg")
.append("g")
.attr("height", height)
.attr("width", width);
var g = svg.append("g");
var projection = d3.geo.mercator()
.center([86, 27])
.scale(1200);
var path = d3.geo.path().projection(projection);
var pc_geojson = topojson.feature(pc, pc.objects.india_pc_2014);
var st_geojson = topojson.feature(state_json, state_json.objects.india_state_2014);
g.selectAll(".pc")
.data(pc_geojson.features)
.enter().append("path")
.attr("class", "pc")
.attr("d", path)
.attr("id", function(d){ return d.properties.Constituency;})
.attr("fill", "orange")
.on("click", function(d){
drawCons(d);
});
function drawCons(d){
stateSvg.selectAll(".pc2")
.data(d)
.enter().append("path")
.attr("class","pc2")
.attr("d", path)
}
.data() expects to be given an array of objects to be matched against the selection. You're passing a single object, so it doesn't work. You can either use .datum(d) or .data([d]) to make it work.
Quick and dirty demo here.