I'm very new to D3 - in fact I only started yesterday - have a donut pie chart here:
var dataset = new Array();
dataset[0] = {"value":"50","color":"red"};
dataset[1] = {"value":"20","color":"blue"};
var pie = d3.layout.pie().sort(null).value(function(d){return d.value;});
var h = w = 500;
var center = w / 2;
var outerRadius = ((h/2)-5);
var innerRadius = outerRadius-10;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var arcOutter = d3.svg.arc()
.innerRadius(outerRadius)
.outerRadius(outerRadius + 1);
var arcInner = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(innerRadius - 1);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + center + ", " + center + ")");
//Set up outter arc groups
var outterArcs = svg.selectAll("g.outter-arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "outter-arc")
.attr("transform", "translate(" + center + ", " + center + ")");
//Set up outter arc groups
var innerArcs = svg.selectAll("g.inner-arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "inner-arc")
.attr("transform", "translate(" + center + ", " + center + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function (d, i)
{
return d.data.color;
}).attr("d", arc);
//Draw outter arc paths
outterArcs.append("path")
.attr("fill", 'green')
.attr("d", arcOutter).style('stroke', 'white')
.style('stroke-width', 0);
//Draw inner arc paths
innerArcs.append("path")
.attr("fill", 'green')
.attr("d", arcInner).style('stroke', 'white')
.style('stroke-width', 0);
jsFiddle chart
But I'm struggling to add 4 clock points and their time tables to it, (12am, 3pm, 6pm, 9pm), I've tried searching clock examples but they're all working clocks, not just the points.
I want it to look pretty much like this:
Any help would be greatly appreciated.
I don't know how aestheticaly correct it is, but here it goes. What you could do, is add 4 line segments in your chart at these locations:
[w/2, 0],[w/2,h],[0,h/2],[w,h/2]
You can achieve that if you add the following lines:
var x=d3.scale.linear().domain([0,outerRadius]).range([0,w])
var y=d3.scale.linear().domain([0,outerRadius]).range([h,0])
svg.append('line').attr("x1",x(outerRadius/2)).attr("y1",0).attr("x2",x(outerRadius/2)).attr("y2",20)
svg.append('line').attr("x1",x(outerRadius/2)).attr("y1",y(outerRadius)).attr("x2",x(outerRadius/2)).attr("y2",y(outerRadius)-20)
svg.append('line').attr("x1",0).attr("y1",y(outerRadius/2)).attr("x2",20).attr("y2",y(outerRadius/2))
svg.append('line').attr("x1",x(outerRadius)).attr("y1",y(outerRadius/2)).attr("x2",x(outerRadius)-20).attr("y2",y(outerRadius/2))
Please note that you have to create a css entry, so that the line is shown:
line{
display:block;
stroke:black;
}
JSFiddle here
Hope this helps
Following the lovely example here.
var radians = 0.0174532925;
var hourScale = d3.scale.linear()
.range([0,330])
.domain([0,11]);
var labelGroup = svg.append('g')
.attr('transform','translate(' + (center + margin) + ',' + (center + margin) + ')');
labelGroup.selectAll('.hour-label')
.data([12,3,6,9])
.enter()
.append('text')
.attr('class', 'hour-label')
.attr('text-anchor','middle')
.style('font-size','16pt')
.attr('x',function(d){
return outerRadius * Math.sin(hourScale(d)*radians);
})
.attr('y',function(d){
return -outerRadius * Math.cos(hourScale(d)*radians);
})
.text(function(d){
return d;
});
Updated fiddle.
Related
My code is like this. Can you say what is the error? My color is not showing properly although the section text is showing. the data set is the death rate of the US over time.
function clicked(d,i) {
var dataset = [d.females, d.males];
var pcolor = ["green", "pink"];
var outerRadius = 60;
var innerRadius = 0;
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.pie();
//Easy colors accessible via a 10-step ordinal scale
//var color = d3.scaleOrdinal(d3.schemeCategory10);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arcs")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("d", arc)
.attr("fill", function(d, i) {
console.log(d);
return pcolor(i);
});
//Labels
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
}
I'm accessing a GITHUB raw file and using the d3.pie() function making the start and end angles of the pie, at that point the data is showing on console but when I access it in tooltip it gives UNDEFINED.
Do run the code if you can, the link to my github is given where I'm loading my file d3.csv() also FUNCTION TEST is running only once I need to run it till my data runs out.
//CALCULATING RADIUS OF CHART
var radius = Math.min(width, height) / 2 - margin
//APPENDING SVG IN DIV HAVING ID pieChart
var svg = d3.select("#pieChart")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// DATA
d3.csv
("https://raw.githubusercontent.com/Dehya/django/master/pkpopulation.csv?
token=AHXLL23PHQSJGYIYCLA6YX25I7IJA",function(error, data){
// GETTING VALUES AS POPULATION FROM DATA AND CALCULATING THE START AND
END
ANGLE:
var pie = d3.pie()
.value(function(d) {return d.population; })
console.log(pie(data));
//SETTING COLOR SCALE
var color = d3.scaleOrdinal()
.domain(data)
.range(["red", "yellow", "green", "blue", "orange"])
function Test(d){
for( i ; i<data.length ; i++)
{
console.log(data[i].name + " : " + data[i].population);
return data[i].name + " : " + data[i].population;
}
}
//MAKING TOOPTIP
var tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(Test(data));
svg.call(tip);
//MAKING SLICES OF PIE CHART
svg
.selectAll("mySlices")
.data(pie(data))
.enter()
.append("path")
.attr('d',d3.arc()
.innerRadius(0)
.outerRadius(radius)
)
.attr("fill", function(d){ return color(d.data.key) })
.attr("stroke","black")
.style("stroke-width","1px")
.style("opacity",0.7)
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
});
I am using this example to guide my foray into chord diagrams with d3. I have it working with my data in v2 (the version the example is in), and now I am attempting to upgrade to v4.
Here is the code that works with v2:
<script src="http://d3js.org/d3.v2.min.js?2.8.1"></script>
<script>
var width = 900,
height = 900,
outerRadius = Math.min(width, height) / 2 - 10,
innerRadius = outerRadius - 24;
var formatPercent = d3.format(",.0f");
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var layout = d3.layout.chord()
.padding(.02)
.sortSubgroups(d3.descending)
.sortChords(d3.ascending);
var path = d3.svg.chord()
.radius(innerRadius);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("id", "circle")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
svg.append("circle")
.attr("r", outerRadius);
d3.csv("teams.csv", function(cities) {
d3.json("matrix.json", function(matrix) {
// Compute the chord layout.
layout.matrix(matrix);
// Add a group per neighborhood.
var group = svg.selectAll(".group")
.data(layout.groups)
.enter().append("g")
.attr("class", "group")
.on("mouseover", mouseover);
// Add a mouseover title.
group.append("title").text(function(d, i) {
return cities[i].name + ": " + formatPercent(d.value) + " as business unit";
});
// Add the group arc.
var groupPath = group.append("path")
.attr("id", function(d, i) { return "group" + i; })
.attr("d", arc)
.style("fill", function(d, i) { return cities[i].color; });
// Add the chords.
var chord = svg.selectAll(".chord")
.data(layout.chords)
.enter().append("path")
.attr("class", "chord")
.style("fill", function(d) { return cities[d.source.index].color; })
.attr("d", path);
// Add an elaborate mouseover title for each chord.
chord.append("title").text(function(d) {
return cities[d.source.index].name
+ " → " + cities[d.target.index].name
+ ": " + formatPercent(d.source.value)
+ "\n" + cities[d.target.index].name
+ " → " + cities[d.source.index].name
+ ": " + formatPercent(d.target.value);
});
function mouseover(d, i) {
chord.classed("fade", function(p) {
return p.source.index != i
&& p.target.index != i;
});
}
});
});
</script>
Here is the same code midway through my attempt to migrate to v4:
<script src="http://d3js.org/d3.v4.min.js"></script>
<script>
var width = 900,
height = 900,
outerRadius = Math.min(width, height) / 2 - 10,
innerRadius = outerRadius - 24;
var formatPercent = d3.format(",.0f");
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var layout = d3.chord()
.padAngle(.02)
.sortSubgroups(d3.descending)
.sortChords(d3.ascending);
var path = d3.ribbon()
.radius(innerRadius);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("id", "circle")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
svg.append("circle")
.attr("r", outerRadius);
d3.csv("teams.csv", function(cities) {
d3.json("matrix.json", function(matrix) {
// Compute the chord layout.
layout.matrix(matrix);
// Add a group per neighborhood.
var group = svg.selectAll(".group")
.data(layout.groups)
.enter().append("g")
.attr("class", "group")
.on("mouseover", mouseover);
// Add a mouseover title.
group.append("title").text(function(d, i) {
return cities[i].name + ": " + formatPercent(d.value) + " as business unit";
});
// Add the group arc.
var groupPath = group.append("path")
.attr("id", function(d, i) { return "group" + i; })
.attr("d", arc)
.style("fill", function(d, i) { return cities[i].color; });
// Add the chords.
var chord = svg.selectAll(".chord")
.data(layout.chords)
.enter().append("path")
.attr("class", "chord")
.style("fill", function(d) { return cities[d.source.index].color; })
.attr("d", path);
// Add an elaborate mouseover title for each chord.
chord.append("title").text(function(d) {
return cities[d.source.index].name
+ " → " + cities[d.target.index].name
+ ": " + formatPercent(d.source.value)
+ "\n" + cities[d.target.index].name
+ " → " + cities[d.source.index].name
+ ": " + formatPercent(d.target.value);
});
function mouseover(d, i) {
chord.classed("fade", function(p) {
return p.source.index != i
&& p.target.index != i;
});
}
});
});
</script>
So far, I've flattened the namespaces (up to d3.csv), changed padding to padAngle, and changed var path = d3.chord() to var path = d3.ribbon(). As I make each change, I am checking the error messages in Chrome Developer. After making those changes, the current error is layout.matrix is not a function. This makes sense, based on v4 standards. To combat this, I tried adding .data(layout.matrix) to the var svg creation. I tried a few other routes gleaned from other chord diagram examples, to no avail.
How should I access and bind the data in v4?
Edit: I added .data(layout(matrix)) instead, and now the g elements with class=group are being created. However, this error is occurring: attribute d: Expected number, "MNaN,NaNLNaN,NaNZ". So I'm thinking this means the location is not being populated correctly.
Edit #2: Now I've gotten everything to show up except for the bars around the outside. Here is my current code. I believe the d attribute of the path elements within the g groups are wrong. They are set to be the same as the path elements outside the g groups. When I attempt to set them to arc instead (.attr("d", arc), the error attribute d: Expected number, "MNaN,NaNLNaN,NaNZ". occurs.
<script>
var width = 900,
height = 900,
outerRadius = Math.min(width, height) / 2 - 10,
innerRadius = outerRadius - 24;
var formatPercent = d3.format(",.0f");
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var layout = d3.chord()
.padAngle(.02)
.sortSubgroups(d3.descending)
.sortChords(d3.ascending);
var ribbon = d3.ribbon()
.radius(innerRadius);
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("id", "circle")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
svg.append("circle")
.attr("r", outerRadius);
d3.csv("teams.csv", function(cities) {
d3.json("matrix.json", function(matrix) {
// Add a group per neighborhood.
var group = svg.selectAll(".group")
.data(layout(matrix))
.enter()
.append("g")
.attr("class", "group");
// Add the group arc.
var groupRibbon = group.append("path")
.attr("id", function(d, i) { return "group" + i; })
.attr("d", ribbon)
//.style("fill", function(d, i) { return cities[i].color; })
;
// Add the chords.
var chord = svg.selectAll(".chord")
.data(layout(matrix))
.enter().append("path")
.attr("class", "chord")
.style("fill", function(d) { return cities[d.source.index].color; })
.attr("d", ribbon);
});
});
</script>
I have a pie chart and I want to increase the inner radius of the arc the user mouses over.
For example, if I mouse over the arc with 161, I want only the inner radius of that arc segment to increase.
How would I do this?
// arc radius
var radius = 200;
var p = Math.PI *2; //full circle
var data = [11,12,51,21,31,58,41,13,14,31,71,31,51,71,16,41,31,161];
var data1 = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18];
var width = 1000;
var height = 1000;
//========== color scale ==========//
var colorScale = d3.scale.ordinal()
.range(['#FFEBEB', '#FFC2C2', '#FFADAD', '#FF9999', '#FF7070', '#FF5C5C', '#FF4747',
'#FF1F1F', '#FF0A0A', '#F50000', '#CC0000', '#A30000', '#8F0000', '#660000', '#520000', '#3D0000', '#290000', '#140000']);
//========== Create canvas and arc ==========//
var canvas = d3.select("body")
.append("svg")
.attr("height", height)
.attr("width", width);
var group = canvas.append("g")
.attr("transform", "translate(" + width/2 + ",500)");
var arc = d3.svg.arc()
.innerRadius(radius-50)
.outerRadius(radius);
var pie = d3.layout.pie()
.value(function (d){return d;});
var sorted = data.sort(function(a,b){return a-b});
var arcs = group.selectAll(".arc")
.data(pie(sorted))
.enter()
.append("g")
.attr("class", "arc");
arcs.append("path")
.attr("d", arc)
.style('stroke', 'white')
.style('stroke-width', 2)
.attr("fill", function(d, i){return colorScale(d.data);});
arcs.append("text")
.attr("transform", function(d){
return "translate(" + arc.centroid(d) +")";
})
.attr("text-anchor", "middle")
.text(function(d){return d.data});
//======== mouse over/out =========//
var prevColor;
arcs.on("mouseover", function(d){
prevColor = d3.select(this).select("path").attr("fill");
d3.select(this).select("path")
.attr("fill", "black");
})
.on("mouseout", function(d){
d3.select(this).select("path")
.attr("fill", prevColor);
});
http://jsfiddle.net/64vFq/
If I understand you correctly, it looks like you can just change this line:
var arc = d3.svg.arc()
.innerRadius(radius-50)
.outerRadius(radius);
I changed it to this and it produced a decent result:
var arc = d3.svg.arc()
.innerRadius(radius-150)
.outerRadius(radius);
(increase the 50 to make the part the user can mouse over larger; decrease it for the opposite effect)
I found a solution that seems to work pretty well.
All you need to do is create another arc (a bigger one)
var biggerArc = d3.svg.arc().outerRadius(radius+10).innerRadius(radius - 40);
then add it to your mouseover
arcs.on("mouseover", function (d) {
prevColor = d3.select(this).select("path").attr("fill");
d3.select(this).select("path").attr("fill", "black");
d3.select(this).select("path").transition()
.duration(100)
.attr("d", biggerArc);
}).on("mouseout", function (d) {
d3.select(this).select("path").attr("fill", prevColor);
d3.select(this).select("path").transition()
.duration(100)
.attr("d", arc);
});
I have created a donut using multi-arcs and I want to update my donut with new data(arcs).
var width = 300;
var height = 300;
var p = Math.PI * 2;
var vis = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var group = vis.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var arcs = [];
arcs[0] = d3.svg.arc()
.innerRadius(50)
.outerRadius(70)
.startAngle(0)
.endAngle(p - 2);
arcs[1] = d3.svg.arc()
.innerRadius(50)
.outerRadius(70)
.startAngle(p - 2)
.endAngle(p);
group.append("path")
.attr("d", arcs[0])
.attr("class", "first")
.attr("fill", "green");
group.append("path")
.attr("d", arcs[1])
.attr("class", "second")
.attr("fill", "grey");
The new data(arcs - functions) must be in arrays and I have to pass them using the .data(dataset) method.
// New data
var data1 = [];
data1[0] = d3.svg.arc()
.innerRadius(60)
.outerRadius(100)
.startAngle(0)
.endAngle(p - 1);
var data2 = [];
data2[0] = d3.svg.arc()
.innerRadius(60)
.outerRadius(100)
.startAngle(p - 1)
.endAngle(p);
-I can update my donut with the new arcs but the issue that I have is that the transition doesn't work.
-I want just to make the transition work following the steps that I described before.
I know already that if i don't use the .data(dataset) method and I use the .attr("d", arc) instead of .attrTween method then the transition will work.
-However that is not what I want because I want to apply the solution to multi-donuts.
//On click, update with new data
d3.select("p")
.on("click", function () {
//Update all rects
vis.selectAll("path.first")
.data(data1)
.transition()
.duration(1000)
.attrTween("d", function (d) { return d; });
vis.selectAll("path.second")
.data(data2)
.transition()
.duration(1000)
.attrTween("d", function (d) { return d; });
Here is an example, click update to see the changes: example