I am following Horizontal stack bar
for populating data . how can add the values of each bar graph at the end of each bar . for example
The above screen shot is for normal horizontal bar chart . but i am expecting for stacked bar graph .Let me know where i can modify code to have this value at the end of each stacked horizontal bar in the code given of above link
Thanks
Prasad
In order to generate the total counts for each bar, you will need to do two steps:
Transform the data so that you get an array of objects containing both the date and the total sum. Referencing to the d3 example you have linked, we will want to sum the integers in the keys of disease, wounds, and other.
We pass this transformed data to insert <text> elements into your SVG, and position them correctly using the pre-existing scales.
Step 1: Data transformation
You can store our transformed data in a variable called totals:
var totals = d3.nest()
.key(function(d) {
return d.date;
})
.rollup(function(d) {
return d3.sum(d, function(g) {
return g.disease + g.wounds + g.other;
});
})
.entries(data);
An explanation of the code above: we basically want to perform a summary based on date, and in this case we can use the d3.nest() function. The key will be the date, and we use d3.nest().rollup() to perform a sum of the values in disease, wounds, and other keys.
This will create an array of objects in the following format: totals = [{key: <date>, value: <total>}, {...}]. Note that the dates are now stored in the key and the totals in value.
Step 2: Create labels
We bind totals to a newly created object, and create new <text> elements from it:
var totalLabels = svg.append('g').attr('class', 'totals');
totalLabels.selectAll('.total')
.data(totals)
.enter().append('text')
.attr('class', 'total')
.attr("y", function(d) {
// Retrieve the correct vertical coordinates based on the date (stored as d.key)
// Plus some pixel offset so that the text is centered vertically relative to bar
return yScale(parseDate(d.key)) + yScale.bandwidth() - 2;
})
.attr("x", function(d) {
// Retrieve the horizontal coordinates based on total (stored as d.value)
// Add 5px offset so the label does not 'stick' to end of stacked bar
return xScale(d.value) + 5;
})
.text(function(d) {
// Inject total as text content (stored as d.value)
return d.value;
});
An explanation to the code above:
We create a <g> wrapper to store all your text labels
We create text labels by binding totals to it using .data(totals). We enter the data, and append <text> labels
For positioning, we simply reuse the xScale and yScale that is already defined. You simply pass the totals into xScale, i.e. xScale(d.value) and the dates into yScale, i.e. yScale(parseDate(d.key)).
Inject text into the element using d3.text(), with the totals as the text content, i.e. d.value.
Example
With the following code, we can create a modification of the d3.js example you have linked, where you can append totals to the end of the stacked barchart:
See proof-of-concept example below:
var initStackedBarChart = {
draw: function(config) {
me = this,
domEle = config.element,
stackKey = config.key,
data = config.data,
margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
parseDate = d3.timeParse("%m/%Y"),
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
xScale = d3.scaleLinear().rangeRound([0, width]),
yScale = d3.scaleBand().rangeRound([height, 0]).padding(0.1),
color = d3.scaleOrdinal(d3.schemeCategory20),
xAxis = d3.axisBottom(xScale),
yAxis = d3.axisLeft(yScale).tickFormat(d3.timeFormat("%b")),
svg = d3.select("#" + domEle).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 + ")");
var stack = d3.stack()
.keys(stackKey)
.offset(d3.stackOffsetNone);
var layers = stack(data);
data.sort(function(a, b) {
return b.total - a.total;
});
yScale.domain(data.map(function(d) {
return parseDate(d.date);
}));
xScale.domain([0, d3.max(layers[layers.length - 1], function(d) {
return d[0] + d[1];
})]).nice();
var layer = svg.selectAll(".layer")
.data(layers)
.enter().append("g")
.attr("class", "layer")
.style("fill", function(d, i) {
return color(i);
});
layer.selectAll("rect")
.data(function(d) {
return d;
})
.enter().append("rect")
.attr("y", function(d) {
return yScale(parseDate(d.data.date));
})
.attr("x", function(d) {
return xScale(d[0]);
})
.attr("height", yScale.bandwidth())
.attr("width", function(d) {
return xScale(d[1]) - xScale(d[0])
});
var totals = d3.nest()
.key(function(d) {
return d.date;
})
.rollup(function(d) {
return d3.sum(d, function(g) {
return g.disease + g.wounds + g.other;
});
})
.entries(data);
var totalLabels = svg.append('g').attr('class', 'totals');
totalLabels.selectAll('.total')
.data(totals)
.enter().append('text')
.attr('class', 'total')
.attr("y", function(d) {
// Retrieve the correct vertical coordinates based on the date (stored as d.key)
// Plus some pixel offset so that the text is centered vertically relative to bar
return yScale(parseDate(d.key)) + yScale.bandwidth() - 2;
})
.attr("x", function(d) {
// Retrieve the horizontal coordinates based on total (stored as d.value)
// Add pixel offset so labels don't stick to end of stacked bars
return xScale(d.value) + 5;
})
.text(function(d) {
// Inject total as text content (stored as d.value)
return d.value;
});
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + (height + 5) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis axis--y")
.attr("transform", "translate(0,0)")
.call(yAxis);
}
}
var data = [{
"date": "4/1854",
"total": 8571,
"disease": 1,
"wounds": 0,
"other": 5
}, {
"date": "5/1854",
"total": 23333,
"disease": 12,
"wounds": 0,
"other": 9
}, {
"date": "6/1854",
"total": 28333,
"disease": 11,
"wounds": 0,
"other": 6
}, {
"date": "7/1854",
"total": 28772,
"disease": 359,
"wounds": 0,
"other": 23
}, {
"date": "8/1854",
"total": 30246,
"disease": 828,
"wounds": 1,
"other": 30
}, {
"date": "9/1854",
"total": 30290,
"disease": 788,
"wounds": 81,
"other": 70
}, {
"date": "10/1854",
"total": 30643,
"disease": 503,
"wounds": 132,
"other": 128
}, {
"date": "11/1854",
"total": 29736,
"disease": 844,
"wounds": 287,
"other": 106
}, {
"date": "12/1854",
"total": 32779,
"disease": 1725,
"wounds": 114,
"other": 131
}, {
"date": "1/1855",
"total": 32393,
"disease": 2761,
"wounds": 83,
"other": 324
}, {
"date": "2/1855",
"total": 30919,
"disease": 2120,
"wounds": 42,
"other": 361
}, {
"date": "3/1855",
"total": 30107,
"disease": 1205,
"wounds": 32,
"other": 172
}, {
"date": "4/1855",
"total": 32252,
"disease": 477,
"wounds": 48,
"other": 57
}, {
"date": "5/1855",
"total": 35473,
"disease": 508,
"wounds": 49,
"other": 37
}, {
"date": "6/1855",
"total": 38863,
"disease": 802,
"wounds": 209,
"other": 31
}, {
"date": "7/1855",
"total": 42647,
"disease": 382,
"wounds": 134,
"other": 33
}, {
"date": "8/1855",
"total": 44614,
"disease": 483,
"wounds": 164,
"other": 25
}, {
"date": "9/1855",
"total": 47751,
"disease": 189,
"wounds": 276,
"other": 20
}, {
"date": "10/1855",
"total": 46852,
"disease": 128,
"wounds": 53,
"other": 18
}, {
"date": "11/1855",
"total": 37853,
"disease": 178,
"wounds": 33,
"other": 32
}, {
"date": "12/1855",
"total": 43217,
"disease": 91,
"wounds": 18,
"other": 28
}, {
"date": "1/1856",
"total": 44212,
"disease": 42,
"wounds": 2,
"other": 48
}, {
"date": "2/1856",
"total": 43485,
"disease": 24,
"wounds": 0,
"other": 19
}, {
"date": "3/1856",
"total": 46140,
"disease": 15,
"wounds": 0,
"other": 35
}];
var key = ["wounds", "other", "disease"];
initStackedBarChart.draw({
data: data,
key: key,
element: 'stacked-bar'
});
.axis text {
font: 10px sans-serif;
}
.axis line,
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.path-line {
fill: none;
stroke: yellow;
stroke-width: 1.5px;
}
svg {
background: #f0f0f0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<h2>Stacked Bar Chart - d3.v4 implementation</h2>
<div id='stacked-bar'></div>
You mean something like this?
Stackchart
See sample - fiddle
var data = [
{
"interest_rate":"< 4%",
"Default":60,
"Charge-off":20,
"Current":456,
"30 days":367.22,
"60 days":222,
"90 days":198,
"Default":60
},
{
"interest_rate":"4-7.99%",
"Charge-off":2,
"Default":30,
"Current":271,
"30 days":125,
"60 days":78,
"90 days":72
}
];
var margin = {
top: 20,
right: 20,
bottom: 40,
left: 60
},
width = 450 - margin.left - margin.right,
height = 315 - margin.top - margin.bottom,
that = this;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .3);
var y = d3.scale.linear().rangeRound([height, 0]);
var color = d3.scale.category20();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left").tickFormat(d3.format(".0%"));
var svg = d3.select(".viz-portfolio-delinquent-status").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 + ")");
color.domain(d3.keys(data[0]).filter(function (key) {
return key !== "interest_rate";
}));
data.forEach(function (d) {
var y0 = 0;
d.rates = color.domain().map(function (name) {
console.log();;
return {
name: name,
y0: y0,
y1: y0 += +d[name],
amount: d[name]
};
});
d.rates.forEach(function (d) {
d.y0 /= y0;
d.y1 /= y0;
});
console.log(data);
});
data.sort(function (a, b) {
return b.rates[0].y1 - a.rates[0].y1;
});
x.domain(data.map(function (d) {
return d.interest_rate;
}));
svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")").call(xAxis);
svg.append("g").attr("class", "y axis").call(yAxis);
var interest_rate = svg.selectAll(".interest-rate").data(data).enter().append("g").attr("class", "interest-rate").attr("transform", function (d) {
return "translate(" + x(d.interest_rate) + ",0)";
});
interest_rate.selectAll("rect").data(function (d) {
return d.rates;
}).enter().append("rect").attr("width", x.rangeBand()).attr("y", function (d) {
return y(d.y1);
}).attr("height", function (d) {
return y(d.y0) - y(d.y1);
}).style("fill", function (d) {
return color(d.name);
}).on('mouseover', function (d) {
var total_amt;
total_amt = d.amount;
console.log('----');
d3.select(".chart-tip").style('opacity', '1').html('Amount: <strong>$' + that.numberWithCommas(total_amt.toFixed(2)) + '</strong>');
}).on('mouseout', function () {
d3.select(".chart-tip").style('opacity', '0');
});
var legend = svg.selectAll(".legend").data(color.domain().slice().reverse()).enter().append("g").attr("class", "legend").attr("transform", function (d, i) {
return "translate(" + i * -70 + ",283)";
});
legend.append("rect").attr("x", width + -53).attr("width", 10).attr("height", 10).style("fill", color);
legend.append("text").attr("x", width - 40).attr("y", 5).attr("width", 40).attr("dy", ".35em").style("text-anchor", "start").text(function (d) {
return d;
});
h1 {
font-family: helvetica, arial, sans-serif;
text-align:center;
margin-top: 80px;
}
.viz-portfolio-delinquent-status {
font-family: helvetica, arial, sans-serif;
margin: 0 auto;
font-size: 10px;
width: 450px;
height: 300px
}
path { fill: #83B0EA;}
.domain {
fill: none;
stroke: #000;
stroke-width: 1px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<h1>D3 Stacked Bar Chart Example</h1>
<div class="viz-portfolio-delinquent-status"></div>
Related
I'm trying to show a vertical bar chart with x and y axes. I get the bar chart with y axis, however I'm struggling with the x-axis.
The x-axis text labels are equally distributed with the width of the bars, however: there are markers/vertical lines on the x-axis with varying width, particularly the first and last sections, even though I've specified the scaleBand and the domain.
My code:
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg class="v5chart" width="960" height="500"></svg>
<style>
/*Rectangle bar class styling*/
.bar {
fill: #0080FF
}
.bar:hover {
fill: #003366
}
/*Text class styling*/
.text {
fill: white;
font-family: sans-serif
}
</style>
<script>
////VERTICAL BAR CHART WITH SVG AND NAMES
// Create data array of values to visualize
var dataArray = [{ "Player": "John Doe", "Points": 23 }, { "Player": "Jane Doe", "Points": 13 }, { "Player": "Mary Jane", "Points": 21 }, { "Player": "Debasis Das", "Points": 14 }, { "Player": "Nishant", "Points": 37 }, { "Player": "Mark", "Points": 15 }, { "Player": "Andrew", "Points": 18 }, { "Player": "Simon", "Points": 34 }, { "Player": "Lisa", "Points": 30 }, { "Player": "Marga", "Points": 20 }];
// Create variable for the SVG
var canvas = d3.select(".v5chart1").append("g").attr("transform", "translate(20,30)");
var canvasWidth = 500;
var maxValue = d3.max(dataArray, function (d) { return d.Points; });
var canvasHeight = maxValue*10;
var heightScale = d3.scaleLinear()
.domain([0, d3.max(dataArray, function (d) { return d.Points; })])
.range([canvasHeight, 0]); //use max value (37) * 10
var y_axis = d3.axisLeft()
.scale(heightScale);
var x = d3.scaleBand()
.rangeRound([0, canvasWidth], .1);
x.domain(dataArray.map(function (d) { return d.Player; }));
var x_Axis = d3.axisBottom(x);
// Select, append to SVG, and add attributes to rectangles for bar chart
canvas.selectAll("rect")
.data(dataArray)
.enter().append("rect")
.attr("class", "bar")
.attr("height", function (d, i) { return (d.Points * 10) })
.attr("width", canvasWidth/dataArray.length)
.attr("x", function (d, i) { return (i * (canvasWidth / dataArray.length)) })
.attr("y", function (d, i) { return canvasHeight - (d.Points * 10) });
// Select, append to SVG, and add attributes to text
canvas.selectAll("text")
.data(dataArray)
.enter().append("text")
.text(function (d) { return d.Points })
.attr("class", "text")
.attr("x", function (d, i) { return (i * (canvasWidth / dataArray.length)) + (canvasWidth / dataArray.length)/2 })
.attr("y", function (d, i) { return canvasHeight + 20 - (d.Points * 10) });
canvas.append("g")
.attr("transform", "translate(0,0)")
.call(y_axis);
canvas.append("g")
.attr("transform", "translate(0," + canvasHeight + ")")
.call(x_Axis)
.selectAll("text")
.attr("x",40)
.attr("transform", function (d) {
return "rotate(65)"
});
</script>
I already checked here: https://www.d3-graph-gallery.com/graph/custom_axis.html
You should have read properly the scaleBand example on the link that you provided:
scaleBand provides a convenient bandwidth() method to provide you with the width for each bar
the idea od axis in d3js is that you don't need to do calculations yourself, so in your case you can just pass the player name to the x function and it will do the coordinate calculations for you.
same applies to the y calculations, but I leave this for you to figure out, it should not be hard at all.
one more small thing about scaleBand, you were using rangeRound() method, which I am not familiar with, but if you use range() method combined with padding() as it is in the example you linked, then by adjusting the padding value you can control the width of the bar, without affecting the x axis. The higher value, the thinner will be the bar and more space would be between the bars.
////VERTICAL BAR CHART WITH SVG AND NAMES
// Create data array of values to visualize
var dataArray = [{ "Player": "John Doe", "Points": 23 }, { "Player": "Jane Doe", "Points": 13 }, { "Player": "Mary Jane", "Points": 21 }, { "Player": "Debasis Das", "Points": 14 }, { "Player": "Nishant", "Points": 37 }, { "Player": "Mark", "Points": 15 }, { "Player": "Andrew", "Points": 18 }, { "Player": "Simon", "Points": 34 }, { "Player": "Lisa", "Points": 30 }, { "Player": "Marga", "Points": 20 }];
// Create variable for the SVG
var canvas = d3.select(".v5chart").append("g").attr("transform", "translate(20,30)");
var canvasWidth = 500;
var maxValue = d3.max(dataArray, function (d) { return d.Points; });
var heightScale = d3.scaleLinear()
.domain([0, d3.max(dataArray, function (d) { return d.Points; })])
.range([maxValue * 10, 0]); //use max value (37) * 10
var y_axis = d3.axisLeft()
.scale(heightScale);
var x = d3.scaleBand()
.range([0, canvasWidth]).padding([0.1]);
x.domain(dataArray.map(function (d) { return d.Player; }));
var x_Axis = d3.axisBottom(x);
// Select, append to SVG, and add attributes to rectangles for bar chart
canvas.selectAll("rect")
.data(dataArray)
.enter().append("rect")
.attr("class", "bar")
.attr("height", function (d, i) { return (d.Points * 10) })
.attr("width", x.bandwidth())
.attr("x", function (d, i) { return x(d.Player); })
.attr("y", function (d, i) { return 370 - (d.Points * 10) });
// Select, append to SVG, and add attributes to text
canvas.selectAll("text")
.data(dataArray)
.enter().append("text")
.text(function (d) { return d.Points })
.attr("class", "text")
.attr("text-anchor", "middle")
.attr("x", function (d, i) { return x(d.Player)+x.bandwidth()/2; })
.attr("y", function (d, i) { return 390 - (d.Points * 10) });
canvas.append("g")
.attr("transform", "translate(0,0)")
.call(y_axis);
canvas.append("g")
.attr("transform", "translate(0,370)")
.call(x_Axis);
.bar {
fill: #0080FF
}
.bar:hover {
fill: #003366
}
/*Text class styling*/
.text {
fill: white;
font-family: sans-serif
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class="v5chart" width="960" height="500"></svg>
I have been struggling to get this chart work. I tried so many methods. It didn't show any error but doesn't draw the chart properly.
I want to use strings as x axis domain. I had even tried to set domain for x-scale. Still no use. The code which I have tried so far:
$(".wrapper").delay(600).fadeIn(500);
var barDataset = [{
"name": "aA",
"date": 1,
"successful": 1,
"unsuccessful": 2
},
{
"name": "bB",
"date": 2,
"successful": 41,
"unsuccessful": 8
},
{
"name": "cC",
"date": 3,
"successful": 44,
"unsuccessful": 4
},
{
"name": "dD",
"date": 4,
"successful": 2,
"unsuccessful": 5
},
{
"name": "eE",
"date": 5,
"successful": 21,
"unsuccessful": 1
},
{
"name": "fF",
"date": 6,
"successful": 14,
"unsuccessful": 6
},
{
"name": "gG",
"date": 7,
"successful": 42,
"unsuccessful": 1
},
{
"name": "hH",
"date": 8,
"successful": 10,
"unsuccessful": 1
},
{
"name": "iI",
"date": 9,
"successful": 24,
"unsuccessful": 10
},
{
"name": "jJ",
"date": 10,
"successful": 23,
"unsuccessful": 6
},
{
"name": "kK",
"date": 11,
"successful": 21,
"unsuccessful": 15
},
{
"name": "lL",
"date": 12,
"successful": 28,
"unsuccessful": 15
}
]
function drawBarGraph(data) {
var status = ["successful", "unsuccessful"];
var colors = [
["Successful", "#50E3C2"],
["Unsuccessful", "#EF5C6E"]
];
var margin = {
top: 30,
right: 30,
bottom: 40,
left: 60
},
width = 860 - margin.left - margin.right,
height = 290 - margin.top - margin.bottom;
var z = d3.scale.ordinal()
.range(["#50E3C2", "#EF5C6E"]);
/* var n = 12;
var x = d3.scale.linear()
.domain([1, n - 1])
.rangeRound([0, width], .1);*/
var x = d3.scale.ordinal()
.domain(data.map(function(d) {
return d['name'];
}))
.rangeRoundBands([0, width], .5);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
/*.tickFormat(d3.format("d"))
.ticks(30)*/
;
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
.tickFormat(d3.format("d"));
var svg = d3.select("#chart-bar")
.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 + ")");
var layers = d3.layout.stack()
(status.map(function(c) {
return data.map(function(d) {
return {
x: d.date,
y: d[c]
};
});
}));
y.domain([
0, d3.max(layers[layers.length - 1], function(d) {
return d.y0 + d.y;
})
]);
// gridlines in y axis function
function make_y_gridlines() {
return d3.svg.axis().scale(y)
.orient("left").ticks(5);
}
// add the Y gridlines
svg.append("g")
.attr("class", "gridline")
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
);
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(6," + height + ")")
.call(xAxis)
.append("text")
.attr("transform", "translate(364,0)")
.attr("y", "3em")
.style("text-anchor", "middle")
.text("Days");
svg.append("g")
.attr("class", "axis axis--y")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("x", "-5em")
.attr("y", "-2.5em")
.style("text-anchor", "end")
.text("Number of calls sent");
function type(d) {
// d.date = parseDate(d.date);
d.date;
status.forEach(function(c) {
d[c] = +d[c];
});
return d;
}
var tooltip = d3.select("#chart-bar").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var layer = svg.selectAll(".layer")
.data(layers)
.enter().append("g")
.attr("class", "layer")
.style("fill", function(d, i) {
return z(i);
});
layer.selectAll("rect")
.data(function(d) {
return d;
})
.enter().append("rect")
.on("mouseover", function(d) {
tooltip.transition()
.duration(200)
.style("opacity", 1);
tooltip.html("<span>" + d.y + " calls" + "</span>")
.style("left", (d3.event.pageX - 25) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
})
.attr("x", function(d) {
return x(d.x);
})
.attr("y", function(d) {
return height;
})
.attr("width", 12)
.attr("height", 0)
.transition().duration(1500)
.attr("y", function(d) {
return y(d.y + d.y0);
})
.attr("height", function(d) {
return y(d.y0) - y(d.y + d.y0);
});
}
drawBarGraph(barDataset);
$('.count').each(function() {
$(this).prop('Counter', 0).animate({
Counter: $(this).text()
}, {
duration: 1500,
easing: 'swing',
step: function(now) {
$(this).text(Math.ceil(now));
}
});
});
#import url("https://fonts.googleapis.com/css?family=Overpass");
* {
box-sizing: border-box;
font: normal 14px/1.5 "Overpass", sans-serif;
}
body {
background: #76daff;
}
.chart-wrapper {
background: #333B66;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
clear: both;
padding: 20px 0 10px;
}
text {
font-size: 12px;
fill: #A7B2EB;
}
.axis path,
.axis line,
.gridline line {
fill: none;
stroke: #fff;
opacity: 0.1;
shape-rendering: crispEdges;
}
.line {
stroke: #17EAD9;
stroke-width: 3px;
fill: none;
}
path.domain {
fill: none;
opacity: 0.1;
}
div.tooltip {
color: #4a4a4a;
position: absolute;
text-align: center;
padding: 3px 6px;
font-size: 12px;
background: #fff;
border-radius: 4px;
pointer-events: none;
}
.tick text {
font-size: 10px;
}
.vbroadcast-legend {
float: right;
margin-right: 40px;
margin-top: 16px;
}
.vbroadcast-legend li {
color: #fff;
font-size: 13px;
float: left;
list-style: none;
margin-left: 20px;
padding-left: 18px;
position: relative;
}
.vbroadcast-legend li:before {
content: "";
height: 12px;
left: 0;
position: absolute;
top: 3px;
width: 12px;
}
.vbroadcast-legend li.successful:before {
background: #50e3c2;
}
.vbroadcast-legend li.unsuccessful:before {
background: #ef5c6e;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="chart-bar" class="chart-wrapper"></div>
Kindly help me in fixing it. Thanks in advance.
Thanks for getting back with the data. It's a minor fix in your code.
You're using name for drawing the X axis but it's not being mapped while being assigned to the layers array.
Relevant changes:
Changed d.date to d.name
return data.map(function(d) {
return {
x: d.name,
y: d[c]
};
});
Assigning x to the rects using this d.x and axes rangeBand to align it with the ticks.
.attr("x", function(d) {
return x(d.x) + x.rangeBand()/2;
})
Snippet:
$(".wrapper").delay(600).fadeIn(500);
var barDataset = [{
"name": "aA",
"date": 1,
"successful": 1,
"unsuccessful": 2
},
{
"name": "bB",
"date": 2,
"successful": 41,
"unsuccessful": 8
},
{
"name": "cC",
"date": 3,
"successful": 44,
"unsuccessful": 4
},
{
"name": "dD",
"date": 4,
"successful": 2,
"unsuccessful": 5
},
{
"name": "eE",
"date": 5,
"successful": 21,
"unsuccessful": 1
},
{
"name": "fF",
"date": 6,
"successful": 14,
"unsuccessful": 6
},
{
"name": "gG",
"date": 7,
"successful": 42,
"unsuccessful": 1
},
{
"name": "hH",
"date": 8,
"successful": 10,
"unsuccessful": 1
},
{
"name": "iI",
"date": 9,
"successful": 24,
"unsuccessful": 10
},
{
"name": "jJ",
"date": 10,
"successful": 23,
"unsuccessful": 6
},
{
"name": "kK",
"date": 11,
"successful": 21,
"unsuccessful": 15
},
{
"name": "lL",
"date": 12,
"successful": 28,
"unsuccessful": 15
}
]
function drawBarGraph(data) {
var status = ["successful", "unsuccessful"];
var colors = [
["Successful", "#50E3C2"],
["Unsuccessful", "#EF5C6E"]
];
var margin = {
top: 30,
right: 30,
bottom: 40,
left: 60
},
width = 860 - margin.left - margin.right,
height = 290 - margin.top - margin.bottom;
var z = d3.scale.ordinal()
.range(["#50E3C2", "#EF5C6E"]);
/* var n = 12;
var x = d3.scale.linear()
.domain([1, n - 1])
.rangeRound([0, width], .1);*/
var x = d3.scale.ordinal()
.domain(data.map(function(d) {
return d['name'];
}))
.rangeRoundBands([0, width], .5);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
/*.tickFormat(d3.format("d"))
.ticks(30)*/
;
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
.tickFormat(d3.format("d"));
var svg = d3.select("#chart-bar")
.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 + ")");
var layers = d3.layout.stack()
(status.map(function(c) {
return data.map(function(d) {
return {
x: d.name,
y: d[c],
};
});
}));
y.domain([
0, d3.max(layers[layers.length - 1], function(d) {
return d.y0 + d.y;
})
]);
// gridlines in y axis function
function make_y_gridlines() {
return d3.svg.axis().scale(y)
.orient("left").ticks(5);
}
// add the Y gridlines
svg.append("g")
.attr("class", "gridline")
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
);
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(6," + height + ")")
.call(xAxis)
.append("text")
.attr("transform", "translate(364,0)")
.attr("y", "3em")
.style("text-anchor", "middle")
.text("Days");
svg.append("g")
.attr("class", "axis axis--y")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("x", "-5em")
.attr("y", "-2.5em")
.style("text-anchor", "end")
.text("Number of calls sent");
function type(d) {
// d.date = parseDate(d.date);
d.date;
status.forEach(function(c) {
d[c] = +d[c];
});
return d;
}
var tooltip = d3.select("#chart-bar").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var layer = svg.selectAll(".layer")
.data(layers)
.enter().append("g")
.attr("class", "layer")
.style("fill", function(d, i) {
return z(i);
});
layer.selectAll("rect")
.data(function(d) {
return d;
})
.enter().append("rect")
.on("mouseover", function(d) {
tooltip.transition()
.duration(200)
.style("opacity", 1);
tooltip.html("<span>" + d.y + " calls" + "</span>")
.style("left", (d3.event.pageX - 25) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
})
.attr("x", function(d) {
return x(d.x) + x.rangeBand()/2;
})
.attr("y", function(d) {
return height;
})
.attr("width", 12)
.attr("height", 0)
.transition().duration(1500)
.attr("y", function(d) {
return y(d.y + d.y0);
})
.attr("height", function(d) {
return y(d.y0) - y(d.y + d.y0);
});
}
drawBarGraph(barDataset);
$('.count').each(function() {
$(this).prop('Counter', 0).animate({
Counter: $(this).text()
}, {
duration: 1500,
easing: 'swing',
step: function(now) {
$(this).text(Math.ceil(now));
}
});
});
#import url("https://fonts.googleapis.com/css?family=Overpass");
* {
box-sizing: border-box;
font: normal 14px/1.5 "Overpass", sans-serif;
}
body {
background: #76daff;
}
.chart-wrapper {
background: #333B66;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
clear: both;
padding: 20px 0 10px;
}
text {
font-size: 12px;
fill: #A7B2EB;
}
.axis path,
.axis line,
.gridline line {
fill: none;
stroke: #fff;
opacity: 0.1;
shape-rendering: crispEdges;
}
.line {
stroke: #17EAD9;
stroke-width: 3px;
fill: none;
}
path.domain {
fill: none;
opacity: 0.1;
}
div.tooltip {
color: #4a4a4a;
position: absolute;
text-align: center;
padding: 3px 6px;
font-size: 12px;
background: #fff;
border-radius: 4px;
pointer-events: none;
}
.tick text {
font-size: 10px;
}
.vbroadcast-legend {
float: right;
margin-right: 40px;
margin-top: 16px;
}
.vbroadcast-legend li {
color: #fff;
font-size: 13px;
float: left;
list-style: none;
margin-left: 20px;
padding-left: 18px;
position: relative;
}
.vbroadcast-legend li:before {
content: "";
height: 12px;
left: 0;
position: absolute;
top: 3px;
width: 12px;
}
.vbroadcast-legend li.successful:before {
background: #50e3c2;
}
.vbroadcast-legend li.unsuccessful:before {
background: #ef5c6e;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="chart-bar" class="chart-wrapper"></div>
Hope this helps solve the issue.
If you have a list of 'aa' .. 'jj' and you set the domain of x to this list you most likely do not get tick marks like '0-15' and '15-30'.
Extract the x-domain values from the dataset or some other means of extracting the unique values. This is with the small dataset in the question.
var strn = ['aa', 'bb', 'cc', 'dd', 'ee', 'ff', 'gg', 'hh', 'ii', 'jj'];
// ...
//x.domain(strn);
x.domain(data.map(d=>d.DB));
I am implementing a multi-line series chart using d3.js and I am getting an error pointing to my x-axis when trying to plot my dateTime from the data coming in. "Error: attribute d: Expected number, "MNaN,376.88020650…"."
Here is my function
var data = [{
"Brand": "Toyota",
"Count": 1800,
"Time": "2017-04-02 16"},
{
"Brand": "Toyota",
"Count": 1172,
"Time": "2017-04-02 17"},
{
"Brand": "Toyota",
"Count": 2000,
"Time": "2017-04-02 18"},
{
"Brand": "Honda",
"Count": 8765,
"Time": "2017-04-02 16"},
{
"Brand": "Honda",
"Count": 3445,
"Time": "2017-04-02 17"},
{
"Brand": "Honda",
"Count": 1232,
"Time": "2017-04-02 18"}
]
var dataGroup = d3.nest() //d3 method that groups data by Brand
.key(function(d) {return d.Brand;})
.entries(data);
console.log(JSON.stringify(dataGroup));
//var color = d3.scale.category10();
var vis = d3.select("#visualisation"),
WIDTH = 1000,
HEIGHT = 500,
MARGINS = {
top: 50,
right: 20,
bottom: 50,
left: 50
},
xScale = d3.scaleLinear().range([MARGINS.left, WIDTH - MARGINS.right]).domain([d3.min(data, function(d) { //set up x-axis based on data
return d.Time;
}), d3.max(data, function(d) {
return d.Time;
})]),
yScale = d3.scaleLinear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([d3.min(data, function(d) { //set up y-axis based on data
return d.Count;
}), d3.max(data, function(d) {
return d.Count;
})]),
xAxis = d3.axisBottom()
.scale(xScale),
yAxis = d3.axisLeft()
.scale(yScale)
vis.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
.call(xAxis);
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
var lineGen = d3.line()
.x(function(d) {
return xScale(d.Time);
})
.y(function(d) {
return yScale(d.Count);
})
.curve(d3.curveBasis);
dataGroup.forEach(function(d,i) { //iterate over the dataGroup and create line graph for each brand
vis.append('svg:path')
.attr('d', lineGen(d.values))
.attr('stroke', function(d,j) {
return "hsl(" + Math.random() * 360 + ",100%,50%)"; //random color for each brand line on graph
})
.attr('stroke-width', 2)
.attr('id', 'line_'+d.key)
.attr('fill', 'none');
lSpace = WIDTH/dataGroup.length; //define the legend space based on number of brands
vis.append("text")
.attr("x", (lSpace/2)+i*lSpace)
.attr("y", HEIGHT)
.style("fill", "black")
.attr("class","legend")
.on('click',function(){
var active = d.active ? false : true;
var opacity = active ? 0 : 1;
d3.select("#line_" + d.key).style("opacity", opacity);
d.active = active;
})
.text(d.key);
});
My dates are in yyyy-mm-dd HH format and what I am trying to accomplish is this for example:
"Time": "2017-04-02 16" converted to 'April 02' on the x axis and have the hour (HH) just displayed as a tool tip...etc
Here is a jsfiddle link https://jsfiddle.net/rsov2s2s/
Any help is appreciated.
In your data objects, Time is only a string. Thus, you`ll have to parse it into an actual date:
data.forEach(function(d){
d.Time = d3.timeParse("%Y-%m-%d %H")(d.Time)
});
In this function, d3.timeParse uses "%Y-%m-%d %H" as a specifier, which matches the structure of your strings.
After that, don't forget to change the xScale from scaleLinear to scaleTime.
Here is your code with those changes only:
var data = [{
"Brand": "Toyota",
"Count": 1800,
"Time": "2017-04-02 16"
}, {
"Brand": "Toyota",
"Count": 1172,
"Time": "2017-04-02 17"
}, {
"Brand": "Toyota",
"Count": 2000,
"Time": "2017-04-02 18"
}, {
"Brand": "Honda",
"Count": 8765,
"Time": "2017-04-02 16"
}, {
"Brand": "Honda",
"Count": 3445,
"Time": "2017-04-02 17"
}, {
"Brand": "Honda",
"Count": 1232,
"Time": "2017-04-02 18"
}];
data.forEach(function(d) {
d.Time = d3.timeParse("%Y-%m-%d %H")(d.Time)
});
var dataGroup = d3.nest() //d3 method that groups data by Brand
.key(function(d) {
return d.Brand;
})
.entries(data);
//var color = d3.scale.category10();
var vis = d3.select("#visualisation"),
WIDTH = 1000,
HEIGHT = 500,
MARGINS = {
top: 50,
right: 20,
bottom: 50,
left: 50
},
xScale = d3.scaleTime().range([MARGINS.left, WIDTH - MARGINS.right]).domain([d3.min(data, function(d) { //set up x-axis based on data
return d.Time;
}), d3.max(data, function(d) {
return d.Time;
})]),
yScale = d3.scaleLinear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([d3.min(data, function(d) { //set up y-axis based on data
return d.Count;
}), d3.max(data, function(d) {
return d.Count;
})]),
xAxis = d3.axisBottom()
.scale(xScale),
yAxis = d3.axisLeft()
.scale(yScale)
vis.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
.call(xAxis);
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
var lineGen = d3.line()
.x(function(d) {
return xScale(d.Time);
})
.y(function(d) {
return yScale(d.Count);
})
.curve(d3.curveBasis);
dataGroup.forEach(function(d, i) { //iterate over the dataGroup and create line graph for each brand
vis.append('svg:path')
.attr('d', lineGen(d.values))
.attr('stroke', function(d, j) {
return "hsl(" + Math.random() * 360 + ",100%,50%)"; //random color for each brand line on graph
})
.attr('stroke-width', 2)
.attr('id', 'line_' + d.key)
.attr('fill', 'none');
lSpace = WIDTH / dataGroup.length; //define the legend space based on number of brands
vis.append("text")
.attr("x", (lSpace / 2) + i * lSpace)
.attr("y", HEIGHT)
.style("fill", "black")
.attr("class", "legend")
.on('click', function() {
var active = d.active ? false : true;
var opacity = active ? 0 : 1;
d3.select("#line_" + d.key).style("opacity", opacity);
d.active = active;
})
.text(d.key);
});
.axis path {
fill: none;
stroke: #777;
shape-rendering: crispEdges;
}
.axis text {
font-family: Lato;
font-size: 13px;
}
.legend {
font-size: 14px;
font-weight: bold;
cursor: pointer;
<title>D3 Test</title>
<script src="https://d3js.org/d3.v4.js"></script>
<body>
<svg id="visualisation" width="1000" height="600"></svg>
<script src="InitChart.js"></script>
</body>
Hi I'm implementing the D3.js chart in my module.I need that on the basis of my dropdown selection my chart type will update accordingly.
JsFiddle
I have sample.json file to retrieve data from json.
{
"sample2": [{
"time": 1387212120,
"open": 368,
"close": 275,
"high": 380,
"low": 158
}, {
"time": 1387212130,
"open": 330,
"close": 350,
"high": 389,
"low": 310
}, {
"time": 1387212140,
"open": 213,
"close": 253,
"high": 289,
"low": 213
}, {
"time": 1387212150,
"open": 180,
"close": 150,
"high": 189,
"low": 110
}, {
"time": 1387212160,
"open": 310,
"close": 350,
"high": 389,
"low": 310
}]
}
Line is the default chart selected in your demo. So you should kept that option selected by default in the drop down also (For now, I have put 'line' as the first option in the code snippet and will be selected by default). Also note that the data bonded to the pie chart paths was not correct. You should bind data as shown below and since pie chart need multiple paths to be drawn, you should use selectAll and enter method for this.
var container = canvas.selectAll(".arc")
.data(pie(sample2))
.enter().append("path")
instead of
canvas.append("path")
.datum(sample2);
And hide/show the x and y axes, when switching between pie chart and other charts.
// loading sample.json
var sample2 = {
"sample2": [{
"time": 1387212120,
"open": 368,
"close": 275,
"high": 380,
"low": 158
}, {
"time": 1387212130,
"open": 330,
"close": 350,
"high": 389,
"low": 310
}, {
"time": 1387212140,
"open": 213,
"close": 253,
"high": 289,
"low": 213
}, {
"time": 1387212150,
"open": 180,
"close": 150,
"high": 189,
"low": 110
}, {
"time": 1387212160,
"open": 310,
"close": 350,
"high": 389,
"low": 310
}]
};
sample2 = sample2.sample2
// date manipulation to format UTC to js Date obj
sample2.forEach(function(d) {
d.time = new Date(d.time * 1000);
});
// helpers and constants
var margin = {
"top": 50,
"right": 100,
"bottom": 56,
"left": 50
};
var width = 930 - margin.right - margin.left;
var height = 582 - margin.top - margin.bottom;
var radius = Math.min(width, height) / 2;
var timeFormat = d3.time.format("%c");
var X = width / sample2.length * 0.25;
// find data range
var xDomain = d3.extent(sample2, function(d, i) {
return d.time;
});
var yMin = d3.min(sample2, function(d) {
return Math.min(d.low);
});
var yMax = d3.max(sample2, function(d) {
return Math.max(d.high);
});
// scales, add 10pc padding to x-domain
var xScale = d3.time.scale()
.domain(xDomain);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 20);
xScale.domain([-0.1, 1.1].map(xScale.invert))
.range([margin.left, width - margin.right]);
var yScale = d3.scale.linear()
.domain([yMin, yMax])
.range([height - margin.top, margin.bottom]);
// set up axes
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(10)
.tickPadding(10);
// .tickFormat(timeFormat)
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("right")
.tickValues(yScale.domain());
// set up chart types
var area = d3.svg.area()
.x(function(d) {
return xScale(d.time);
})
.y0(height - margin.bottom)
.y1(function(d) {
return yScale(d.close);
});
var line = d3.svg.line().interpolate("monotone")
.x(function(d) {
return xScale(d.time);
})
.y(function(d) {
return yScale(d.close);
});
var pie = d3.layout.pie()
.value(function(d) {
return d.time;
})
.sort(null);
// create svg container and offset
var canvas = d3.select("body").append("svg")
.attr({
"width": width,
"height": height
})
.append("g")
.attr("transform", "translate(" + margin.top / 2 + "," + margin.left / 2 + ")");
var color = d3.scale.category20();
// gridsk
canvas.append("svg:rect")
.attr({
"width": width - margin.right - margin.left,
"height": height - margin.bottom - margin.top,
"class": "plot",
"transform": "translate(" + margin.top + "," + margin.bottom + ")"
});
// chart options by type
var chartDraw = {
candle: function() {
canvas.selectAll("line.candle")
.data(sample2)
.enter()
.append("svg:line")
.attr({
"class": "candle alt-view",
"x1": function(d, i) {
return xScale(d.time) - X * 0.5;
},
"x2": function(d, i) {
return xScale(d.time) - X * 0.5;
},
"y1": function(d, i) {
return yScale(d.high);
},
"y2": function(d, i) {
return yScale(d.low);
},
"stroke": "black"
});
canvas.selectAll("rect.candle")
.data(sample2)
.enter()
.append("svg:rect")
.attr({
"class": "candle alt-view",
"width": function(d) {
return X
},
"x": function(d, i) {
return xScale(d.time) - X;
},
"y": function(d, i) {
return yScale(Math.max(d.open, d.close));
},
"height": function(d, i) {
return yScale(Math.min(d.open, d.close)) - yScale(Math.max(d.open, d.close));
},
"fill": function(d) {
return d.open > d.close ? "#dc432c" : "#0CD1AA"
},
"stroke": "gray"
});
},
line: function() {
canvas.append("path")
.datum(sample2)
.attr("class", "line alt-view")
.attr("d", line);
},
pie: function() {
var container = canvas.selectAll(".arc")
.data(pie(sample2))
.enter().append("path")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.attr("class", "pie alt-view")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc)
.each(function(d) {
this._current = d;
});
},
area: function() {
canvas.append("path")
.datum(sample2)
.attr("class", "area alt-view")
.attr("d", area);
}
};
// draw axes
canvas.append('g').classed("axis", true).call(xAxis)
.attr('transform', 'translate(0, ' + (height - margin.bottom) + ')');
canvas.append('g').classed("axis", true).call(yAxis)
.attr('transform', 'translate(' + (width - margin.right) + ', 0)');
// drop down menu
var chartOptions = ["line", "candle", "area", "pie"];
var dropdown = d3.select("body").append("foreignObject")
.attr({
"height": 100,
"width": 300,
"transform": "translate(" + margin.left * 1.3 + "," + margin.top * 0.7 + ")"
})
.append("xhtml:select")
.on("change", function() {
d3.selectAll(".alt-view").remove();
selected = this.value;
if (selected == "line") {
canvas.selectAll(".axis").style("display", "block");
canvas.select(".plot").style("display", "block");
chartDraw.line();
} else if (selected == "area") {
canvas.selectAll(".axis").style("display", "block");
canvas.select(".plot").style("display", "block");
chartDraw.area();
} else if (selected == "candle") {
canvas.selectAll(".axis").style("display", "block");
canvas.select(".plot").style("display", "block");
chartDraw.candle();
} else if (selected == "pie") {
canvas.selectAll(".axis").style("display", "none");
canvas.select(".plot").style("display", "none");
chartDraw.pie();
}
})
.attr("id", "drop-down")
.selectAll("option")
.data(chartOptions)
.enter()
.append("option")
.text(function(d) {
return d;
})
.attr("value", function(d) {
return d;
});
// default chart
chartDraw.line();
.line {
fill: none;
stroke: #0CD1AA;
stroke-width: 3px;
}
.area {
fill: #0cd1aa;
stroke: #dc432c;
stroke-width 0.5;
}
.plot {
fill: lightblue;
opacity: 0.5;
}
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="inlet.js"></script>
<link src="style.css" />
<body></body>
Here is a link to the jsfiddle
http://jsfiddle.net/jaimem/RPGPL/2/
Now the graph shows red color for all the circles.Is dere a way to show random colors on the circles.
Here is the d3.js code
var data = [{ "count": "202", "year": "1590"},
{ "count": "215", "year": "1592"},
{ "count": "179", "year": "1593"},
{ "count": "199", "year": "1594"},
{ "count": "134", "year": "1595"},
{ "count": "176", "year": "1596"},
{ "count": "172", "year": "1597"},
{ "count": "161", "year": "1598"},
{ "count": "199", "year": "1599"},
{ "count": "181", "year": "1600"},
{ "count": "157", "year": "1602"},
{ "count": "179", "year": "1603"},
{ "count": "150", "year": "1606"},
{ "count": "187", "year": "1607"},
{ "count": "133", "year": "1608"},
{ "count": "190", "year": "1609"},
{ "count": "175", "year": "1610"},
{ "count": "91", "year": "1611"},
{ "count": "150", "year": "1612"} ];
function ShowGraph(data) {
d3.selectAll('.axis').remove();
var vis = d3.select("#visualisation").append('svg'),
WIDTH = 500,
HEIGHT = 500,
MARGINS = {
top: 20,
right: 20,
bottom: 20,
left: 30
},
xRange = d3.scale
.linear()
.domain([
d3.min(data, function(d){ return parseInt(d.year, 10);}),
d3.max(data, function(d){ return parseInt(d.year, 10);})
])
.range([MARGINS.left, WIDTH - MARGINS.right]),
yRange = d3.scale
.linear()
.domain([
d3.min(data, function(d){ return parseInt(d.count, 10);}),
d3.max(data, function(d){ return parseInt(d.count, 10);})
])
.range([HEIGHT - MARGINS.top, MARGINS.bottom]),
xAxis = d3.svg.axis() // generate an axis
.scale(xRange) // set the range of the axis
.tickSize(5) // height of the ticks
.tickSubdivide(true), // display ticks between text labels
yAxis = d3.svg.axis() // generate an axis
.scale(yRange) // set the range of the axis
.tickSize(5) // width of the ticks
.orient("left") // have the text labels on the left hand side
.tickSubdivide(true); // display ticks between text labels
var transition = vis.transition().duration(1000).ease("exp-in-out");
transition.select(".x.axis").call(xAxis);
transition.select(".y.axis").call(yAxis);
vis.append("svg:g") // add a container for the axis
.attr("class", "x axis") // add some classes so we can style it
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")") // move it into position
.call(xAxis); // finally, add the axis to the visualisation
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
var circles = vis.selectAll("circle").data(data)
circles.enter()
.append("svg:circle")
.attr("cx", function (d) {
return xRange(d.year);
})
.attr("cy", function (d) {
return yRange(d.count);
})
.style("fill", "red")
circles.transition().duration(1000)
.attr("cx", function (d) {
return xRange(d.year);
})
.attr("cy", function (d) {
return yRange(d.count);
})
.attr("r", 10)
circles.exit()
.transition().duration(1000)
.attr("r", 10)
.remove();
}
you can also use d3.scale.category20(); to get some predefined random colors
Just define color scale as
var color = d3.scale.category20();
Add add fill attribute to the circles as
.attr("fill",function(d,i){return color(i);});
replace .style("fill","red") with
.style("fill",function() {
return "hsl(" + Math.random() * 360 + ",100%,50%)";
})
doc for dynamic properties
For a quick-and-dirty approach to random colors:
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
d3.select("body").selectAll("div")
.data(dataset)
.enter()
.append("div")
.attr("class", "bar")
.style('height',(data) => { return data+'px' })
.style('background-color',() => {
let color = '#'+Math.floor(Math.random() * Math.pow(2,32) ^ 0xffffff).toString(16).substr(-6);
console.log(color);
return color;
})
.bar {
width: 25px;
height: 100px;
display: inline-block;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
May be the Chumliu answer is the first approach, but it has one fault: it will repeat colors and make a confusion for the when read the graphics.
Like this way you have different colors:
var colors = [];
var arr = [];
var j;
products.forEach(function(d)
{
do
{
j = Math.random();
}
while($.inArray(j,arr) != -1);
arr.push(j);
//this gives us different values
var value = parseFloat(d.category_id) + parseFloat(d.total);
eval('colors.cat'+d.category_id+' = "hsl('+ parseFloat('0.'+ value ) * 360 + ',100%,50%)"');
}
later you can use it in D3 like this:
g.append("path").style("fill", function(d)
{
var indexcolor = 'cat'+d.data.category_id; return colors[indexcolor];
});