circle location different when zoom or drag the d3 map? - javascript

Actually I want to use D3 for creating map for data visualization .
I have try to defining a sample data set of lon and lat coordinate points.This is an array of JSON objects where each object has the keys "lon " and "lat ".
I have set these points on map with concentric circles emanating from dots
like the image
[![enter image description here][1]][1]
but when zoom in the map or drag the map ,these circle with concentric circles emanating from dots on map will be not move ,like the image as below
[![enter image description here][2]][2]
my code,
var width = window.innerWidth,
height = window.innerHeight;
var projection = d3.geo.mercator()
.center([0, 5 ])
.scale(153)
.rotate([160, 0])
.translate([width / 2, height / 2])
.precision(.1);
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");
var arcGroup = g.append('g');
var y = d3.scale.ordinal().domain(d3.range(1)).rangePoints([0, height]);
var data = [ { "lat":-6.13, "lon": 39.31 },{ "lat": 35.68, "lon": 139.76 },
{ "lat": -36.85, "lon": 174.78 },{ "lat": 13.75, "lon": 100.48 },
{ "lat": 29.01, "lon": 77.38 },{ "lat": 1.36, "lon": 103.75 },
{ "lat":-15.67, "lon": -47.43 },{ "lat":22.90, "lon": -43.24 }];
// load and display the World
d3.json("world-110m2.json", function(error, topology) {
g.selectAll("path")
.data(topojson.object(topology, topology.objects.countries)
.geometries)
.enter().append("path")
.attr("d", path)
//add path
g.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 8)
.attr("transform",translateCircle);
var links = [];
var count = 0;
for(var i=0, len=data.length-1; i<len; i++){
console.log(i);
// (note: loop until length - 1 since we're getting the next
// item with i+1)
links.push(
{
type: "LineString",
coordinates: [
[ data[i].lon, data[i].lat ],
[ data[i+1].lon, data[i+1].lat ]
]
});i = i+1;
}
// Standard enter / update
var pathArcs = arcGroup.selectAll(".arc")
.data(links);
//enter
pathArcs.enter()
.append("path").attr({
'class': 'arc'
}).style({
fill: 'none',
});
//update
pathArcs.attr({
//d is the points attribute for this path, we'll draw
// an arc between the points using the arc function
d: path
})
.style({
stroke: '#0000ff',
'stroke-width': '1px'
})
});
setInterval(function(){
data.forEach(function(datum)
{
svg.append("circle")
.attr("class", "ring")
.data(data)
.attr("transform", function(d) {
return "translate(" + projection([
datum.lon,
datum.lat
]) + ")";
})
.attr("r", 6)
.style("stroke-width", 3)
.style("stroke", "red")
.transition()
.ease("linear")
.duration(6000)
.style("stroke-opacity", 1e-6)
.style("stroke-width", 1)
.style("stroke", "brown")
.attr("r", 160)
.remove();
})
}, 750)
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 translateCircle(datum, index)
{
return "translate(" + projection([datum.lon, datum.lat]) + ")";
};
It would be great if you could point me to some worked out examples or tutorials

Append the circles to the <g> element defined in the zoom function.
setInterval(function(){
data.forEach(function(datum){
g.append("circle")
codepen: http://codepen.io/Aure1ius/pen/jVgdmv

Related

JSON object not returning pie slices

I have been working off of this basic pie example to learn about writing pie charts in D3, but while I got the example to work when mimicking their data structure, I wanted to try it out with a JSON data structure that would be more native to how I would structure data for the visualizations. When switching the same data to this new structure I noticed that the black stroke appears and the annotations, but the slices aren't present and the annotation labels are referencing an index and object value.
I believe this is due to the .entries() method that converts it to a key-value data structure, but I'm curious if that is a necessary method to use in order to visualize the data points or if there is a simpler method to utilize the structure I have in place.
Working data structure:
var data = {
deep: 22.37484390963787,
light: 62.65183335225337,
rem: 14.973322738108752
}
JSON data structure:
var data = [
{ "label": "deep", "value": 22.37484390963787 },
{ "label": "light", "value": 62.65183335225337 },
{ "label": "rem", "value": 14.973322738108752 }
]
var data = [
{ "label": "deep", "value": 22.37484390963787 },
{ "label": "light", "value": 62.65183335225337 },
{ "label": "rem", "value": 14.973322738108752 }
]
// var data = {
// deep: 22.37484390963787,
// light: 62.65183335225337,
// rem: 14.973322738108752
// }
console.log(data)
var width = 480;
var height = 480;
var margin = 40;
var radius = Math.min(width, height) / 2 - margin;
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal()
.domain(data)
.range(["#98abc5", "#8a89a6", "#7b6888"]);
var pie = d3.pie()
.value(function(d) { return d.value; });
var data_ready = pie(d3.entries(data));
console.log(data_ready);
var arcGenerator = d3.arc()
.innerRadius(0)
.outerRadius(radius);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('path')
.attr('d', arcGenerator)
.attr('fill', function(d){ return color(d.data.key)})
.attr("stroke", "black")
.style("stroke-width", "2px")
.style("opacity", 0.7);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('text')
.text(function(d){ return d.data.key + ', ' + d.data.value})
.attr("transform", function(d) { return "translate(" + arcGenerator.centroid(d) + ")"; })
.style("text-anchor", "middle")
.style("font-size", 17);
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
The other way to achieve this is to not use d3.entries and pass your data directly. A couple of other tweaks are required where you get the color and label text (ie use d.data.label in place of d.data.key).
var data = [
{ "label": "deep", "value": 22.37484390963787 },
{ "label": "light", "value": 62.65183335225337 },
{ "label": "rem", "value": 14.973322738108752 }
]
// var data = {
// deep: 22.37484390963787,
// light: 62.65183335225337,
// rem: 14.973322738108752
// }
console.log(data)
var width = 480;
var height = 480;
var margin = 40;
var radius = Math.min(width, height) / 2 - margin;
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal()
.domain(data)
.range(["#98abc5", "#8a89a6", "#7b6888"]);
var pie = d3.pie()
.value(function(d) { return d.value; });
var data_ready = pie(data);
console.log(data_ready);
var arcGenerator = d3.arc()
.innerRadius(0)
.outerRadius(radius);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('path')
.attr('d', arcGenerator)
.attr('fill', function(d){ return color(d.data.label)})
.attr("stroke", "black")
.style("stroke-width", "2px")
.style("opacity", 0.7);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('text')
.text(function(d){ return d.data.label + ', ' + d.data.value})
.attr("transform", function(d) { return "translate(" + arcGenerator.centroid(d) + ")"; })
.style("text-anchor", "middle")
.style("font-size", 17);
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
You can't just change the format of the data without changing something else too. The simplest solution is to reformat your structure into the structure that d3 expected in the first place:
var formatted_data = data.reduce((acc,i) => {acc[i.label] = i.value; return acc;},{});
And then pass that to entries:
var data = [
{ "label": "deep", "value": 22.37484390963787 },
{ "label": "light", "value": 62.65183335225337 },
{ "label": "rem", "value": 14.973322738108752 }
]
// var data = {
// deep: 22.37484390963787,
// light: 62.65183335225337,
// rem: 14.973322738108752
// }
var formatted_data = data.reduce((acc,i) => {acc[i.label] = i.value; return acc;},{});
console.log(formatted_data)
var width = 480;
var height = 480;
var margin = 40;
var radius = Math.min(width, height) / 2 - margin;
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal()
.domain(data)
.range(["#98abc5", "#8a89a6", "#7b6888"]);
var pie = d3.pie()
.value(function(d) { return d.value; });
var data_ready = pie(d3.entries(formatted_data));
console.log(data_ready);
var arcGenerator = d3.arc()
.innerRadius(0)
.outerRadius(radius);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('path')
.attr('d', arcGenerator)
.attr('fill', function(d){ return color(d.data.key)})
.attr("stroke", "black")
.style("stroke-width", "2px")
.style("opacity", 0.7);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('text')
.text(function(d){ return d.data.key + ', ' + d.data.value})
.attr("transform", function(d) { return "translate(" + arcGenerator.centroid(d) + ")"; })
.style("text-anchor", "middle")
.style("font-size", 17);
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

getting the centroid co-ordinates in d3

I'm trying to append a small circle to the centroid of the arcs in the pie chart I have made, the centroid returns an array of both and x and y co-ordinate value so I tried to separate it by using the array index [0],[1]
<!doctype HTML>
<html>
<head>
<title>Page Title</title>
<meta charset="UTF-8">
<script type="text/javascript" src="js/d3.min.js"></script>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<script type="text/javascript">
//=================================================================================================================
// initializing variables
var data = []; // empty array to hold the objects imported from the JSON file
var oRadius = 300; //var holding value for the outer radius of the arc
var iRadius = 80; //var holding the value for the inner radius of the arc
var cRadius = 3; //var holding the value for the corner radius of the arc
var colors = d3.scale.category20b();//built in D3 function to color pieces of data
var width = 1400; //setting the width of the svg
var height = 1000; //setting the height of the svg
var dRadius = 5; //setting the radius for the dots
var sColor = "white"; // color for the stroke of the arcs
var dStrokeColor = "#666";
var dFillColor = "#ccc"
var myChart;
var myArcMaker= d3.svg.arc().outerRadius(oRadius).innerRadius(iRadius).cornerRadius(cRadius); //var that creates the arc
var bigArcMaker= d3.svg.arc().outerRadius(400).innerRadius(oRadius).cornerRadius(cRadius);
var mySvg = d3.select('body')
.append('svg')
.attr('width', width)
.attr("height", height) //selecting the body and appending an, then svg setting the height and width properties for the svg
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")// centers the pie chart in the center of the svg
mySvg.append("g")
.attr("class", "slices");
mySvg.append("g")
.attr("class", "dots");
mySvg.append("g")
.attr("class", "lines");
var myPie = d3.layout.pie()
.sort(null)
.startAngle(2*(Math.PI))
.endAngle(((Math.PI))/360)
.padAngle(-1.5*(2*(Math.PI))/360).value(function(d){return d.value}); //setting the values for that start angle, end angle and pad angle for the arcs and takes in the the values from the objects in the data array
//===================================================================================================================
d3.json("data.json", function (json) // importing the json file
{
data = json; // setting the empty data array equal to the values of the objects in the json file
visual(); // this function holds all the d3 code to create the arc
})
function visual() // this function prevents the code that creates the arc from running before the objects from the json file are added into the empty data array
{
console.log(data); // checking to see if the objects are loaded into the data ray using the console in chrome
var z = function(d) {return myArcMaker.centroid()}
var x1 = z[0]
var y1 = z[1]
console.log(x1);
var slice = mySvg.select(".slices")
.selectAll("path.slice")
.data(myPie(data)) //
.enter()
.append("path")
.attr("class", "slice")
.attr("d", function(d)
{
return myArcMaker(d)
})
.attr("fill", function(d, i) {return colors(i);}) //using the d3 color brewer to color each arc
.attr("stroke", "white") //giving each arc a stroke of white
var dots = slice.select(".dots")
.data(myPie(data))
.enter()
.append("circle")
.attr("class", "dots")
.attr("cx", x1)
.attr("cy", y1)
.attr("r", dRadius)
.attr("fill", dFillColor)
.attr("stroke", sColor)
}
</script>
</body>
</html>
When I run the code however the dots are only appearing in the center of the pie chart and arent appending to the x,y values of each respective arc. Any ideas on how to iterate through each arc to append the dot?
json data:
> [ { "Fruits": "Oranges", "value": 60 }, { "Fruits":
> "Apples", "value": 135 }, { "Fruits": "Bananas", "value": 225
> }, { "Fruits": "Kiwis", "value": 120 }, { "Fruits":
> "Pears", "value": 175 }, { "Fruits": "Grapes", "value": 145 }
> ]
Set the dot positions as shown below.
var dots = slice.select(".dots")
.data(myPie(data))
.enter()
.append("circle")
.attr("transform", function(d) {
return "translate(" + myArcMaker.centroid(d) + ")";
})
.attr("r", dRadius)
.attr("fill", dFillColor)
.attr("stroke", sColor);
And you missed value settings from d3 pie.
var myPie = d3.layout.pie()
.sort(null)
.startAngle(2 * (Math.PI))
.endAngle(((Math.PI)) / 360)
.value(function(d) {
return d.value;
});
Working Fiddle:
var data = [{
"Fruits": "Oranges",
"value": 60
}, {
"Fruits": "Apples",
"value": 135
}, {
"Fruits": "Bananas",
"value": 225
}, {
"Fruits": "Kiwis",
"value": 120
}, {
"Fruits": "Pears",
"value": 175
}, {
"Fruits": "Grapes",
"value": 145
}];
var oRadius = 300; //var holding value for the outer radius of the arc
var iRadius = 80; //var holding the value for the inner radius of the arc
var cRadius = 3; //var holding the value for the corner radius of the arc
var colors = d3.scale.category20b(); //built in D3 function to color pieces of data
var width = 1400; //setting the width of the svg
var height = 1000; //setting the height of the svg
var dRadius = 5; //setting the radius for the dots
var sColor = "white"; // color for the stroke of the arcs
var dStrokeColor = "#666";
var dFillColor = "#ccc"
var myChart;
var myArcMaker = d3.svg.arc().outerRadius(oRadius).innerRadius(iRadius);
var bigArcMaker = d3.svg.arc().outerRadius(200).innerRadius(oRadius);
var mySvg = d3.select('body')
.append('svg')
.attr('width', width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
mySvg.append("g")
.attr("class", "slices");
mySvg.append("g")
.attr("class", "dots");
mySvg.append("g")
.attr("class", "lines");
var myPie = d3.layout.pie()
.sort(null)
.startAngle(2 * (Math.PI))
.endAngle(((Math.PI)) / 360)
.value(function(d) {
return d.value;
});
visual();
function visual() {
var slice = mySvg.select(".slices")
.selectAll("path.slice")
.data(myPie(data)) //
.enter()
.append("path")
.attr("class", "slice")
.attr("d", function(d) {
return myArcMaker(d)
})
.attr("fill", function(d, i) {
return colors(i);
}) //using the d3 color brewer to color each arc
.attr("stroke", "white") //giving each arc a stroke of white
var dots = slice.select(".dots")
.data(myPie(data))
.enter()
.append("circle")
.attr("class", "dots")
.attr("transform", function(d) {
return "translate(" + myArcMaker.centroid(d) + ")";
})
.attr("r", dRadius)
.attr("fill", dFillColor)
.attr("stroke", sColor)
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
}
path {
stroke-width: 2px;
}
polyline {
opacity: .3;
stroke: black;
stroke-width: 2px;
fill: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Interactive d3 zip code choropleth - WA state

As the title says, I'm trying to make an interactive choropleth using d3. I've found an interesting example that I'm trying to replicate for another location.
Concretely, I'm trying to plot the Washington state, at the zip code level.
I've added the code I have at the moment that could be potentially edited, it's based on this example here is the live demo that shows the final result.
This is working for the California state, however when changing the zip code topojson state (to Washington state) the plot doesn't work. Also there are no explicit errors. The error could be in differences in the topojson.
This is the california topojson, here the Washington version.
Below are the first values pretty printed for each topojson.
California topojson:
{
"type": "Topology",
"objects": {
"zip": {
"type": "GeometryCollection",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"geometries": [
{
"type": "Polygon",
"properties": {
"zipcode": 94601
},
"arcs": [
[
0,
1,
2,
3,
4,
5
]
]
}
Washington topojson:
{
"type": "Topology",
"objects": {
"tl_2010_53_zcta510": {
"type": "GeometryCollection",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"geometries": [
{
"type": "Polygon",
"properties": {
"zipcode": "98822"
},
"arcs": [
[
0,
1,
2,
3
],
[
4
]
]
}
The following is the main.js function. I assume this and inspecting both topojson files could help find where the problem might be. Basically the only thing changing is the topojson file, then the main.js function should reflect these changes.
Also the "fake_data.csv" would just represent a serie of zipcode:value pairs as:
zip,values
98001,1
98002,1
98003,1
98004,2
98005,2
98006,2
main.js
(function chart() {
var width = 1000,
height = 1200,
centered;
var rateById = d3.map();
var quantize = d3.scale.quantize()
.domain([0, 100000])
.range(d3.range(9).map(function(i) { return "q" + i + "-9"; }));
var projection = d3.geo.albersUsa()
.scale(6000)
.translate([2300, 680]);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("#ca-chart").append("svg")
.attr("width", width)
.attr("height", height);
var tooltip = d3.select("#ca-chart").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
svg.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.on("click", clicked);
var g = svg.append("g");
// These are the two lines that are different from the working example
queue()
.defer(d3.json, "https://gist.githubusercontent.com/martinbel/e14cd6ecd565914f53af/raw/e3a3a8332c20fe3cee6d7fd2a9ac01ad43f7aaa4/WA.topojson")
.defer(d3.csv, "fake_data.csv", function(d) { rateById.set(d.zip.toString(), +d.values); })
.await(ready);
function ready(error, zipcode) {
var features = topojson.feature(zipcode, zipcode.objects.tl_2010_53_zcta510).features;
g.append("g")
.attr("class", "state")
.selectAll("path")
.data(topojson.feature(zipcode, zipcode.objects.tl_2010_53_zcta510).features)
.enter().append("path")
.attr("d", path)
.attr("stroke", "#333")
.attr("stroke-width", "1.5px")
.attr("fill", "#fff");
g.append("g")
.attr("class", "zipcodes")
.selectAll("path")
.data(features)
.enter().append("path")
.attr("class", getColorClass)
.attr("d", path)
.on("click", clicked)
.on("mouseover", mouseover)
.on("mouseout", mouseout);
}
function getColorClass(d) {
return quantize(rateById.get(d.properties.zipcode));
}
function getPopulation(d) {
return rateById.get(getZip(d)).toString();
}
function getZip(d) {
return d && d.properties ? d.properties.zipcode : null;
}
function mouseout(d) {
d3.select(this)
.style("stroke", null);
tooltip.transition()
.duration(250)
.style("opacity", 0);
}
function mouseover(d) {
d3.select(this.parentNode.appendChild(this))
.style("stroke", "#F00");
tooltip.transition()
.duration(250)
.style("opacity", 1);
tooltip
.html("<p><strong>Zipcode: " + getZip(d) + "<br>Population: " + getPopulation(d) + "</strong></p>")
.style("left", (d3.event.pageX + 25) + "px")
.style("top", (d3.event.pageY - 28) + "px");
}
function clicked(d) {
var x, y, k;
if (d && centered !== d) {
var centroid = path.centroid(d);
x = centroid[0];
y = centroid[1];
k = 8; // control zoom depth
centered = d;
} else {
x = width / 2;
y = height / 2;
k = 1;
centered = null;
}
g.selectAll("path")
.classed("active", centered && function(d) { return d === centered; });
g.transition()
.duration(750)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")")
.style("stroke-width", 1.5 / k + "px");
}
d3.select(self.frameElement).style("height", height + "px");
}());
The topojson file was produced in the following way:
curl -O "ftp://ftp2.census.gov/geo/tiger/TIGER2010/ZCTA5/2010/tl_2010_53_zcta510.zip"
unzip "tl_2010_53_zcta510.zip"
ogr2ogr -f GeoJSON -s_srs crs:84 -t_srs crs:84 tl_2010_53_zcta510.geojson tl_2010_53_zcta510.shp
topojson -o tl_2010_53_zcta510.topojson --properties zipcode=ZCTA5CE10 tl_2010_53_zcta510.geojson
The issue is that you're drawing the paths outside of the active viewing area. Try just this as your projection and you'll see the paths.
var projection = d3.geo.albersUsa()
// .scale(6000)
// .translate([2300, 680]);
You'll have to edit the scaling/translation for Washington...might be helpful to make your svg width and height ginormous (10000px or so) as you do this just so you can see where the map ends up.
This solved it for showing the map and display it without having to hack the parameters by hand. Actually the trick is to use a projection that supports the .center() method, albersUsa doesn't. Then it's much easier to sort out the scale parameter.
var projection = d3.geo.mercator()
.center([-120.574951, 47.361153])
.scale(5000)
.translate([(width) / 2, (height)/2]);
After this some other issues appeared.

How to group and filter using crossfilter in d3.js

js users,
I just started using d3.js & crossfilter and was attempting to make use of Adam Pearce's example on meteor map to visualise weather data. Instead of having only one record for each name in the "name" column, I have multiple-year records as I'm keen to analyse the weather changes over the years. Below is a sample of the original data and my own data:
orginal data
name mass_g year cartodb_id ....
Vilna 1 1967 34039
Silistra 1 1917 34017
My data
name rainfall year cartodb_id ....
station_A 100 1997 34039
station_A 200 1998 34039
station_B 300 1997 34017
station_B 400 1998 34017
I'm not sure where went wrong as it did not produce any error(s). However,
the crossfilter did not seem to take effect on the map
it did not group the rainfall values by the stations on the map (I think they are overlapping each other)
I couldn't group the two bar charts such that I could show the time series of rainfall over the years, as well as the rainfall distribution (I think need to use some Reduce function but I can't figure it out)
Below is my js script to replace the original drawMap.js (sorry, it's a little too long; Thank you for any kind advice!):
var width = 1000,
height = 500;
var proj = d3.geo.mercator()
.center([103.8,1.33])
.scale(100000)
.rotate([0,0]);
var path = d3.geo.path()
.projection(proj);
// for map
var zoom = d3.behavior.zoom()
.translate(proj.translate())
.scale(proj.scale())
.scaleExtent([100000,Infinity]) //.scaleExtent([height*.33, 4 * height])
.on("zoom", zoom);
var svg = d3.select("#map").append("svg")
.attr("width", width)
.attr("height", height)
.call(zoom);
function zoom() {
proj.translate(d3.event.translate).scale(d3.event.scale);
svg.selectAll("path").attr("d", path);
circles
.attr("cx", function(d){return proj([d.long, d.lat])[0];})
.attr("cy", function(d){return proj([d.long, d.lat])[1];});
}
var borders = svg.append("g");
var impacts = svg.append("g");
// colours and scales for the corresponding values in map
var metorScale = d3.scale.pow().exponent(.5).domain([0, 100, 1000, 2000, 3000, 5000, 8000]);
var colorScale = d3.scale.linear().domain([1980, 1888, 1996, 2004, 2014]);
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 1e-6)
.style("background", "rgba(250,250,250,.7)");
tooltip.append("img")
.attr("id", "tooltipImg")
.attr("height", 200)
.attr("width", 200)
.style("opacity", "1");
// change the fell file to our rainfall
// file has to be at aggregated level for each year
// one station one value for one year
// change the json file to our map
queue()
.defer(d3.json, "Planning_Area_Census2010_WGS84.json")
.defer(d3.csv, "yearlyrainfall.csv")
/*.defer(d3.json, "pics.json")*/
.await(ready);
var metors;
// for the rest of the code
// removed pics in the inputs
function ready(error, topology, csv){
borders.selectAll("path")
.data(topojson.object(topology, topology.objects.Planning_Area_Census2010_WGS84)
.geometries)
.enter()
.append("path")
.attr("d", path)
.attr("class", "border")
rawMetors = csv;
// change mass_g to rainfall
// cartodb_id is a key for our station
metors = [];
rawMetors.forEach(function(d){
d.rainfall = +d.rainfall;
d.year = +d.year;
d.id = +d.cartodb_id;
d.name = d.name;
d.region = d.region;
metors.push(d);
});
metors.sort(function(a, b){return a.id - b.id;})
// size tag to rainfall
//colour tag to year
metorScale
.range([1.5, 2, 3, 4, 5, 8, 10]);
colorScale
.range(["#FFFF66", "#FFFF00", "#E68000", "#D94000", "#CC0000"]);
circles = impacts.selectAll("circle")
.data(metors).enter()
.append("svg:a")
.attr("xlink:href", function(d) { return d.database; })
.attr("xlink:show", "new")
.append("circle")
.attr("cx", function(d){return proj([d.long, d.lat])[0];})
.attr("cy", function(d){return proj([d.long, d.lat])[1];})
.attr("r", function(d){return metorScale(d.rainfall);})
.attr("id", function(d){return "id" + d.id;})
.style("fill", function(d){return colorScale(d.year); })
.on("mouseover", function(d){
d3.select(this)
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("fill-opacity", 1);
tooltip
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 5) + "px")
.transition().duration(300)
.style("opacity", 1)
.style("display", "block")
updateDetails(d);
})
.on("mouseout", function(d){
d3.select(this)
.attr("stroke", "")
.attr("fill-opacity", function(d){return 1;})
tooltip.transition().duration(700).style("opacity", 0);
});
metorsCF = crossfilter(metors),
all = metorsCF.groupAll(),
year = metorsCF.dimension(function(d){return d.year;}), /*creating a type dimension*/
years = year.group(function(d){return Math.floor(d);}),
rainfall = metorsCF.dimension(function(d){return d.rainfall }), /*creating a type dimension*/
rainfalls = rainfall.group(function(d){return Math.floor(d/10)*10;}),
// for grouping at var charts
// group by type, change to region
region = metorsCF.dimension(function(d){return d.region;}), /*creating a type dimension*/
regions = region.group();
// create group of ids
cartoDbId = metorsCF.dimension(function(d){return d.id;}); /*creating a type dimension*/
cartoDbIds = cartoDbId.group()
// create all the bar charts
// first one draw by group of years
// change the domain relate to the format tick in barchart.js
var charts = [
barChart()
.dimension(year)
.group(years)
.x(d3.scale.linear()
.domain([1970,2020])
.rangeRound([-1, 20*24-5])),
// change the domain relate to the format tickvalues in barchart.js
barChart()
.dimension(rainfall)
.group(rainfalls)
.x(d3.scale.linear()
.domain([1,10000])
.rangeRound([0,20*24]))
];
var chart = d3.selectAll(".chart")
.data(charts)
.each(function(chart){chart.on("brush", renderAll).on("brushend", renderAll)});
d3.selectAll("#total")
.text(metorsCF.size());
function render(method){
d3.select(this).call(method);
}
lastFilterArray = [];
metors.forEach(function(d, i){
lastFilterArray[i] = 1;
});
function renderAll(){
chart.each(render);
var filterArray = cartoDbIds.all();
filterArray.forEach(function(d, i){
if (d.value != lastFilterArray[i]){
lastFilterArray[i] = d.value;
d3.select("#id" + d.key).transition().duration(500)
.attr("r", d.value == 1 ? 2*metorScale(metors[i].rainfall) : 0)
.transition().delay(550).duration(500)
.attr("r", d.value == 1 ? metorScale(metors[i].rainfall) : 0);
}
})
d3.select("#active").text(all.value());
}
window.reset = function(i){
charts[i].filter(null);
renderAll();
}
renderAll();
}
// to show the labels on what to display on map
var printDetails = [
{'var': 'name', 'print': 'Station'},
{'var': 'region', 'print': 'Region'},
{'var': 'rainfall', 'print': 'Rainfall(mm)'},
{'var': 'year', 'print': 'Year'}];
function updateDetails(metorsCF){
// var image = new Image();
// image.onload = function(){
// document.getElementById("tooltipImg").src = 'pictures/' + metor.cartodb_id + '.jpg';}
// image.src = 'pictures/' + metor.cartodb_id + '.jpg';
tooltip.selectAll("div").remove();
tooltip.selectAll("div").data(printDetails).enter()
.append("div")
.append('span')
.text(function(d){return d.print + ": ";})
.attr("class", "boldDetail")
.insert('span')
.text(function(d){return metorsCF[d.var];})
.attr("class", "normalDetail");
}
[1]: http://roadtolarissa.com/meteors/

Different colors for each circle - D3 circle pack

I have done the bubble chart. But I'm not getting different colors for each bubble. How could I do that? How could I give different colors for each circle? And the circle data with the highest value should always come at the center surrounded by other bubbles.
Snippet:
var diameter = 200,
format = d3.format(",d"),
color = ["#7b6888", "#ccc", "#aaa", "#6b486b"];
var bubble = d3.layout.pack()
.size([diameter, diameter]);
var svg = d3.select("#bubbleCharts").append("svg")
.attr("width", diameter + 10)
.attr("height", diameter)
.attr("class", "bubble");
var a;
d3.json("flare.json", function(error, root) {
var node = svg.selectAll(".node")
.data(bubble.nodes(classes(root))
.filter(function(d) { return !d.children; }))
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + 20 + "," + d.y + ")"; });
node.append("circle")
.attr("r", function(d) { return d.r+ 7; })
.style("fill", function(d) {
for(a in color){
return color[a]; };} );
node.append("text")
.attr("dy", ".3em")
.style("text-anchor", "middle")
.text(function(d) { return d.value+"%"; });
});
function classes(root) {
var classes = [];
function recurse(name, node) {
if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
else classes.push({packageName: name, value: node.value});
}
recurse(null, root);
return {children: classes};
}
My data is:
{
"name": "Spending Activity",
"children": [
{"name": "Petrol", "value": 60},
{"name": "Travel", "value": 10},
{"name": "Medical", "value": 25},
{"name": "Shopping", "value": 5}
]
}
You probably want a colour scale to get the fill colours:
var colour = d3.scale.category20();
Then you can set the fill colour like this:
node.append("circle")
.attr("r", function(d) { return d.r+ 7; })
.style("fill", function(d, i) { return colour(i); });
As for the positions of the nodes, the pack layout doesn't provide any functionality to affect that, i.e. you cannot force a particular circle to be in the center.
This reference card may be handy while choosing built-in D3 color sets:
Alternatively, you can use colorbrewer color sets: (see example here)

Categories