I am trying to create a chart like below:
While I've created the skeleton of it but stuck on how to fill those areas with multiple colors. I'm using d3 to complete this chart.
My code for reference:
var line = d3.line()
.x(function(d) { return x(d.ind); })
.y(function(d) { return y(d.tot_cases); })
x.domain(data.map(function(d) { return d.ind; }));
y.domain([0, d3.max(data, function(d) { return d.tot_cases; })]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
var lineAndDots = g.append("g")
.attr("class", "line-and-dots")
.attr("transform", "translate(" + ((margin.left + margin.right) / 3) + "," + 0 + ")")
// Data line
lineAndDots.append("path")
.datum(data)
.attr("class", "data-line")
.attr("d", line);
// Data dots
lineAndDots.selectAll("line-circle")
.data(data)
.enter().append("circle")
.attr("class", "data-circle")
.attr("r", 5)
.attr("cx", function(d) { return x(d.ind); })
.attr("cy", function(d) { return y(d.tot_cases); });
g.selectAll("lines-ax")
.data(data)
.enter().append("line")
.attr("class", "line")
.attr("x1", function(d) { return x(d.ind) + margin.right; })
.attr("y1", function(d) { return height - margin.bottom})
.attr("x2", function(d) { return x(d.ind) + margin.right ; })
.attr("y2", function(d) { return y(d.tot_cases); })
.attr("fill", "black")
.attr("stroke", "gray")
.attr("stroke-width", 3);
You can find my entire code in this link.
Any ideas on how to do this is very helpful. Thanks in advance!
Not a clean implementation, since I did not implement select, enter, append pattern of D3, also I add a random color generator, I will leave it to you to clean it up and add your color scheme to the chart
You might notice that the last element missing its color and polygon item since there is no indication on how to add it.
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = [
{"ind": "Examined", tot_cases: 25000},
{"ind": "Notified", tot_cases: 17000},
{"ind": "Initiated", tot_cases: 10000},
{"ind": "HIV Stat. Confirmed", tot_cases: 14000},
{"ind": "HIV Unknown", tot_cases:15000}
]
var stroke_colors = {
"Examined": '#2B597C',
"Notified": "#6D5C7E",
"Initiated": '#BF6D84',
"HIV Stat. Confirmed": '#F1737E',
"HIV Unknown": '#F9B294'
}
var color = ["#2B597C","#6D5C7E","#BF6D84","#F1737E","#F9B294"]
var line = d3.line()
.x(function(d) { return x(d.ind); })
.y(function(d) { return y(d.tot_cases); })
x.domain(data.map(function(d) { return d.ind; }));
y.domain([0, d3.max(data, function(d) { return d.tot_cases; })]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
var lineAndDots = g.append("g")
.attr("class", "line-and-dots")
.attr("transform", "translate(" + ((margin.left + margin.right) / 3) + "," + 0 + ")")
// Data line
lineAndDots.append("path")
.datum(data)
.attr("class", "data-line")
.attr("d", line)
.style('stroke', function(d){
for(i = 0; i < 5; i++){
return stroke_colors[d[i].ind];}})
.style('fill', 'none')
// Data dots
lineAndDots.selectAll("line-circle")
.data(data)
.enter().append("circle")
.attr("class", "data-circle")
.attr("r", 5)
.attr("cx", function(d) { return x(d.ind); })
.attr("cy", function(d) { return y(d.tot_cases); })
g.selectAll("lines-ax")
.data(data)
.enter().append("line")
.attr("class", "line")
.attr("x1", function(d) { return x(d.ind) + margin.right; })
.attr("y1", function(d) { return height})
.attr("x2", function(d) { return x(d.ind) + margin.right ; })
.attr("fill", "black")
.attr("stroke", "#F2F2F2")
.attr("stroke-width", 3);
for(let i=1; i< data.length; i++) {
let points = [];
points[0] = {x: x(data[i-1].ind) + margin.right, y: y(data[i-1].tot_cases)};
points[1] = {x: x(data[i].ind) + + margin.right, y: y(data[i].tot_cases)};
points[2] = {x: x(data[i].ind) + + margin.right, y: height};
points[3] = {x: x(data[i-1].ind) + margin.right, y: height};
points[4] = {x: x(data[i-1].ind) + margin.right, y: y(data[i-1].tot_cases)};
g.append("polygon")
.attr("points", points.map(function(d) { return [d.x,d.y].join(","); }).join(" "))
.attr("stroke","red")
.attr("stroke-width", 2)
.attr('fill', getRandomRgb());
}
let points = [];
points[0] = {x: x(data[data.length - 1].ind) + margin.right, y: y(data[data.length - 1].tot_cases)};
points[1] = {x: x(data[data.length - 1].ind) + margin.right + 150, y: y(data[data.length - 1].tot_cases)};
points[2] = {x: x(data[data.length - 1].ind) + margin.right + 150, y: height};
points[3] = {x: x(data[data.length - 1].ind) + margin.right, y: height};
points[4] = {x: x(data[data.length - 1].ind) + margin.right, y: y(data[data.length - 1].tot_cases)};
g.append("polygon")
.attr("points", points.map(function(d) { return [d.x,d.y].join(","); }).join(" "))
.attr("stroke","red")
.attr("stroke-width", 2)
.attr('fill', getRandomRgb());
function getRandomRgb() {
const num = Math.round(0xffffff * Math.random());
const r = num >> 16;
const g = num >> 8 & 255;
const b = num & 255;
return 'rgb(' + r + ', ' + g + ', ' + b + ')';
}
body {
font-family: 'Droid Sans', sans-serif;
}
.axis {
font-size: 14px;
font-weight: bold;
}
text {
fill: #727075;
stroke: none;
}
.axis path,
.axis line {
fill: none;
stroke: none;
stroke-width: 2px;
shape-rendering: crispEdges;
}
.grid path {
stroke: none;
}
.grid line {
stroke: #E0E0E0;
shape-rendering: crispEdges;
}
.data-line {
fill: none;
stroke: url(#line-gradient);
stroke-width: 1px;
}
.data-circle {
fill: #3C92BA;
}
.axis-title {
text-anchor: end;
fill: #5D6971;
font-weight: normal;
}
.axis-tspan {
font-size: 12px;
}
<!DOCTYPE html>
<html>
<head>
<style>
</style>
</head>
<body>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v5.min.js"></script>
</body>
</html>
Related
I have created line chart and I want to customize the chart by adding the grid lines from the x-axis to the point(if possible) using d3.js or any other suggestion on how to add is helpful. My graph currently is like
It should look like
Sample code
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width - (margin.left + margin.right)]);
var y = d3.scaleLinear().range([height - (margin.top * 2), 0]);
var line = d3.line()
.x(function(d) { return x(d.module); })
.y(function(d) { return y(d.value); });
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = [
{"value": 83, "module": 0},
{"value": 79, "module": 1},
{ "value": 73, "module": 3},
{"value": 71, "module": 4},
{"value": 67, "module": 5},
{"value": 65, "module":6}
]
data.forEach(function(d) {
d.value = +d.value;
d.module = +d.module;
});
x.domain(d3.extent(data, function(d) { return d.module; }));
y.domain([
(Math.floor(d3.min(data, function(d) { return d.value; }) / 10) * 10),
(Math.ceil(d3.max(data, function(d) { return d.value; }) / 10) * 10)
]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(" + ((margin.left + margin.right) / 2) + "," + (height - margin.top) + ")")
.call(d3.axisBottom(x)
.ticks(6)
.tickFormat(function(d) { return 'Module ' + d; })
)
g.append("g")
.attr("class", "axis axis--y")
You can look through my code in the code editor here
Thanks in advance!
I believe this is what you need:
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width - (margin.left + margin.right)]);
var y = d3.scaleLinear().range([height - (margin.top * 2), 0]);
var line = d3.line()
.x(function(d) { return x(d.module); })
.y(function(d) { return y(d.value); });
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = [
{"value": 83, "module": 0},
{"value": 79, "module": 1},
{ "value": 73, "module": 3},
{"value": 71, "module": 4},
{"value": 67, "module": 5},
{"value": 65, "module":6}
]
data.forEach(function(d) {
d.value = +d.value;
d.module = +d.module;
});
x.domain(d3.extent(data, function(d) { return d.module; }));
y.domain([
(Math.floor(d3.min(data, function(d) { return d.value; }) / 10) * 10),
(Math.ceil(d3.max(data, function(d) { return d.value; }) / 10) * 10)
]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(" + ((margin.left + margin.right) / 2) + "," + (height - margin.top) + ")")
.call(d3.axisBottom(x)
.ticks(6)
.tickFormat(function(d) { return 'Module ' + d; })
)
g.append("g")
.attr("class", "axis axis--y")
// Data line and dots group
var lineAndDots = g.append("g")
.attr("class", "line-and-dots")
.attr("transform", "translate(" + ((margin.left + margin.right) / 2) + "," + 0 + ")")
// Data line
lineAndDots.append("path")
.datum(data)
.attr("class", "data-line")
.attr("d", line);
// Data dots
lineAndDots.selectAll("line-circle")
.data(data)
.enter().append("circle")
.attr("class", "data-circle")
.attr("r", 5)
.attr("cx", function(d) { return x(d.module); })
.attr("cy", function(d) { return y(d.value); });
g.selectAll("lines-ax")
.data(data)
.enter().append("line")
.attr("class", "line")
.attr("x1", function(d) { return x(d.module) + margin.right + 10; })
.attr("y1", function(d) { return height - margin.bottom })
.attr("x2", function(d) { return x(d.module) + margin.right + 10; })
.attr("y2", function(d) { return y(d.value); })
.attr("stroke", "gray")
.attr("stroke-width", 3);
/*focus.append("line")
.attr("class", "x-hover-line hover-line")
.attr("y1", 0)
.attr("y2", height);
//focus.select(".x-hover-line").attr("y2", height - y(d.value));*/
body {
font-family: 'Droid Sans', sans-serif;
}
.axis {
font-size: 14px;
font-weight: bold;
}
text {
fill: #727075;
stroke: none;
}
.axis path,
.axis line {
fill: none;
stroke: none;
stroke-width: 2px;
shape-rendering: crispEdges;
}
.grid path {
stroke: none;
}
.grid line {
stroke: #E0E0E0;
shape-rendering: crispEdges;
}
.data-line {
fill: none;
stroke: #3C92BA;
stroke-width: 4px;
}
.data-circle {
fill: #3C92BA;
}
.axis-title {
text-anchor: end;
fill: #5D6971;
font-weight: normal;
}
.axis-tspan {
font-size: 12px;
}
<svg width="730" height="375"></svg>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/5.15.0/d3.js"></script>
I'm trying to write a generic multiline chart function based on Mike Bostock's example (https://bl.ocks.org/mbostock/3884955).
I'm facing an issue wherein, the last tick label on my Monthly graph x-axis does not show up. The last tick appears fine on the Weekly graph x-axis.
JS Fiddle Link:
http://jsfiddle.net/Q5Jag/11879/
I'm suspecting the issue here could be due to the range specified for the x-axis which for some reason ignores the last value. But I'm not exactly sure what is going on here. Could anyone help me debug ?
Here is my code:
function renderMultiLineChart(datafile, chartDiv, xAxisLabel, yAxisLabel, graphCadence){
var margin = {top: 20, right: 60, bottom: 80, left: 60},
width = 760 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%m/%d/%y");
var x = d3.scaleUtc()
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var color = d3.scaleOrdinal(d3.schemeCategory10);
//var xAxis = d3.axisBottom(x).tickFormat(function(d){ return d.x;});
switch(graphCadence) {
case "Daily":
var xAxis = d3.axisBottom(x).ticks(d3.timeDay.every(1)).tickFormat(d3.timeFormat("%m/%d"))
break;
case "Weekly":
var xAxis = d3.axisBottom(x).ticks(d3.timeSaturday.every(1)).tickFormat(d3.timeFormat("%m/%d"))
break;
case "Monthly":
//var xAxis = d3.axisBottom(x).ticks(d3.timeDay.every(1))
var xAxis = d3.axisBottom(x).ticks(d3.timeMonth.every(1)).tickFormat(d3.utcFormat("%m/%d"))
break;
}
var yAxis = d3.axisLeft(y);
var line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.count); })
var div = d3.select(chartDiv).append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var svg = d3.select(chartDiv).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 + ")");
//https://pharos-rest-service-iad.iad.proxy.amazon.com/s3/tool.csv
d3.csv(datafile, function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
//console.log(d);
d.date = parseDate(d.date);
});
var datapoints = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, count: +d[name]};
})
};
});
console.log(data);
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(datapoints, function(c) { return d3.min(c.values, function(v) { return v.count; }); }),
d3.max(datapoints, function(c) { return d3.max(c.values, function(v) { return v.count; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.style("text-anchor", "end")
.attr("transform", "rotate(-45)");
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top + 30) + ")")
.style("text-anchor", "middle")
.text(xAxisLabel);
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")
.style("fill", "black") // set the line colour
.text(yAxisLabel);
var datapoint = svg.selectAll(".datapoint")
.data(datapoints)
.enter().append("g")
.attr("class", "datapoint");
datapoint.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
j = -1;
datapoint.selectAll("circle")
.data(function(d){return d.values})
.enter()
.append("circle")
.attr("r", 3)
.attr("cx", function(d,i) { return x(d.date); })
.attr("cy", function(d) { return y(d.count); })
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", 1);
div.html("<b>"+d.count+"</b>")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
.style("fill", function(d,i) { if (i == 0) { j++ }; return color(datapoints[j].name); });
var legendRectSize = 8;
var legendSpacing = 80;
var legendHolder = svg.append('g')
// translate the holder to the right side of the graph
.attr('transform', "translate(" + (100+margin.left+margin.right) + ","+(height+margin.bottom-20)+")")
var legend = legendHolder.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr("transform", function (d, i) {
if (i === 0) {
dataL = legendRectSize + legendSpacing
return "translate(0,0)"
} else {
var newdataL = dataL
dataL += legendRectSize + legendSpacing
return "translate(" + (newdataL) + ",0)"
}
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + 5)
.attr('y', legendRectSize)
.text(function(d) { return d; });
});
}
renderMultiLineChart("https://gist.githubusercontent.com/techyogii/323024b01c1eb4d0c07637e183e1e6d7/raw/422ed207cc2c38426fa726795ecd963f153135dd/app_usage","div#multiChartMonthly","Snapshot Date","Metric Count","Monthly")
renderMultiLineChart("https://gist.githubusercontent.com/techyogii/8ed38bdb3b8e44194ee8570ef9cc5b75/raw/d0c85aaf9eaa7e8819fd6e6e210885b0cfa6f47d/app_usage_weekly","div#multiChartWeekly","Snapshot Date","Metric Count","Weekly")
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
/*display: none;*/
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
div.tooltip {
position: absolute;
text-align: center;
/*width: 60px;
height: 28px;*/
padding: 4px;
font: 14px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 10px;
pointer-events: none;
}
.legend {
font-size: 12px;
}
rect {
stroke-width: 2;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="multiChartWeekly">
<div id="multiChartMonthly">
Thanks,
Yogesh
I believe the problem lies in a misalignment between how d3.timeMonth works and how your data is formatted. You see that d3.timeMonth is labeling the first of every month, whereas the data is grouped on the last day of every month. So when you call x.domain(d3.extent(data, function(d) { return d.date; }));, the last data point's date is less than the next label would have been.
One potential solution is to change your parse function to bump all your month dates forward by one day to make them line up with the first of the month. See below.
To remove any dates that end mid-month, you can filter the data set after parsing dates to clean it up.
function renderMultiLineChart(datafile, chartDiv, xAxisLabel, yAxisLabel, graphCadence){
var margin = {top: 20, right: 60, bottom: 80, left: 60},
width = 760 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = function(dateString){
if(graphCadence == "Monthly"){
var date = new Date(dateString);
date.setDate(date.getDate()+1);
return date;
}
return d3.timeParse("%m/%d/%y")(dateString);
}
var x = d3.scaleUtc()
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var color = d3.scaleOrdinal(d3.schemeCategory10);
//var xAxis = d3.axisBottom(x).tickFormat(function(d){ return d.x;});
switch(graphCadence) {
case "Daily":
var xAxis = d3.axisBottom(x).ticks(d3.timeDay.every(1)).tickFormat(d3.timeFormat("%m/%d"))
break;
case "Weekly":
var xAxis = d3.axisBottom(x).ticks(d3.timeSaturday.every(1)).tickFormat(d3.timeFormat("%m/%d"))
break;
case "Monthly":
//var xAxis = d3.axisBottom(x).ticks(d3.timeDay.every(1))
var xAxis = d3.axisBottom(x).ticks(d3.timeMonth.every(1)).tickFormat(d3.utcFormat("%m/%d"))
break;
}
var yAxis = d3.axisLeft(y);
var line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.count); })
var div = d3.select(chartDiv).append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var svg = d3.select(chartDiv).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 + ")");
//https://pharos-rest-service-iad.iad.proxy.amazon.com/s3/tool.csv
d3.csv(datafile, function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
if(graphCadence == "Monthly"){
data = data.filter(function(d){
return d.date.getDate() == 1
});
}
var datapoints = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, count: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(datapoints, function(c) { return d3.min(c.values, function(v) { return v.count; }); }),
d3.max(datapoints, function(c) { return d3.max(c.values, function(v) { return v.count; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.style("text-anchor", "end")
.attr("transform", "rotate(-45)");
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top + 30) + ")")
.style("text-anchor", "middle")
.text(xAxisLabel);
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")
.style("fill", "black") // set the line colour
.text(yAxisLabel);
var datapoint = svg.selectAll(".datapoint")
.data(datapoints)
.enter().append("g")
.attr("class", "datapoint");
datapoint.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
j = -1;
datapoint.selectAll("circle")
.data(function(d){return d.values})
.enter()
.append("circle")
.attr("r", 3)
.attr("cx", function(d,i) { return x(d.date); })
.attr("cy", function(d) { return y(d.count); })
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", 1);
div.html("<b>"+d.count+"</b>")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
.style("fill", function(d,i) { if (i == 0) { j++ }; return color(datapoints[j].name); });
var legendRectSize = 8;
var legendSpacing = 80;
var legendHolder = svg.append('g')
// translate the holder to the right side of the graph
.attr('transform', "translate(" + (100+margin.left+margin.right) + ","+(height+margin.bottom-20)+")")
var legend = legendHolder.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr("transform", function (d, i) {
if (i === 0) {
dataL = legendRectSize + legendSpacing
return "translate(0,0)"
} else {
var newdataL = dataL
dataL += legendRectSize + legendSpacing
return "translate(" + (newdataL) + ",0)"
}
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + 5)
.attr('y', legendRectSize)
.text(function(d) { return d; });
});
}
renderMultiLineChart("https://gist.githubusercontent.com/JstnPwll/5a24137a36c9246cf065c58d7f5bb5a5/raw/ff986ee88338e99d10ab93035ffacd3ffe92fd4e/gistfile1.txt","div#multiChartMonthly","Snapshot Date","Metric Count","Monthly")
renderMultiLineChart("https://gist.githubusercontent.com/techyogii/8ed38bdb3b8e44194ee8570ef9cc5b75/raw/d0c85aaf9eaa7e8819fd6e6e210885b0cfa6f47d/app_usage_weekly","div#multiChartWeekly","Snapshot Date","Metric Count","Weekly")
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
/*display: none;*/
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
div.tooltip {
position: absolute;
text-align: center;
/*width: 60px;
height: 28px;*/
padding: 4px;
font: 14px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 10px;
pointer-events: none;
}
.legend {
font-size: 12px;
}
rect {
stroke-width: 2;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="multiChartWeekly">
<div id="multiChartMonthly">
can you resolve this problem.
I am not able to rotate in X-axis values. can you please check below examples. Now x-axis text is coming horizontally but we wants Vertical alignment.
In my requirement is rotate -60 or -90 only. in "Model 1 , Module 2, Module 3" values i needs to rotate.
var margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
padding = 0.3;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], padding);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(function(d) { return dollarFormatter(d); });
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//d3.csv("data.csv", type, function(error, data) {
var data = [{ name :"Module 1",value : 20 },{ name :"Module 2",value :15},{ name :"Module 3 ",value :45},
{ name :"Final Count ",value :200}];
//console.log(data);
// Transform data (i.e., finding cumulative values and total) for easier charting
var cumulative = 0;
for (var i = 0; i < data.length; i++) {
data[i].start = cumulative;
cumulative += data[i].value;
data[i].end = cumulative;
data[i].class = ( data[i].value >= 0 ) ? 'positive' : 'negative'
}
data.push({
name: 'Total',
end: cumulative,
start: 0,
class: 'total'
});
x.domain(data.map(function(d) { return d.name; }));
y.domain([0, d3.max(data, function(d) { return d.end; })]);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
chart.append("g")
.attr("class", "y axis")
.call(yAxis);
var bar = chart.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", function(d) { return "bar " + d.class })
.attr("transform", function(d) { return "translate(" + x(d.name) + ",0)"; });
bar.append("rect")
.attr("y", function(d) { return y( Math.max(d.start, d.end) ); })
.attr("height", function(d) { return Math.abs( y(d.start) - y(d.end) ); })
.attr("width", x.rangeBand());
bar.append("text")
.attr("x", x.rangeBand() / 2)
.attr("y", function(d) { return y(d.end) + 5; })
.attr("dy", function(d) { return ((d.class=='negative') ? '-' : '') + ".75em" })
.text(function(d) { return dollarFormatter(d.end - d.start);});
bar.filter(function(d) { return d.class != "total" }).append("line")
.attr("class", "connector")
.attr("x1", x.rangeBand() + 5 )
.attr("y1", function(d) { return y(d.end) } )
.attr("x2", x.rangeBand() / ( 1 - padding) - 5 )
.attr("y2", function(d) { return y(d.end) } )
//});
function type(d) {
d.value = +d.value;
return d;
}
function dollarFormatter(n) {
n = Math.round(n);
var result = n;
if (Math.abs(n) > 1000) {
result = Math.round(n/1000) + 'K';
}
return result;
}
.bar.total rect {
fill: steelblue;
}
.bar.positive rect {
fill: darkolivegreen;
}
.bar.negative rect {
fill: crimson;
}
.bar line.connector {
stroke: grey;
stroke-dasharray: 3;
}
.bar text {
fill: white;
font: 10px sans-serif;
text-anchor: middle;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<script src="http://d3js.org/d3.v3.min.js"></script>
<svg class="chart"></svg>
To rotate only the first 3 ticks ("module 1", "module 2" and "module 3"):
var ticks = d3.selectAll(".x.axis text").each(function(d, i) {
if (i < 3) {
d3.select(this).attr("y", 0)
d3.select(this).attr("x", 10)
d3.select(this).attr("dy", ".35em")
d3.select(this).attr("transform", "rotate(90)")
d3.select(this).style("text-anchor", "start");
}
});
Check the demo:
var margin = {
top: 20,
right: 30,
bottom: 60,
left: 40
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
padding = 0.3;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], padding);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(function(d) {
return dollarFormatter(d);
});
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//d3.csv("data.csv", type, function(error, data) {
var data = [{
name: "Module 1",
value: 20
}, {
name: "Module 2",
value: 15
}, {
name: "Module 3 ",
value: 45
}, {
name: "Final Count ",
value: 200
}];
//console.log(data);
// Transform data (i.e., finding cumulative values and total) for easier charting
var cumulative = 0;
for (var i = 0; i < data.length; i++) {
data[i].start = cumulative;
cumulative += data[i].value;
data[i].end = cumulative;
data[i].class = (data[i].value >= 0) ? 'positive' : 'negative'
}
data.push({
name: 'Total',
end: cumulative,
start: 0,
class: 'total'
});
x.domain(data.map(function(d) {
return d.name;
}));
y.domain([0, d3.max(data, function(d) {
return d.end;
})]);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var ticks = d3.selectAll(".x.axis text").each(function(d, i) {
if (i < 3) {
d3.select(this).attr("y", 0)
d3.select(this).attr("x", 10)
d3.select(this).attr("dy", ".35em")
d3.select(this).attr("transform", "rotate(90)")
d3.select(this).style("text-anchor", "start");
}
});
chart.append("g")
.attr("class", "y axis")
.call(yAxis);
var bar = chart.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", function(d) {
return "bar " + d.class
})
.attr("transform", function(d) {
return "translate(" + x(d.name) + ",0)";
});
bar.append("rect")
.attr("y", function(d) {
return y(Math.max(d.start, d.end));
})
.attr("height", function(d) {
return Math.abs(y(d.start) - y(d.end));
})
.attr("width", x.rangeBand());
bar.append("text")
.attr("x", x.rangeBand() / 2)
.attr("y", function(d) {
return y(d.end) + 5;
})
.attr("dy", function(d) {
return ((d.class == 'negative') ? '-' : '') + ".75em"
})
.text(function(d) {
return dollarFormatter(d.end - d.start);
});
bar.filter(function(d) {
return d.class != "total"
}).append("line")
.attr("class", "connector")
.attr("x1", x.rangeBand() + 5)
.attr("y1", function(d) {
return y(d.end)
})
.attr("x2", x.rangeBand() / (1 - padding) - 5)
.attr("y2", function(d) {
return y(d.end)
})
//});
function type(d) {
d.value = +d.value;
return d;
}
function dollarFormatter(n) {
n = Math.round(n);
var result = n;
if (Math.abs(n) > 1000) {
result = Math.round(n / 1000) + 'K';
}
return result;
}
.bar.total rect {
fill: steelblue;
}
.bar.positive rect {
fill: darkolivegreen;
}
.bar.negative rect {
fill: crimson;
}
.bar line.connector {
stroke: grey;
stroke-dasharray: 3;
}
.bar text {
fill: white;
font: 10px sans-serif;
text-anchor: middle;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<script src="http://d3js.org/d3.v3.min.js"></script>
<svg class="chart"></svg>
I'm building a d3js chart with horizontal bars and an axis on every bar.
Here is the jsfiddle http://jsfiddle.net/juri33/r5tkL8L1/
Now the scaling is done by this function
xScale.domain([0, d3.max(data, function(d) {
return d.initvalue * 2;
})]);
I would like to scale on every bar with different values -> every bar should get an another axis.
How can i do this? Any ideas?
Here's a quick fix which scales each axis separately:
// an array of scales
// that's 5% larger then the data is representing
var xs = data.map(function(d,i){
return d3.scale
.linear()
.range([0, width])
.domain([0, d.restlifetime + (d.restlifetime * 0.05)]);
});
// set width with appropriate scale
bar.append("rect")
.attr("width", function(d,i) {
return xs[i](d.restlifetime);
})
.attr("height", barHeight - 1);
// draw an axis for each scale
bar.append("g")
.attr("class", "x axis")
.attr("transform", function(d, i) {
return "translate(0, " + scaleOffset + ")";
})
.each(function(d,i){
d3.select(this)
.call(d3.svg.axis()
.scale(xs[i])
.orient("bottom"));
});
Full code:
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 50
},
width = 500 - margin.left - margin.right,
barHeight = 20,
barOffset = 30,
scaleOffset = 19;
var data = [{
bearingname: "B1",
restlifetime: 1000
}, {
bearingname: "B2",
restlifetime: 100
}, {
bearingname: "B3",
restlifetime: 400
}, {
bearingname: "B4",
restlifetime: 300
}];
var x = d3.scale.linear()
.range([0, width]);
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right + 300)
.attr("height", function(d, i) {
return (barHeight + barOffset) * data.length + margin.top + margin.bottom;
})
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xs = data.map(function(d,i){
return d3.scale
.linear()
.range([0, width])
.domain([0, d.restlifetime + (d.restlifetime * 0.05)]);
});
var bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) {
return "translate(0," + i * (barHeight + barOffset) + ")";
});
bar.append("rect")
.attr("width", function(d,i) {
return xs[i](d.restlifetime);
})
.attr("height", barHeight - 1);
bar.append("g")
.attr("class", "x axis")
.attr("transform", function(d, i) {
return "translate(0, " + scaleOffset + ")";
})
.each(function(d,i){
d3.select(this)
.call(d3.svg.axis()
.scale(xs[i])
.orient("bottom"));
});
bar.append("text")
.attr("x", function(d,i) {
return xs[i](d.restlifetime) - 3;
})
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d) {
return d.restlifetime + " h";
});
bar.append("text")
.attr("x", 520)
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.style("fill", "black")
.text(function(d) {
return d.bearingname;
});
bar.append("text")
.attr("x", 600)
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.style("fill", "black")
.html("S 0, min");
.chart rect {
fill: green;
}
.chart text {
fill: white;
font: 10px sans-serif;
text-anchor: end;
}
.bar text {
fill: black;
}
.axis text {
font: 10px sans-serif;
fill: black;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg class="chart"></svg>
I wanted to use the Sortable Bar Chart of Mike Bostock without it's transition property and sort the bars according to their lenght but I couldn't. I want the bars just like this. without interactivity.
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<style>
body {
font: 10px sans-serif;
}
.bar rect {
fill: steelblue;
}
.bar text {
fill: white;
}
.axis path, .axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
</style>
<script src="http://mbostock.github.com/d3/d3.js"></script>
<script>
var margin = {top: 0, right: 10, bottom: 20, left: 10},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var index = d3.range(24),
data = index.map(d3.random.normal(100, 10));
var x = d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, width]);
var y = d3.scale.ordinal()
.domain(index)
.rangeRoundBands([0, height], .1);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var bar = svg.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d, i) { return "translate(0," + y(i) + ")"; });
bar.append("rect")
.attr("height", y.rangeBand())
.attr("width", x);
bar.append("text")
.attr("text-anchor", "end")
.attr("x", function(d) { return x(d) - 6; })
.attr("y", y.rangeBand() / 2)
.attr("dy", ".35em")
.text(function(d, i) { return i; });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.svg.axis()
.scale(x)
.orient("bottom"));
//var sort = false;
//setInterval(function() {
// if (sort = !sort) {
// index.sort(function(a, b) { return data[a] - data[b]; });
// } else {
// index = d3.range(24);
// }
// y.domain(index);
// bar.transition()
// .duration(750)
// .delay(function(d, i) { return i * 50; })
// .attr("transform", function(d, i) { return "translate(0," + y(i) + ")"; });
//}, 5000);
var hierarchy = d3.layout.partition()
.data(function(d) { return d.data; });
</script>
I removed the the code from var sort = false; part and added
var hierarchy =.. part but It's still not working. How can I make it?
Any help will be appreciated.
Thanks.
You should add the following line to sort the values:
index.sort(function(a, b) { return data[b] - data[a]; });
Check out the jsfiddle: http://jsfiddle.net/k9rcyeyo/