I try to modify this example. I would like to create two data arrays and merge them using special mergingAr() function instead of data.csv. But it does not work. There is one-colour chart without any data. I can`t find the problem place in the code. So, here it is:
var width = 250,
height = 250,
radius = 230;
var arr1 = [44, 64]; //age
var arr2 = [14106543, 8819342]; //population
function type(d) {
d[1] = +d[1];
return d;
}
function mergingAr(array1, array2)
{
var i, out = [];
for(i=0;i<array1.length;i++)
{
out.push([array1[i],array2[i]]);
}
return out;
}
var data = mergingAr(arr1, arr2);
var color = d3.scale.ordinal()
.range(["#EB7221", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(radius - 100)
.innerRadius(radius - 180);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d[1]; });
var svg = d3.select("#pie").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d[0]); });
g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d[0]; });
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
Thanks all for help!
Your data is there, but your color is wrong. Right now, you have this line setting path color:
.style("fill", function(d) { return color(d[0]); });
The problem is that your data is an object, not an array. (It's transformed by the pie function), so you need to reference the data attribute on the object, and then get the zero index of that array, like so:
.style("fill", function(d) { return color(d.data[0]); });
Related
I am trying to group bars monthwise using D3 so that grouped bars align below the month names on the x axis properly.
the data i am reading is from a csv file as shown below :
Month,Projected Sales/Purchase,Purchase ,Shipped ,Supplier,
JAN-17,310504,552339,259034,A,
JAN-17,610504,252339,659034,B,
FEB-17,910504,552339,259034,A,
FEB-17,210504,252339,659034,B,
FEB-17,810504,252339,659034,C,
This is what i'm trying to achieve http://imgur.com/qxnq5ZJ
Each stacked bar in a month represents a particular supplier. And the supplier count may vary from month to month.
The following is the code that i've tried:
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 50, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand()
.rangeRound([0, width])
.paddingInner(0.05)
.align(0.1);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var z = d3.scaleOrdinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
d3.csv("data.csv", function(d, i, columns) {
for (i = 1, t = 0; i < (columns.length-1); ++i)
t += d[columns[i]] = +d[columns[i]];
d.total = t;
return d;
}, function(error, data) {
if (error) throw error;
var keys = data.columns.slice(1,4);
x.domain(data.map(function(d) { return d.Month; }));
y.domain([0, d3.max(data, function(d) { return d.total; })]);
z.domain(keys);
var stack = d3.stack()
.keys(data.columns.slice(1,4));
var stackedData = stack(data);
g.append("g")
.selectAll("g")
.data(stackedData)
.enter().append("g")
.attr("fill", function(d) { return z(d.key); })
.selectAll("rect")
.data(function(d,i) { console.info(d[i].data.Month);return d; })
.enter().append("g").append("rect")
.attr("x", function(d, i){return i * 75;})
.attr("y", function(d) { return y(d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[1]); })
.attr("width", 50);
g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + 450 + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(null, "s"))
.append("text")
.attr("x", 2)
.attr("y", y(y.ticks().pop()) + 0.5)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start");
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; });
});
</script>
http://imgur.com/eUG56rr is the output for the above code.
I have a bar chart that updates based on the results selected in a drop-down menu. When I change the selcetion, I get negaitve "y" values. It seems that my domain does not get updated with the new data. When I hard code the domain, my "y" are what I expect them to be. Anyone knows why ? Any other other comments (formatting, etc) welcomed.
var new_data;
//Create SVG margins and patting for the interior
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
//Create Scale
var xScale = d3
.scale
.ordinal()
.rangeRoundBands([margin.left, width], .1);
;
var yScale = d3
.scale
.linear()
.range([height, 0])
;
var xAxis = d3
.svg
.axis()
.scale(xScale)
.orient("bottom")
.tickPadding([5])
;
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10)
;
//Create SVG with the above specs
var svg = d3.select("#container")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
;
svg
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
;
svg
.append("g")
.attr("class", "y axis")
.append("text") // just for the title (ticks are automatic)
.attr("transform", "rotate(-90)") // rotate the text!
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("frequency")
;
var temp = svg
.append("g")
.attr("class", "domx")
;
d3.csv("data3.csv", function(error, csv_data) {
// Filter the dataset to only get dept_1
var new_data = csv_data.filter(function(d) {
return d['dept'] == 'dept_1';
});
// function to handle histogram.
function histoGram(new_data){
//Create Scales
xScale
.domain(new_data.map(function(d) {return d.Pos;}))
;
yScale
// .domain([0, d3.max(new_data, function(d) { return d.Value; })])
.domain([0, d3.max(new_data, function(d) { return d.Value; })])
// .domain([0, 20])
;
svg
.select(".x.axis")
.transition()
.duration(1500)
.call(xAxis)
;
svg
.select(".y.axis")
.transition()
.duration(1500)
.call(yAxis)
;
// Data Join
var MyGroups = temp
.selectAll("g")
.data(new_data);
;
var MyGroupsEnter = MyGroups
.enter()
.append("g")
;
//Update
MyGroups
.attr("class", "update")
;
//Enter
MyGroupsEnter
.append("rect")
.attr("class", "enter")
.attr("x", function(d) { return xScale(d.Pos); })
.attr("y", function(d) { return (yScale(d.Value));})
.attr("width", xScale.rangeBand())
.attr("height", function(d) { return (height - yScale(d.Value)); })
.text(function(d) { return d.Value; })
.attr("fill", function(d) {return "rgb(0, 0, 0)";})
.style("fill-opacity", 0.2)
;
MyGroupsEnter
.append("text")
.attr("class", "text")
.text(function(d) { return d.Value; })
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "black")
.attr("text-anchor", "middle")
.attr("x", function(d) { return xScale(d.Pos) + xScale.rangeBand()/2; })
.attr("y", function(d) { return yScale(d.Value) - 10; })
;
//Enter + Update
MyGroups
.transition()
.duration(1500)
.select("rect")
.attr("x", function(d) { return xScale(d.Pos); })
.attr("width", xScale.rangeBand())
.attr("y", function(d) { return (yScale(d.Value));})
.attr("height", function(d) { return (height - yScale(d.Value)); })
.text(function(d) { return d.Value; })
.style("fill-opacity", 1) // set the fill opacity
.attr("fill", function(d) {return "rgb(0, 0, " + (d.Value * 30) + ")";})
;
MyGroups
.transition()
.duration(1500)
.select("text")
.attr("class", "text")
.text(function(d) { return d.Value; })
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "black")
.attr("text-anchor", "middle")
.attr("x", function(d) { return xScale(d.Pos) + xScale.rangeBand()/2; })
.attr("y", function(d) { return yScale(d.Value) - 8; })
;
MyGroups
.exit()
.transition()
.duration(1500)
.remove()
;
}
histoGram(new_data);
var options = ["dept_1","dept_2","dept_3"];
var dropDown = d3
.select("#sel_button")
.append("select")
.attr("name", "options-list")
.attr("id", "id-name");
var options = dropDown
.selectAll("option")
.data(options)
.enter()
.append("option");
options
.text(function (d) { return d; })
.attr("value", function (d) { return d; });
d3.select("#id-name")
.on("change", function() {
var value = d3.select(this).property("value");
var new_data2 = csv_data.filter(function(d) {
return d['dept'] == value;
});
histoGram(new_data2);
});
});
Here is the data:
dept,Pos,Value
dept_1,d1_p1,1
dept_1,d1_p10,10
dept_1,d1_p11,11
dept_1,d1_p12,12
dept_2,d2_p1,1.5
dept_2,d2_p2,3
dept_2,d2_p3,4.5
dept_2,d2_p4,6
dept_2,d2_p5,7.5
dept_2,d2_p6,9
dept_2,d2_p7,10.5
dept_2,d2_p8,12
dept_2,d2_p9,13.5
dept_2,d2_p10,15
dept_2,d2_p11,16.5
dept_2,d2_p12,17.5
dept_2,d2_p13,18.5
dept_3,d3_p1,5
dept_3,d3_p2,7
dept_3,d3_p3,10
Firgured out what was my problem. I hadn't defined the format of the values. The max function was returning the maximum number out of character values (9). I added the following piece of code prior to the domain function and everything now works fines.
csv_data.forEach(function(d) {
d.dept = d.dept;
d.Pos = d.Pos;
d.Value = +d.Value;
});
After plotting a donut chart, I'm trying to add some legend, based on the following example:
http://bl.ocks.org/ZJONSSON/3918369
However, I'm receiving this error:
TypeError: undefined is not an object (evaluating 'n.apply')
I've printed the return of line 131 and all the legend names are printed.
I don't know what's is causing the undefined error print.
This is my main code:
var width = 300,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(colorrange);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(radius - 70);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value;
});
var svg = d3.select("#info").attr("align", "center").append("svg")
.attr("class", "piechart")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.attr("data-legend", function(d) {
return d.data.name;
})
.style("fill", function(d, i) {
return color(i);
});
g.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.text(function(d) {
return d.data.label;
});
legend = svg.append("g")
.attr("class", "legend")
.attr("transform", "translate(50,30)")
.style("font-size", "12px")
.call(d3.legend)
And this is a minimal example:
https://jsfiddle.net/g6vyk7t1/12/
You need to upload the code http://bl.ocks.org/ZJONSSON/3918369#d3.legend.js for the legend in your Javascript (just copy-and-paste it the code, it's the function d3.legend).
I'm trying to add a legend to a d3 scatterplot matrix (using this example as a template: http://bl.ocks.org/mbostock/4063663), and while the scatterplot itself is displaying as expected, I have been unable to successfully add a legend. The code for the plot and one of the attempts at adding a legend are below:
var width = 960,
size = 150,
padding = 19.5;
var x = d3.scale.linear()
.range([padding / 2, size - padding / 2]);
var y = d3.scale.linear()
.range([size - padding / 2, padding / 2]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
var color = d3.scale.category10();
d3.csv(datafilename, function(error, dataset) {
var domainByTrait = {},
traits = d3.keys(dataset[0]).filter(function(d) { return d !== "class"; }),
n = traits.length;
traits.forEach(function(trait) {
domainByTrait[trait] = d3.extent(dataset, function(d) { return d[trait]; });
});
xAxis.tickSize(size * n);
yAxis.tickSize(-size * n);
var brush = d3.svg.brush()
.x(x)
.y(y)
.on("brushstart", brushstart)
.on("brush", brushmove)
.on("brushend", brushend);
var svg = d3.select("#visualizationDiv").append("svg")
.attr("width", size * n + padding)
.attr("height", size * n + padding)
.append("g")
.attr("transform", "translate(" + padding + "," + padding / 2 + ")");
svg.selectAll(".x.axis")
.data(traits)
.enter().append("g")
.attr("class", "x axis")
.attr("transform", function(d, i) { return "translate(" + (n - i - 1) * size + ",0)"; })
.each(function(d) { x.domain(domainByTrait[d]); d3.select(this).call(xAxis); });
svg.selectAll(".y.axis")
.data(traits)
.enter().append("g")
.attr("class", "y axis")
.attr("transform", function(d, i) { return "translate(0," + i * size + ")"; })
.each(function(d) { y.domain(domainByTrait[d]); d3.select(this).call(yAxis); });
var cell = svg.selectAll(".cell")
.data(cross(traits, traits))
.enter().append("g")
.attr("class", "cell")
.attr("transform", function(d) { return "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")"; })
.each(plot);
// Titles for the diagonal.
cell.filter(function(d) { return d.i === d.j; }).append("text")
.attr("x", padding)
.attr("y", padding)
.attr("dy", ".71em")
.text(function(d) { return d.x; });
cell.call(brush);
function plot(p) {
var cell = d3.select(this);
x.domain(domainByTrait[p.x]);
y.domain(domainByTrait[p.y]);
cell.append("rect")
.attr("class", "frame")
.attr("x", padding / 2)
.attr("y", padding / 2)
.attr("width", size - padding)
.attr("height", size - padding);
cell.selectAll("circle")
.data(dataset)
.enter().append("circle")
.attr("cx", function(d) { return x(d[p.x]); })
.attr("cy", function(d) { return y(d[p.y]); })
.attr("r", 3)
.style("fill", function(d) { return color(d.class); });
}
var brushCell;
// Clear the previously-active brush, if any.
function brushstart(p) {
if (brushCell !== this) {
d3.select(brushCell).call(brush.clear());
x.domain(domainByTrait[p.x]);
y.domain(domainByTrait[p.y]);
brushCell = this;
}
}
// Highlight the selected circles.
function brushmove(p) {
var e = brush.extent();
svg.selectAll("circle").classed("hidden", function(d) {
return e[0][0] > d[p.x] || d[p.x] > e[1][0]
|| e[0][1] > d[p.y] || d[p.y] > e[1][1];
});
}
// If the brush is empty, select all circles.
function brushend() {
if (brush.empty()) svg.selectAll(".hidden").classed("hidden", false);
}
function cross(a, b) {
var c = [], n = a.length, m = b.length, i, j;
for (i = -1; ++i < n;) for (j = -1; ++j < m;) c.push({x: a[i], i: i, y: b[j], j: j});
return c;
}
d3.select(self.frameElement).style("height", size * n + padding + 20 + "px");
// add legend
var legend = svg.append("g")
.attr("class", "legend")
.attr("height", 100)
.attr("width", 100)
.attr('transform', 'translate(-20,50)');
legend.selectAll('rect')
.data(dataset)
.enter()
.append("rect")
.attr("x", width - 65)
.attr("y", function(d, i){ return i * 20;})
.attr("width", 10)
.attr("height", 10)
.style("fill", function(d) { return color(d.class); });
legend.selectAll('text')
.data(dataset)
.enter()
.append("text")
.attr("x", width - 52)
.attr("y", function(d, i){ return i * 20 + 9;})
.text(function(d) { return d.class; });
});
Among my other unsuccessful attempts at adding a legend are
var legend = svg.selectAll("g")
.data(dataset)
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 28)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) { return color(d.class); });
legend.append("text")
.attr("x", width - 34)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d.class; });
and
var legend = svg.selectAll('g').data(dataset)
.enter()
.append('g')
.attr("class", "legend");
legend.append("rect")
.attr("x", width - 45)
.attr("y", 25)
.attr("height", 50)
.attr("width", 50)
.each(function(d, i) {
var g = d3.select(this);
g.append("rect")
.attr("x", width - 65)
.attr("y", i*25)
.attr("width", 10)
.attr("height", 10)
.style("fill", function(d) { return color(d.class); });
g.append("text")
.attr("x", width - 50)
.attr("y", i * 25 + 8)
.attr("height",30)
.attr("width",100)
.style("fill", function(d) { return color(d.class); })
.text(function(d) { return d.class; });
all based on examples I've found on the web. None of these approaches seem to be working - I must be missing something here. Any insights or suggestions would be greatly appreciated.
The problem is right at the beginning:
var legend = svg.selectAll('g').data(dataset)
.enter()
.append('g')
.attr("class", "legend");
The selectAll('g') is going to select one of the groups already in your diagram, and then nothing will happen because enter() indicates that everything from there on (including the value that gets saved to the legend variable) only applies to groups that don't exist yet.
I'm pretty sure this legend code is supposed to be run from within its own <g> element. That way, it won't interfere with the rest of your graph.
var legendGroup = svg.append('g')
.attr('class', 'legend')
.attr('transform', /* translate as appropriate */);
var legendEntry = legendGroup.selectAll('g')
.data(dataset);
//create one legend entry for each series in the dataset array
//if that's not what you want, create an array that has one
//value for every entry you want in the legend
legendEntry.enter().append("g")
.attr("class", "legend-entry")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
//shift each entry down by approx 1 line (20px)
legendEntry.append("rect") //add a square to each entry
/* and so on */
Long time lurker 1st time poster. I am trying to display the text value form a CSV file when the relevant segment of pie chart is hovered over. I have the pie chart (thanks to Mike Bostock) and the display when hovering but cant remove it on the mouse out. Any help would be greatly appreciated at this stage.
var width = 960,
height = 600,
radius = Math.min(width, height) / 2.5;
var arc = d3.svg.arc()
.outerRadius(radius + 10)
.innerRadius(radius - 70);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scale.ordinal()
.range(["#0bd0d2", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.Total; });
var pieSlice = svg.selectAll("g.slice");
d3.csv("childcare.csv", function(error, data) {
data.forEach(function(d) {
d.population = +d.population;
});
var arcs = svg.selectAll("g.slice")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
arcs.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.place); })
.on("mouseenter", function(d) {
//console.log("mousein")
arcs.append("text")
.attr("transform", arc.centroid(d))
.attr("dy", ".5em")
.style("text-anchor", "middle")
.style("fill", "blue")
.attr("class", "on")
.text(d.data.place);
})
.on("mouseout", function(d) {
console.log("mouseout")
});
});
You can just save your text and remove it on mouseout:
var text;
var arcs = svg.selectAll("g.slice")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
arcs.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.place); })
.on("mouseenter", function(d) {
//console.log("mousein")
text = arcs.append("text")
.attr("transform", arc.centroid(d))
.attr("dy", ".5em")
.style("text-anchor", "middle")
.style("fill", "blue")
.attr("class", "on")
.text(d.data.place);
})
.on("mouseout", function(d) {
text.remove();
});