var text=["level1","level2","level3"]
var color=['blue','black','green']
var legend = svg.append("g")
.attr("class", "legend")
.attr("id","ad")
.attr('transform', 'translate(210,40)');
legend.selectAll('#ad')
.data(text)
.enter()
.append("rect")
.attr("x", function(d, i){ return i * 100;})
.attr("y", height)
.attr("width", 10)
.attr("height", 10)
.style("fill",function(d,i){return color(i);});
legend.selectAll('text')
.data(text)
.enter()
.append("text")
.attr("x", function(d, i){ return i * 100 + 15;})
.attr("y",height+10)
.attr("class","leg_txt_font")
.text(function(d,i){ return text[i];});
i have tried above code to set the legend.,how to make legend text as clickable in d3.js
i have to set legend text as clickable..if i click the legend text means just need to show the alert message
You just need to use on("click", function(){ ... }):
selection.on("click", function(d){
alert(d)
});
In the snippet bellow, click on the legend to get the alert:
var text=["level1","level2","level3"];
var color=['blue','black','green'];
var svg = d3.select("body")
.append("svg")
.attr("width", 400)
.attr("height", 400);
var legend = svg.append("g")
.attr("class", "legend")
.attr("id","ad")
.attr('transform', 'translate(40,40)');
var rects = legend.selectAll('#ad')
.data(text)
.enter()
.append("rect")
.attr("x", function(d, i){ return i * 100;})
.attr("y", 50)
.attr("width", 10)
.attr("height", 10)
.style("fill",function(d,i){return color[i];});
var texts = legend.selectAll('text')
.data(text)
.enter()
.append("text")
.attr("x", function(d, i){ return i * 100 + 15;})
.attr("y",60)
.attr("class","leg_txt_font")
.text(function(d,i){ return text[i];})
texts.on("click", function(d){
alert(d)
});
text {
cursor: pointer;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
Related
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.
I would love to implement a dropdown filter in my visualisation that allows me to filter by endorsed president. However, being very new to d3, I am really struggling. I have tried to implement it using code I have found elsewhere but to no avail.
var dataPath = "data/p.csv";
var dataPath2 = "data/e.csv";
var field1=[];
var field2=[];
d3.csv(dataPath2,function(data){
data.map(function(d){
field1.push(d.year);
field2.push(d.publication);
})
//called after the AJAX is success
console.log("field1",field1);
console.log("field2",field2);
console.log("field1",field1[0]);
var myData = data;
var margin = 150,
width = 1000 - margin,
height = 2000 - margin;
/*
* value accessor - returns the value to encode for a given data object.
* scale - maps value to a visual display encoding, such as a pixel position.
* map function - maps from data value to display value
* axis - sets up axis
*/
// setup x
var yValue = function(d) { return d.publication;}, // data -> value
yScale = d3.scale.ordinal().domain(field2).rangePoints([height, margin]); // value -> display
yMap = function(d) { return yScale(yValue(d));}, // data -> display
yAxis = d3.svg.axis().scale(yScale).orient("left");
// setup y
var xValue = function(d) { return d.year;}, // data -> value
xExtent = d3.extent(data, function(d) {
return d.year;
});
xScale = d3.scale.linear().domain(xExtent).range([0,width-200]), // value -> display
xMap = function(d) { return xScale(xValue(d));}, // data -> display
xAxis = d3.svg.axis().scale(xScale).orient("bottom");
//
//
// // setup fill color
var cValue = function(d) { return d.endorsed;},
color = d3.scale.category10();
//
// // add the graph canvas to the body of the webpage
var svg = d3.select("body").append("svg")
.attr("width", width + margin)
.attr("height", height + margin)
.append("g")
.attr("transform", "translate(150)");
// add the tooltip area to the webpage
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// x-axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis
.ticks(12))
.append("text")
.attr("class", "label")
.attr("x", width-200)
.attr("y", -6)
.style("text-anchor", "end")
.text("Year");
//
// // y-axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis
.ticks(50))
.append("text")
.attr("class", "label")
// .attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Publication");
// draw dots
svg.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 4)
.attr("x", width - 10)
.attr("y", 95)
.attr("cx", xMap )
.attr("cy", yMap)
.style("fill", function(d) { return color(cValue(d));})
// if (d.endorsed == "Clinton") { return "red"}
// else {return "black"}; })
.on("mouseover", function(d) {
tooltip.transition()
.duration(1000)
.style("opacity", .9);
tooltip.html( d.endorsed
)
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(1000)
.style("opacity", 0);
});
// draw legend
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
// draw legend colored rectangles
legend.append("rect")
.attr("x", width - 10)
.attr("y", 95)
.attr("width", 10)
.attr("height", 10)
.style("fill", color);
// draw legend text
legend.append("text")
.attr("x", width - 24)
.attr("y", 100)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d;})
});
I had a similar requirement that I was able to solve with help of others, but you are going to need more than just d3. Take a look at using JQuery to create dropdown options, and you can filter your data based on selections.
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
});
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);
I have used d3 to create a pie chart. It works nicely, but, when the values of two elements' data are equal, it's showing the same color. How can I fix this problem?
function graph_pie_value(data, id, height, width){
d3.select(id).selectAll("svg").remove();
var radius = Math.min(width, height)/2;
var color = d3.scale.category20c();
var pie = d3.layout.pie()
.sort(null)
.value(function(d){return d.value;});
var arc = d3.svg.arc()
.outerRadius(radius-75)
.innerRadius(0);
var svg = d3.select(id).append("svg")
.attr("height", height)
.attr("width", width)
.append("g")
.attr("transform", "translate("+width/2+","+height/2+")");
svg.append("text").attr("class", "title_text").attr("x", 0)
.attr("y", -height/6*2).style("font-size", "14px").style("font-weight", 600)
.style("z-index", "19")
.style("text-anchor", "middle")
.text("Market Participation Value");
var totalValue=d3.nest()
.rollup(function(d){
return d3.sum(d,function(d){return +d.value;});
})
.entries(data);
data.forEach(function(d){
d.value = +d.value;
d.percent = +(d.value/totalValue*100);
});
var g = svg.selectAll(".arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.attr("fill", function(d){return color(d.value);});
console.log(pie);
g.append("text")
.attr("transform", function(d){
var c = arc.centroid(d);
var x = c[0];
var y = c[1];
var h = Math.sqrt(x*x+y*y);
return "translate("+(x/h*(radius-30))+","+(y/h*(radius-30))+")";
})
.attr("dy", "0.35em")
.attr("class", "percent")
.style("text-anchor", "middle")
.text(function(d){return d.data.percent.toFixed(2)+"%";});
g.append("path")
.style("fill", "none")
.style("stroke", "black")
.attr("d", function(d)
{
var c = arc.centroid(d);
var x = c[0];
var y = c[1];
var h = Math.sqrt(x*x+y*y);
return "M"+(x/h*(radius-73))+","+(y/h*(radius-73))+"L"+(x/h*(radius-50))+","+(y/h*(radius-50));
});
var legend = svg.selectAll(".legend")
.data(data)
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate("+(150-width+i*60)+"," + (height-70) + ")"; });
legend.append("rect")
.attr("x", width/2-150)
.attr("y", 50-height/2)
.attr("width", 12)
.attr("height", 12)
.style("fill", function(d){return color(d.value)});
legend
.append("text")
.attr("class", "legend")
.attr("x", width/2-130)
.attr("y", 60-height/2)
.attr("dy", ".10em")
.style("text-anchor", "start")
.text(function(d) { return d.symbol; });
return;
}
Here is the data format:
var data = [
{"symbol":"MSFT","value":14262751},
{"symbol":"CSCO","value":12004177}
]
It creates no problem in arc color, but when these two values are equal...
var data = [
{"symbol":"MSFT","value":14262751},
{"symbol":"CSCO","value":14262751}
]
...then the pie chart shows the same arc color.
The reason that when two values are equal, their corresponding slices have the same color is because you are setting the color based on value:
g.append("path")
.attr("d", arc)
.attr("fill", function(d){return color(d.value);});
Instead, set the color based on the index i of the data (which D3 also passes the callback function in this situation), like this:
g.append("path")
.attr("d", arc)
.attr("fill", function(d, i){return color(i);});
This will give you a pie chart with multiple colors, even if the slices have the same value: