Apply D3 tooltip to Donut Multiples - javascript

I have code like this that creates multiple D3 donut multiples.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
svg {
padding: 10px 0 0 10px;
}
.arc {
stroke: #fff;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var radius = 74,
padding = 10;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(radius)
.innerRadius(radius - 30);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "State"; }));
data.forEach(function(d) {
d.ages = color.domain().map(function(name) {
return {name: name, population: +d[name]};
});
});
var legend = d3.select("body").append("svg")
.attr("class", "legend")
.attr("width", radius * 2)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain().slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", ".35em")
.text(function(d) { return d; });
var svg = d3.select("body").selectAll(".pie")
.data(data)
.enter().append("svg")
.attr("class", "pie")
.attr("width", radius * 2)
.attr("height", radius * 2)
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
svg.selectAll(".arc")
.data(function(d) { return pie(d.ages); })
.enter().append("path")
.attr("class", "arc")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.name); });
svg.append("text")
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d.State; });
});
</script>
I am looking for a way to implement the D3 tooltip so that I can see the exact data of each chunk of the donut when I put my cursor over it. I understand that there are other examples of the tooltip on here but none of them have worked with the donut multiples example.
Here is some example data
State,Under 5 Years,5 to 13 Years,14 to 17 Years,18 to 24 Years,25 to 44 Years,45 to 64 Years,65 Years and Over
AL,310504,552339,259034,450818,1231572,1215966,641667
AK,52083,85640,42153,74257,198724,183159,50277
AZ,515910,828669,362642,601943,1804762,1523681,862573
AR,202070,343207,157204,264160,754420,727124,407205
CA,2704659,4499890,2159981,3853788,10604510,8819342,4114496
CO,358280,587154,261701,466194,1464939,1290094,511094
CT,211637,403658,196918,325110,916955,968967,478007
DE,59319,99496,47414,84464,230183,230528,121688
DC,36352,50439,25225,75569,193557,140043,70648
FL,1140516,1938695,925060,1607297,4782119,4746856,3187797
GA,740521,1250460,557860,919876,2846985,2389018,981024
HI,87207,134025,64011,124834,356237,331817,190067
ID,121746,201192,89702,147606,406247,375173,182150
IL,894368,1558919,725973,1311479,3596343,3239173,1575308
IN,443089,780199,361393,605863,1724528,1647881,813839
IA,201321,345409,165883,306398,750505,788485,444554
KS,202529,342134,155822,293114,728166,713663,366706
KY,284601,493536,229927,381394,1179637,1134283,565867
LA,310716,542341,254916,471275,1162463,1128771,540314
ME,71459,133656,69752,112682,331809,397911,199187
MD,371787,651923,316873,543470,1556225,1513754,679565
The D3 doc of this can be found at
http://bl.ocks.org/mbostock/3888852

I'm not sure what you're referring to when you say "the D3 tooltip", because d3 doesn't have any built-in tooltip functionality. That said, there are some good third-party plugins out there for doing tooltips in d3.
d3-tip is one that would work well for what you're trying to do.
You can create a tooltip function to display your population data for each arc like this:
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d) { return d.data.population; })
.direction('s');
Then you can call the function on your svg selection:
svg.call(tip);
Finally, you can use mouse event listeners on your arcs to show and hide the tooltip:
svg.selectAll(".arc")
.data(function(d) { return pie(d.ages); })
.enter().append("path")
.attr("class", "arc")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.name); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
Here's a PLUNK with a working example.
You can also check up on the d3-tip documentation here.

I too got the same TypeError while debugging my javascript code using d3js while adding tooltip for my barcharts.
bars.append('rect')
.attr('y', maxHeight)
.attr('height', 0)
.attr('width', function (d) { return x.rangeBand(d) - 1; })
.attr('class', 'bar')
.transition().duration(1500)
.attr('y', function (d, i) { return y(d.y); })
.attr('height', function (d, i) { return maxHeight - y(d.y); });
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
In the above code i used ".on('mouseover', tip.show)" on "bars.append()".This is wrong usage.
Later, i found that ".on('mouseover', tip.show)" should be applied on function ".select('rect') or .selectall('rect')".
Now below snippet is working correctly for my application.
bars.append('rect')
.attr('y', maxHeight)
.attr('height', 0)
.attr('width', function (d) { return x.rangeBand(d) - 1; })
.attr('class', 'bar')
.transition().duration(1500)
.attr('y', function (d, i) { return y(d.y); })
.attr('height', function (d, i) { return maxHeight - y(d.y); });
bars.select('rect')
.on('mouseover', tip.show)
.on('mouseout', tip.hide);

Related

How to increase xaxis in d3js v4 bar chart?

I'm trying to learn how to code with the d3.js. I am trying to make a simple bar graph with this json file. I got stuck trying to format the xaxis in the file. I've tried looking at the d3.js API and I am still lost. I would be very grateful for any help.
Here is the result screenshot
This image is for shorter xaxis points
This output looks good
This output results when more data points in xaxis
Can anyone suggest me how to increase the xaxis length based on data point coiming to xaxis
Here is my code
.bar {
fill: #F39473;
}
.highlight {
fill: orange;
}
<!doctype html>
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg width="900" height="500"></svg>
<script>
var svg = d3.select("svg"),
top= 20, right= 20, bottom= 50, left= 70,
margin = 200,
width = svg.attr("width") - margin,
height = svg.attr("height") - margin;
var x = d3.scaleBand().range([0, width]).padding(0.4),
y = d3.scaleLinear().range([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + 100 + "," + 100 + ")");
d3.json("data.php", function(error, data) {
data.forEach(function(d) {
d.date = (d.date);
d.count = +d.count;
})
x.domain(data.map(function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.count; })]);
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.append("text")
.attr("y", height - 250)
.attr("x", width - 100)
.attr("text-anchor", "middle")
.attr("stroke", "black")
.text("date");
g.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("count");
g.append("g")
.call(d3.axisLeft(y).tickFormat(function(d){
return d;
}).ticks(10))
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.on("mouseover", onMouseOver) //Add listener for the mouseover event
.on("mouseout", onMouseOut) //Add listener for the mouseout event
.attr("x", function(d) { return x(d.date); })
.attr("y", function(d) { return y(d.count); })
.attr("width", x.bandwidth())
.transition()
.ease(d3.easeLinear)
.duration(400)
.delay(function (d, i) {
return i * 50;
})
.attr("height", function(d) { return height - y(d.count); });
});
//mouseover event handler function
function onMouseOver(d, i) {
d3.select(this).attr('class', 'highlight');
d3.select(this)
.transition() // adds animation
.duration(400)
.attr('width', x.bandwidth() + 5)
.attr("y", function(d) { return y(d.count) - 10; })
.attr("height", function(d) { return height - y(d.count) + 10; });
g.append("text")
.attr('class', 'val')
.attr('x', function() {
return x(d.date);
})
.attr('y', function() {
return y(d.count) - 15;
})
.text(function() {
return [ +d.date, +d.count]; // Value of the text
});
}
//mouseout event handler function
function onMouseOut(d, i) {
// use the text label class to remove label on mouseout
d3.select(this).attr('class', 'bar');
d3.select(this)
.transition() // adds animation
.duration(400)
.attr('width', x.bandwidth())
.attr("y", function(d) { return y(d.count); })
.attr("height", function(d) { return height - y(d.count); });
d3.selectAll('.val')
.remove()
}
</script>
</body>
</html>
I would use d3.nest() and make a rollup out of the key value you'd want to count (d.date in this case) and use this count value in your width variable.
Here's a plunker I made using this method.

Embed a svg shape in d3tip tooltip

I'm working with the popular tip library d3-tip.js, an example of it can be found here. Typically, the tip contains text that is defined dynamically like this:
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
html = "";
html += "<strong>Frequency:</strong> <span style='color:red'>" + d.frequency + "</span>";
return html;
})
However, lets say I have a legend like this:
var legend = g.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(keys.slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", z);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) { return d; });
I would like to somehow append a small svg rect inside the d3 toolip. This way when you hover over a graph with different classes (i.e. grouped bar chart) the tooltip will have a svg rect of matching color in addition to the html text. Ideally by using an existing legend variable, as seen above.
If it's not possible, then just explain why and I can accept that as an answer as well.
For clarity, here is a rough idea of what I'm going for visually:
It's easy to create an SVG inside a d3.tip tooltip. Actually, you just have to use the same logic of any other D3 created SVG: select the container and append the SVG to it.
In the following demo, in your var tip, I'll create an empty div with a given ID. In this case, the div has an ID named mySVGtooltip:
var tool_tip = d3.tip()
.attr("class", "d3-tip")
.offset([20, 40])
.html("<div id='mySVGtooltip'></div>");
After that, it's just a matter of, inside the mouseover event, selecting that div by ID and appending the SVG to it:
var legendSVG = d3.select("#mySVGtooltip")
.append("svg")
.attr("width", 160)
.attr("height", 50);
Here is the demo, hover over the circles:
var svg = d3.select("body")
.append("svg")
.attr("width", 300)
.attr("height", 300);
var tool_tip = d3.tip()
.attr("class", "d3-tip")
.offset([20, 40])
.html("<div id='mySVGtooltip'></div>");
svg.call(tool_tip);
var data = [20, 10, 30, 15, 35];
var circles = svg.selectAll(null)
.data(data)
.enter()
.append("circle");
circles.attr("cy", 50)
.attr("cx", function(d, i) {
return 30 + 55 * i
})
.attr("r", function(d) {
return d
})
.attr("fill", "lightgreen")
.attr("stroke", "dimgray")
.on('mouseover', function(d) {
tool_tip.show();
var legendSVG = d3.select("#mySVGtooltip")
.append("svg")
.attr("width", 160)
.attr("height", 50);
var legend = legendSVG.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10);
legend.append("text")
.attr("x", 80)
.attr("text-anchor", "middle")
.attr("y", 16)
.attr("font-size", 14)
.text("Age Group:");
legend.append("rect")
.attr("y", 25)
.attr("x", 10)
.attr("width", 19)
.attr("height", 19)
.attr("fill", "goldenrod");
legend.append("text")
.attr("x", 35)
.attr("y", 40)
.text(function() {
return d + " years and over";
});
})
.on('mouseout', tool_tip.hide);
.d3-tip {
line-height: 1;
background: gainsboro;
border: 1px solid black;
font-size: 12px;
}
p {
font-family: Helvetica;
}
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
Notice that, in this very simple demo, I'm using the datum (d) passed to the anonymous function by the mouseover event. I'm seeing in your question that you have your own data. Thus, change the code in my demo accordingly.

Access x property on svg element in d3

I'm trying to implement a transform wherein an element moves a couple of pixels to the left by several pixels when a user mouses over it. How can I access the x property of a bar so I can pass in a relative position?
Here's my code; it's pretty standard except that I don't have an axis on the bar chart.
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h)
var tip = d3.tip()
.attr('class','d3-tip')
.html(function(d, i) {
return "<span style='color:red'>" + d.Word +"</span>";
});
svg.selectAll("rect")
.data(words)
.enter()
.append("rect")
.attr("x", function(d, i) {
return i*(w/dataset.length);
})
.attr("y", function(d){
return (h-(800)
);
})
.attr("width", 40)
.attr("class", "rectangle")
.attr("id", function(d, i){return "rect"+i})
.attr("height", function(d, i){
// var barheight = d.Dispersion*100
return "200px"
})
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
svg.call(tip);
$('.rectangle').mouseover(function () {
var rect = d3.select("#"+this.id)
rect.transition()
.duration(500)
.attr("width", 58)
.duration(500)
.attr("height", 220+"px")
.style("fill", function(d, i) {return d.color});
.attr("x", 50) //this goes to a particular position in the parent node
});

Interactive spider or radar chart using d3

I'm looking for a spider chart/radar chart for HTML/javascript that is also interactive. I would like the user to move all the endpoints and store the end result.
I have been searching for a while and although I have found some nice chart components all of them where static and could only updated using code.
Take a look at this.
This is what can be achieved with this alangrafu's code:
The example is really not interactive in the sense that you described, but it is interactive in other ways, and nothing stops you to implement the interactivity you desire, having the code from example as a good starting point.
An Interactive D3 Radar chart example:
index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Radar chart</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="RadarChart.js"></script>
<style>
body {
overflow: hidden;
margin: 0;
font-size: 14px;
font-family: "Helvetica Neue", Helvetica;
}
#chart {
position: absolute;
top: 50px;
left: 100px;
}
</style>
</head>
<body>
<div id="body">
<div id="chart"></div>
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
RadarChart.js
var RadarChart = {
draw: function(id, d, options){
var cfg = {
radius: 5,
w: 600,
h: 600,
factor: 1,
factorLegend: .85,
levels: 3,
maxValue: 0,
radians: 2 * Math.PI,
opacityArea: 0.5,
ToRight: 5,
TranslateX: 80,
TranslateY: 30,
ExtraWidthX: 100,
ExtraWidthY: 100,
color: d3.scale.category10()
};
if('undefined' !== typeof options){
for(var i in options){
if('undefined' !== typeof options[i]){
cfg[i] = options[i];
}
}
}
cfg.maxValue = Math.max(cfg.maxValue, d3.max(d, function(i){return d3.max(i.map(function(o){return o.value;}))}));
var allAxis = (d[0].map(function(i, j){return i.axis}));
var total = allAxis.length;
var radius = cfg.factor*Math.min(cfg.w/2, cfg.h/2);
var Format = d3.format('%');
d3.select(id).select("svg").remove();
var g = d3.select(id)
.append("svg")
.attr("width", cfg.w+cfg.ExtraWidthX)
.attr("height", cfg.h+cfg.ExtraWidthY)
.append("g")
.attr("transform", "translate(" + cfg.TranslateX + "," + cfg.TranslateY + ")");
;
var tooltip;
//Circular segments
for(var j=0; j<cfg.levels-1; j++){
var levelFactor = cfg.factor*radius*((j+1)/cfg.levels);
g.selectAll(".levels")
.data(allAxis)
.enter()
.append("svg:line")
.attr("x1", function(d, i){return levelFactor*(1-cfg.factor*Math.sin(i*cfg.radians/total));})
.attr("y1", function(d, i){return levelFactor*(1-cfg.factor*Math.cos(i*cfg.radians/total));})
.attr("x2", function(d, i){return levelFactor*(1-cfg.factor*Math.sin((i+1)*cfg.radians/total));})
.attr("y2", function(d, i){return levelFactor*(1-cfg.factor*Math.cos((i+1)*cfg.radians/total));})
.attr("class", "line")
.style("stroke", "grey")
.style("stroke-opacity", "0.75")
.style("stroke-width", "0.3px")
.attr("transform", "translate(" + (cfg.w/2-levelFactor) + ", " + (cfg.h/2-levelFactor) + ")");
}
//Text indicating at what % each level is
for(var j=0; j<cfg.levels; j++){
var levelFactor = cfg.factor*radius*((j+1)/cfg.levels);
g.selectAll(".levels")
.data([1]) //dummy data
.enter()
.append("svg:text")
.attr("x", function(d){return levelFactor*(1-cfg.factor*Math.sin(0));})
.attr("y", function(d){return levelFactor*(1-cfg.factor*Math.cos(0));})
.attr("class", "legend")
.style("font-family", "sans-serif")
.style("font-size", "10px")
.attr("transform", "translate(" + (cfg.w/2-levelFactor + cfg.ToRight) + ", " + (cfg.h/2-levelFactor) + ")")
.attr("fill", "#737373")
.text(Format((j+1)*cfg.maxValue/cfg.levels));
}
series = 0;
var axis = g.selectAll(".axis")
.data(allAxis)
.enter()
.append("g")
.attr("class", "axis");
axis.append("line")
.attr("x1", cfg.w/2)
.attr("y1", cfg.h/2)
.attr("x2", function(d, i){return cfg.w/2*(1-cfg.factor*Math.sin(i*cfg.radians/total));})
.attr("y2", function(d, i){return cfg.h/2*(1-cfg.factor*Math.cos(i*cfg.radians/total));})
.attr("class", "line")
.style("stroke", "grey")
.style("stroke-width", "1px");
axis.append("text")
.attr("class", "legend")
.text(function(d){return d})
.style("font-family", "sans-serif")
.style("font-size", "11px")
.attr("text-anchor", "middle")
.attr("dy", "1.5em")
.attr("transform", function(d, i){return "translate(0, -10)"})
.attr("x", function(d, i){return cfg.w/2*(1-cfg.factorLegend*Math.sin(i*cfg.radians/total))-60*Math.sin(i*cfg.radians/total);})
.attr("y", function(d, i){return cfg.h/2*(1-Math.cos(i*cfg.radians/total))-20*Math.cos(i*cfg.radians/total);});
d.forEach(function(y, x){
dataValues = [];
g.selectAll(".nodes")
.data(y, function(j, i){
dataValues.push([
cfg.w/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.sin(i*cfg.radians/total)),
cfg.h/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.cos(i*cfg.radians/total))
]);
});
dataValues.push(dataValues[0]);
g.selectAll(".area")
.data([dataValues])
.enter()
.append("polygon")
.attr("class", "radar-chart-serie"+series)
.style("stroke-width", "2px")
.style("stroke", cfg.color(series))
.attr("points",function(d) {
var str="";
for(var pti=0;pti<d.length;pti++){
str=str+d[pti][0]+","+d[pti][2]+" ";
}
return str;
})
.style("fill", function(j, i){return cfg.color(series)})
.style("fill-opacity", cfg.opacityArea)
.on('mouseover', function (d){
z = "polygon."+d3.select(this).attr("class");
g.selectAll("polygon")
.transition(200)
.style("fill-opacity", 0.1);
g.selectAll(z)
.transition(200)
.style("fill-opacity", .7);
})
.on('mouseout', function(){
g.selectAll("polygon")
.transition(200)
.style("fill-opacity", cfg.opacityArea);
});
series++;
});
series=0;
d.forEach(function(y, x){
g.selectAll(".nodes")
.data(y).enter()
.append("svg:circle")
.attr("class", "radar-chart-serie"+series)
.attr('r', cfg.radius)
.attr("alt", function(j){return Math.max(j.value, 0)})
.attr("cx", function(j, i){
dataValues.push([
cfg.w/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.sin(i*cfg.radians/total)),
cfg.h/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.cos(i*cfg.radians/total))
]);
return cfg.w/2*(1-(Math.max(j.value, 0)/cfg.maxValue)*cfg.factor*Math.sin(i*cfg.radians/total));
})
.attr("cy", function(j, i){
return cfg.h/2*(1-(Math.max(j.value, 0)/cfg.maxValue)*cfg.factor*Math.cos(i*cfg.radians/total));
})
.attr("data-id", function(j){return j.axis})
.style("fill", cfg.color(series)).style("fill-opacity", .9)
.on('mouseover', function (d){
newX = parseFloat(d3.select(this).attr('cx')) - 10;
newY = parseFloat(d3.select(this).attr('cy')) - 5;
tooltip
.attr('x', newX)
.attr('y', newY)
.text(Format(d.value))
.transition(200)
.style('opacity', 1);
z = "polygon."+d3.select(this).attr("class");
g.selectAll("polygon")
.transition(200)
.style("fill-opacity", 0.1);
g.selectAll(z)
.transition(200)
.style("fill-opacity", .7);
})
.on('mouseout', function(){
tooltip
.transition(200)
.style('opacity', 0);
g.selectAll("polygon")
.transition(200)
.style("fill-opacity", cfg.opacityArea);
})
.append("svg:title")
.text(function(j){return Math.max(j.value, 0)});
series++;
});
//Tooltip
tooltip = g.append('text')
.style('opacity', 0)
.style('font-family', 'sans-serif')
.style('font-size', '13px');
}
};
Script.js
var w = 500,
h = 500;
var colorscale = d3.scale.category10();
//Legend titles
var LegendOptions = ['Smartphone','Tablet'];
//Data
var d = [
[
{axis:"Email",value:0.59},
{axis:"Social Networks",value:0.56},
{axis:"Internet Banking",value:0.42},
{axis:"News Sportsites",value:0.34},
{axis:"Search Engine",value:0.48},
{axis:"View Shopping sites",value:0.14},
{axis:"Paying Online",value:0.11},
{axis:"Buy Online",value:0.05},
{axis:"Stream Music",value:0.07},
{axis:"Online Gaming",value:0.12},
{axis:"Navigation",value:0.27},
{axis:"App connected to TV program",value:0.03},
{axis:"Offline Gaming",value:0.12},
{axis:"Photo Video",value:0.4},
{axis:"Reading",value:0.03},
{axis:"Listen Music",value:0.22},
{axis:"Watch TV",value:0.03},
{axis:"TV Movies Streaming",value:0.03},
{axis:"Listen Radio",value:0.07},
{axis:"Sending Money",value:0.18},
{axis:"Other",value:0.07},
{axis:"Use less Once week",value:0.08}
],[
{axis:"Email",value:0.48},
{axis:"Social Networks",value:0.41},
{axis:"Internet Banking",value:0.27},
{axis:"News Sportsites",value:0.28},
{axis:"Search Engine",value:0.46},
{axis:"View Shopping sites",value:0.29},
{axis:"Paying Online",value:0.11},
{axis:"Buy Online",value:0.14},
{axis:"Stream Music",value:0.05},
{axis:"Online Gaming",value:0.19},
{axis:"Navigation",value:0.14},
{axis:"App connected to TV program",value:0.06},
{axis:"Offline Gaming",value:0.24},
{axis:"Photo Video",value:0.17},
{axis:"Reading",value:0.15},
{axis:"Listen Music",value:0.12},
{axis:"Watch TV",value:0.1},
{axis:"TV Movies Streaming",value:0.14},
{axis:"Listen Radio",value:0.06},
{axis:"Sending Money",value:0.16},
{axis:"Other",value:0.07},
{axis:"Use less Once week",value:0.17}
]
];
//Options for the Radar chart, other than default
var mycfg = {
w: w,
h: h,
maxValue: 0.6,
levels: 6,
ExtraWidthX: 300
}
//Call function to draw the Radar chart
//Will expect that data is in %'s
RadarChart.draw("#chart", d, mycfg);
////////////////////////////////////////////
/////////// Initiate legend ////////////////
////////////////////////////////////////////
var svg = d3.select('#body')
.selectAll('svg')
.append('svg')
.attr("width", w+300)
.attr("height", h)
//Create the title for the legend
var text = svg.append("text")
.attr("class", "title")
.attr('transform', 'translate(90,0)')
.attr("x", w - 70)
.attr("y", 10)
.attr("font-size", "12px")
.attr("fill", "#404040")
.text("What % of owners use a specific service in a week");
//Initiate Legend
var legend = svg.append("g")
.attr("class", "legend")
.attr("height", 100)
.attr("width", 200)
.attr('transform', 'translate(90,20)')
;
//Create colour squares
legend.selectAll('rect')
.data(LegendOptions)
.enter()
.append("rect")
.attr("x", w - 65)
.attr("y", function(d, i){ return i * 20;})
.attr("width", 10)
.attr("height", 10)
.style("fill", function(d, i){ return colorscale(i);})
;
//Create text next to squares
legend.selectAll('text')
.data(LegendOptions)
.enter()
.append("text")
.attr("x", w - 52)
.attr("y", function(d, i){ return i * 20 + 9;})
.attr("font-size", "11px")
.attr("fill", "#737373")
.text(function(d) { return d; })
;
Live Example: http://bl.ocks.org/nbremer/6506614
Still looking? Check out this project on github, I think that is exactly what you are looking for:
https://github.com/jmstriegel/jquery.spidergraph
Demo: http://www.jqueryrain.com/?jhRGLHlE
I have been looking for such a library on my own for a long time and came across your post. Did you find another solution as well?

D3: Substituting d3.svg.diagonal() with d3.svg.line()

I have implemented the following graph with the edges rendered with d3.svg.diagonal(). However, when I try substituting the diagonal with d3.svg.line(), it doesn't appear to pull the target and source data. What am I missing? Is there something I don't understand about d3.svg.line?
The following is the code I am referring to, followed by the full code:
var line = d3.svg.line()
.x(function(d) { return d.lx; })
.y(function(d) { return d.ly; });
...
var link= svg.selectAll("path")
.data(links)
.enter().append("path")
.attr("d",d3.svg.diagonal())
.attr("class", ".link")
.attr("stroke", "black")
.attr("stroke-width", "2px")
.attr("shape-rendering", "auto")
.attr("fill", "none");
The entire code:
var margin = {top: 20, right: 20, bottom: 20, left: 20},
width =1500,
height = 1500,
diameter = Math.min(width, height),
radius = diameter / 2;
var balloon = d3.layout.balloon()
.size([width, height])
.value(function(d) { return d.size; })
.gap(50)
var line = d3.svg.line()
.x(function(d) { return d.lx; })
.y(function(d) { return d.ly; });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + (margin.left + radius) + "," + (margin.top + radius) + ")")
root = "flare.json";
root.y0 = height / 2;
root.x0 = width / 2;
d3.json("flare.json", function(root) {
var nodes = balloon.nodes(root),
links = balloon.links(nodes);
var link= svg.selectAll("path")
.data(links)
.enter().append("path")
.attr("d",d3.svg.diagonal())
.attr("class", ".link")
.attr("stroke", "black")
.attr("stroke-width", "2px")
.attr("shape-rendering", "auto")
.attr("fill", "none");
var node = svg.selectAll("g.node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node");
node.append("circle")
.attr("r", function(d) { return d.r; })
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
node.append("text")
.attr("dx", function(d) { return d.x })
.attr("dy", function(d) { return d.y })
.attr("font-size", "5px")
.attr("fill", "white")
.style("text-anchor", function(d) { return d.children ? "middle" : "middle"; })
.text(function(d) { return d.name; })
});
A comparison of how the d attribute of the svg disappears when using "line."
Question is quite dated, but since I don't see an answer and someone might face the same problem, here it is.
The reason why simple replacement of diagonal with line is not working is because d3.svg.line and d3.svg.diagonal return different results:
d3.svg.diagonal returns function that accepts datum and its index and transforms it to path using projection. In other words diagonal.projection determines how the function will get points' coordinates from supplied datum.
d3.svg.line returns function that accepts an array of points of the line and transforms it to path. Methods line.x and line.y determine how coordinates of the point retreived from the single element of supplied array
D3 SVG-Shapes reference
SVG Paths and D3.js
So you can not use result of the d3.svg.line directly in d3 selections (at least when you want to draw multiple lines).
You need to wrap it in another function like this:
var line = d3.svg.line()
.x( function(point) { return point.lx; })
.y( function(point) { return point.ly; });
function lineData(d){
// i'm assuming here that supplied datum
// is a link between 'source' and 'target'
var points = [
{lx: d.source.x, ly: d.source.y},
{lx: d.target.x, ly: d.target.y}
];
return line(points);
}
// usage:
var link= svg.selectAll("path")
.data(links)
.enter().append("path")
.attr("d",lineData)
.attr("class", ".link")
.attr("stroke", "black")
.attr("stroke-width", "2px")
.attr("shape-rendering", "auto")
.attr("fill", "none");
Here's working version of jsFiddle mobeets posted: jsFiddle
I had the same problem...There's a jsFiddle here.
Note that changing line to diagonal will make it work.
Perhaps encapsulating the diagonal function and editing its parameters could work for you:
var diagonal = d3.svg.diagonal();
var new_diagonal = function (obj, a, b) {
//Here you may change the reference a bit.
var nobj = {
source : {
x: obj.source.x,
y: obj.source.y
},
target : {
x: obj.target.x,
y: obj.target.y
}
}
return diagonal.apply(this, [nobj, a, b]);
}
var link= svg.selectAll("path")
.data(links)
.enter().append("path")
.attr("d",new_diagonal)
.attr("class", ".link")
.attr("stroke", "black")
.attr("stroke-width", "2px")
.attr("shape-rendering", "auto")
.attr("fill", "none");
Just set the d attribute of link to line:
.attr("d", line)

Categories

Resources