I am trying to create the image above using d3
http://jsfiddle.net/Spwizard/LBzx7/1/
var dataset = {
hddrives: [20301672, 9408258, 2147483, 21474836, 35622,32210000],
};
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#2DA7E2"]);
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(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 path = svg.selectAll("path")
.data(pie(dataset.hddrives))
.enter().append("path")
.attr("class", "arc")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
svg.append("text")
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("class", "inside")
.text(function(d) { return '56%'; });
svg.append("text")
.attr("dy", "2em")
.style("text-anchor", "middle")
.attr("class", "data")
.text(function(d) { return 'some text'; });
Im struggling to see how to deal with the background color of the inner circle and dealing with the space left for storage
Thanks
To get a "background", you can add another circle with the respective fill colour. To deal with the free space, you can selectively set the opacity of one of the segments to 0. In your example, I've done that for the last slice:
.style("opacity", function(d, i) { return i == dataset.hddrives.length - 1 ? 0 : 1; })
Complete example (provided by OP) here.
Just append text:
svg.append("text")
.attr("text-anchor", "middle")
.attr('font-size', '20px')
.attr('y', '5')
.text(dataset.hddrives + "%");
Related
I have this code, which creates a horizontal bar chart, and it fits nicely to any screen width , but only when the document loads or reload. When I rotate my mobile to landscape mode it does not re-render again according to the new dimensions of the screen, despite I tried to use a addEventLisenet for resize event.
I'll leave a running snippet of my code so that you can see what I am doing wrong.
Thanks a lot for the help.
var data = [72,70,65,58,51,50,21,15,13]
var categoryData = ["International assignment allowance and benefits.","Tax and social security cost.","Relocation costs.","Prepared at start of assigment.","Assignee-specific data.","Vendor fees.","Incentive compensation (projected).","Employee benefit plan contributions and deduction.","They are rough calculations."/*"They are detailed and precise"/*,"General data (not assignee-specific)","Updated annually","Updated for change in assignement policy","Updated for approved policy exceptions"*/]
var width = $(window).width(),
barHeight = 20,
margin = {left:15,top:15,right:15,bottom:15}
var widthScale = d3.scaleLinear()
.domain(d3.extent(data,function(d){return d }))
.range([50, width - 40]);
var svg = d3.select("body")
.append("svg")
.attr("width", width - margin.left - margin.right)
.attr("height"," 100vh")
.attr("id","SVGCanvas")
var mainTitle = svg.append("text")
.attr("class","mainTitle")
.html("Which of the following statements describe your")
.attr("transform","translate(5,60)")
.attr("font-weight","bold")
var mainTitle2 = svg.append("text")
var mainTitle2 = svg.append("text")
.attr("class","mainTitle2")
.html("approach to cost estimates? (Select all that apply.)")
.attr("transform","translate(5,78)")
.attr("font-weight","bold")
.style("float","left")
var mainBarG = svg.append("g")
.attr("class","mainBarG")
.attr("transform","translate(5,142)")
var g = mainBarG.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("class","bGroup")
.attr("transform", function (d, i) {
return "translate(0," + ((i * barHeight*3) ) + ")";
});
g.append("rect")
.attr("width",0)
.transition()
.duration(800)
.delay(function(d,i){return i*25})
.attr("width", function (d) {
return widthScale(d);
})
.attr("height", barHeight*1.3 )
.attr("class","bars")
.attr("fill","#00338D")
.attr("id", function (d,i) {
return "barra" + i;
})
g.append("text")
.attr("x", function (d) { return widthScale(d) })
.attr("y", barHeight / 2)
.attr("dy", ".6em")
.attr("dx", "-2.5em")
.text(function (d) { return d + '%' })
.attr("font-size", 13)
.attr("font-weight", "bold")
.attr( "rx","20")
.attr( "ry","20")
.attr("class","barsText")
.attr("fill","#FFF")
g.append("text")
.data(categoryData)
.attr("x", 0)
.attr("y", (barHeight / 2) - barHeight *.8)
.attr("font-size", 13)
.attr("class","barsText")
.text(function (d) { return d })
setTimeout(function(){
$(".barsText").animate({opacity: 1});
},900);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
I want to highlight a bar with April (value in x-axis) with a square box. but I am not getting a approach to do the same.
tried getting the co-ordinates of the respected bar, but unable to find a solution for the same
Unable to find the co-ordinates of the respective bar which I need to highlight.
what should be the approach for highlighting a bar with a square box in stacked bar chart d3.js v4
createStackedBarChart(130,300,10,60,20,45,"manager-line-graph-2");
function createStackedBarChart(height,width,top,right,bottom,left,id){
var margin = {top: top, right: right, bottom: bottom, left: left };
//console.log("margin"+margin);
var svg = d3.select("#"+id).append("svg"),
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom,
g = svg.attr("width", "100%")
.attr("height", height + margin.top + margin.bottom)
.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand()
.rangeRound([0, width])
.padding(0.2)
.align(5.0);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var z = d3.scaleOrdinal()
.range(["#0000FF", "#00FFFF", "#81F781", "#F3F781", "#FE2E2E"]);
var data = [
{"Months": "Feb","Installation": 5,"Product": 10,"Payment": 15,"Billing": 20,"Outage": 25},
{"Months": "March","Installation": 6,"Product": 8,"Payment": 9,"Billing": 15,"Outage": 18},
{"Months": "April","Installation": 9,"Product": 12,"Payment": 24,"Billing": 17,"Outage": 14},
{"Months": "May","Installation": 9,"Product": 12,"Payment": 14,"Billing": 17,"Outage": 14},
{"Months": "June","Installation": 9,"Product": 12,"Payment": 15,"Billing": 11,"Outage": 10}
];
// fix pre-processing
var keys = [];
for (key in data[0]){
if (key != "Months")
keys.push(key);
}
console.log("value of keys are " + keys);
data.forEach(function(d){
d.total = 0;
keys.forEach(function(k){
d.total += d[k];
})
});
//data.sort(function(a, b) {
//return b.total - a.total;
//});
x.domain(data.map(function(d) {
return d.Months;
}));
y.domain([0, d3.max(data, function(d) {
return d.total;
})]).nice();
z.domain(keys);
g.append("g")
.selectAll("g")
.data(d3.stack().keys(keys)(data))
.enter().append("g")
.attr("fill", function(d) {return z(d.key);})
.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
.attr("x", function(d) {
return x(d.data.Months);
})
.attr("y", function(d) {
return y(d[1]);
})
.attr("height", function(d) {
return y(d[0]) - y(d[1]);
})
.attr("width", x.bandwidth()-5);
g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(5));
g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(5, "s"))
.append("text")
.attr("x", 2)
.attr("y", y(y.ticks(5).pop()))
.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 + 20)
//.attr("width", 10)
//.attr("height", 10)
//.attr("fill", z);
legend.append("circle")
.attr("r",5)
.attr("cx", width+30)
.attr("cy", 0)
.attr("fill",z);
legend.append("text")
.attr("x", width + 88)
.attr("y", 3.5)
.attr("dy", "0.12em")
.text(function(d) {
return`enter code here` d;
});
}
One solution I have used previously is to create an invisible layer of bars for the same data. Then use the .on("mouseover", function...); to make the bars for that data visible again by changing the styles or the fill opacity.
Here is a sample bl.ock with what I mean. It is a grouped bar chart with ordinal scale, but the same could be applied to your data with some tweaking.
https://bl.ocks.org/Coola85/b05339b65a7f9b082ca210d307a3e469
Update May 5, 2018: upon further reading I see your issue is different than the solution I suggested. This link might give you a good starting point of how to use an if statement to selectively highlight particular data.
so you could use the following style for your rect
.style ("fill", function(d) {
if (d.Months === "April") {return "red"} // <== Add these
else { return "black" }
})
Im making a graph that fills the circle by the percentage of the number of a certain product by the total of products avaible im almost close to what i need only problem is i cant figure it out how to change the left-over part of the donut arc.
this is the code
http://jsfiddle.net/LBzx7/345/
I can change the color the circle of the % of the product on this line
.attr("fill", "#F1F1F1");
, but what is left is the same color of the page background, i need to be able to change the color of that. Any ideas?
Here's a code snippet with the requirement fulfilled.
var dataset = {
hddrives: [90,10],
};
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#2DA7E2", "red"]);
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 70);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
//Draw the Circle
svg.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 65)
.attr("fill", "#F1F1F1");
var path = svg.selectAll("path")
.data(pie(dataset.hddrives))
.enter().append("path")
.attr("class", "arc")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
svg.append("text")
.attr("dy", "0em")
.style("text-anchor", "middle")
.attr("class", "inside")
.text(function(d) { return '56%'; });
svg.append("text")
.attr("dy", "1.5em")
.style("text-anchor", "middle")
.attr("class", "data")
.text(function(d) { return '53GB / 123GB'; });
.inside {
font-family: 'Roboto Condensed', sans-serif;
font-size:30px;
}
.data {
font-size:12px;
color:grey;
}
.arc {
stroke: #fff;
}
.
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.7/d3.min.js"></script>
Code changes:
Changed the color scale's range to .range(["#2DA7E2", "red"]);
With this, .attr("fill", function(d, i) { return color(i); }) will find appropriate color based on i. (as it was just one color before, the color was being repeated).
Got rid the opacity of the arcs i.e. removed the following line
(as this was causing the "left-over" part to have an opacity of 0)
.style("opacity", function(d, i) { return i == dataset.hddrives.length - 1 ? 0 : 1; })
Hope this helps. :)
I am using d3 js to draw a bar graph. I have x and y axis too.
The x axis would hold the 'names' and y axis the 'marks'. I am using ordinal scale for x axis.
In my json input dataset_rule_errors, I have 10 entries.
My code is
var svgd = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var x_domain = dataset_rule_errors.map(function(d) { return d.Rulename; })
var xScale = d3.scale.ordinal()
.domain(dataset_rule_errors.map(function (d) { return d.Rulename; }))
.rangeBands([padding_rule, wsvg]);
var xaxeScale = d3.scale.ordinal()
.domain(x_domain)
.rangePoints([padding_rule, wsvg]);
var xAxis = d3.svg.axis()
.scale(xaxeScale)
.tickValues(x_domain)
.orient("bottom");
//drawing rectangles
svgd.append("g")
.selectAll("rect") //based on the data in the dataset[] array, append rectangles s.t.
.data(dataset_rule_errors) //
.enter()
.append("rect")
.attr("x", function (d, i) {
return xScale(d.Rulename); // x position of rect as per i->0,1,2,3,...
})
.attr("y", function (d) {
return (h_rule - yScale(d.NumRuleFailed)); //y position of rect as per (h-value) to prevent inverted range
})
.attr("width", xScale.rangeBand())//"10") //depending upon domain->no of inputs - with of band is decided acc. to fit in svg
.attr("height", function (d) {
return yScale(d.NumRuleFailed); //depending upon domain->value of inputs - with of band is decided acc. to fit in svg
})
.attr("fill", function (d, i) { //colour based on values -> more errors - dark coloured bars
if(i%2==0)
return "rgb(" + 255 + "," + 255 + "," + 200 + ")";
else
return "rgb(" + 0 + "," + 0 + "," + 200 + ")";
})
.attr("stroke", "black");
//drawing x axis with ticks
svgd.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + 0 + "," + (h_rule) + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("text-anchor", "start")
.attr("transform", function (d) {
return "rotate(-90)"
})
.selectAll(".tick text")
.style("text-anchor", "start");
The problem I am facing is that my rectangles and the ticks of x-axis do not align with one another.
The reason is because I have 10 bars and therefore, I should be having 11 ticks including the one at the beginning and the end. But I have only 10 ticks, which distribute evenly along the axis length, so they do not coincide with the rectangle beginnings just like in this question Unable to align ticks with d3.js.
But the solution for this question did not work out for me. What can I do?
dataset_rule_errors = data I retrieve from my database
[{"Rulename":"A","NumRuleFailed":34321},{"Rulename":"B","NumRuleFailed":43},{"Rulename":"C","NumRuleFailed":45522},
{"Rulename":"D","NumRuleFailed":43643},{"Rulename":"E","NumRuleFailed":152},{"Rulename":"F","NumRuleFailed":152}]
I could not reproduce the issue you said you were having but I highly recommend using rangeRoundBands for a bar chart.
You can achieve the bar chart with the following setup:
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .2);
var y = d3.scale.linear()
.range([height, 0]);
// Finding domain of x (all our rulenames)
x.domain(data.map(function(d) {
return d.Rulename;
}));
// Finding domain of y (min and max values)
y.domain([d3.min(data, function(d) {
return d.NumRuleFailed;
}), d3.max(data, function(d) {
return d.NumRuleFailed;
})]);
var xAxis = d3.svg.axis()
.scale(x)
// no need yo specify ticks, x scale
// will take care of that
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
And the following for axis and rect rendering:
// Render xAxis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.50em")
.attr("text-anchor", "start")
.attr("transform", "rotate(-90)")
.selectAll(".tick text")
.style("text-anchor", "start")
// Render yAxis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("NumRuleFailed");
// Render rects
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.Rulename);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.NumRuleFailed);
})
.attr("fill", function(d, i) { //colour based on values -> more errors - dark coloured bars
return (i % 2) ? 'green' : 'red';
})
.attr("height", function(d) {
return height - y(d.NumRuleFailed);
});
Full Plnkr: https://plnkr.co/edit/jmtMGcRyT9hM5efwwTOb?p=preview
I am trying to label my animated Donut using D3...Can change data and get the drop-down to work but am having trouble labeling the donuts....Here is my code
var radius = 74,
padding = 10;
var color = d3.scale.ordinal()
.range(["#aec7e8", "#ff7f0e", "#2ca02c", "#bdbdbd", "#8c564b", "#d62728", "#17becf", "#7f7f7f", "#bcbd22", "#393b79","#31a354"]);
var arc = d3.svg.arc()
.outerRadius(radius)
.innerRadius(radius - 50);
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.DataUnitID = 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 * 3.5)
.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", 16)
.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.DataUnitID); })
.enter().append("path")
.attr("class", "arc")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.name); });
svg.append("text")
.attr("dy", ".15em")
.style("text-anchor", "middle")
.text(function(d) { return d.State; });
});