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>
Related
I am putting together a horizontal bar chart but I am struggling to append the label on the series - I've swapped around the bands - but I am not sure what's missing here - when I tried to get the label displaying then the chart itself breaks
https://bl.ocks.org/caravinden/eb0e5a2b38c8815919290fa838c6b63b
$(document).ready(function() {
var $this = $('.horizontalbarchart');
var data = [{
label: 'Gummi Bears',
value: 20,
},
{
label: 'Butterfinger',
value: 5,
},
{
label: 'Sour Patch Kids',
value: 30,
},
{
label: 'Almond Joy',
value: 40,
},
];
var width = $this.data('width'),
height = $this.data('height');
var color = d3.scaleOrdinal()
.range(["#eb6383", "#fa9191", "#ffe9c5", "#b4f2e1"]);
data.forEach(function(d) {
d.total = +d.value;
});
var margin = {
top: 20,
right: 5,
bottom: 30,
left: 20
},
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom;
var x = d3.scaleLinear()
.range([0, width]);
var y = d3.scaleBand()
.range([height, 0])
.padding(0.1);
x.domain([0, d3.max(data, function(d) {
return d.value;
})]);
y.domain(data.map(function(d) {
return d.total;
}));
var svg = d3.select($this[0])
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr('class', 'barchart')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var bars = svg.append('g').attr('class', 'bars');
bars.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr('fill', function(d, i) {
return color(i);
})
.attr("width", function(d) {
return x(d.total);
})
.attr("y", function(d) {
return y(d.value);
})
.attr("height", y.bandwidth());
bars.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
bars.append("g")
.call(d3.axisLeft(y));
});
body {
background: #eeeeee;
}
#holder {
overflow: hidden;
}
.piechart {
border: 1px solid black;
}
.piechartchart path {
stroke: #cccccc;
stroke-width: 1px;
opacity: 0.8;
}
.piechartchart text {
font-size: 12px;
}
.legend rect {
fill: white;
opacity: 0.8;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://d3js.org/d3.v4.min.js"></script>
<div id="holder">
<div class="horizontalbarchart" data-role="horizontalbarchart" data-width=350 data-height=350></div>
</div>
Consider the following. Just like the way you append the bars, you also append a text element for every value. Then you position them using x() and y(), and give them a value using .text()
$(document).ready(function() {
var $this = $('.horizontalbarchart');
var data = [{
label: 'Gummi Bears',
value: 20,
},
{
label: 'Butterfinger',
value: 5,
},
{
label: 'Sour Patch Kids',
value: 30,
},
{
label: 'Almond Joy',
value: 40,
},
];
var width = $this.data('width'),
height = $this.data('height');
var color = d3.scaleOrdinal()
.range(["#eb6383", "#fa9191", "#ffe9c5", "#b4f2e1"]);
data.forEach(function(d) {
d.total = +d.value;
});
var margin = {
top: 20,
right: 5,
bottom: 30,
left: 80
},
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom;
var x = d3.scaleLinear()
.range([0, width]);
var y = d3.scaleBand()
.range([height, 0])
.padding(0.1);
x.domain([0, d3.max(data, function(d) {
return d.value;
})]);
y.domain(data.map(function(d) {
return d.label;
}));
var svg = d3.select($this[0])
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr('class', 'barchart')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var bars = svg.append('g').attr('class', 'bars');
bars.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr('fill', function(d, i) {
return color(i);
})
.attr("width", function(d) {
return x(d.total);
})
.attr("y", function(d) {
return y(d.label);
})
.attr("height", y.bandwidth());
bars.selectAll(".label")
.data(data)
.enter().append("text")
.attr("class", "label")
.attr('text-anchor', function(d) {
return d.total < 20 ? 'start' : 'end';
})
.attr("x", function(d) {
return d.total < 20 ? x(d.total) + 10 : x(d.total) - 10;
})
.attr("y", function(d) {
return y(d.label) + y.bandwidth() / 2;
})
.attr("dy", 5)
.text(function(d) {
return d.label;
});
bars.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
bars.append("g")
.call(d3.axisLeft(y));
});
body {
background: #eeeeee;
}
#holder {
overflow: hidden;
}
.piechart {
border: 1px solid black;
}
.piechartchart path {
stroke: #cccccc;
stroke-width: 1px;
opacity: 0.8;
}
.piechartchart text {
font-size: 12px;
}
.legend rect {
fill: white;
opacity: 0.8;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://d3js.org/d3.v4.min.js"></script>
<div id="holder">
<div class="horizontalbarchart" data-role="horizontalbarchart" data-width=550 data-height=350></div>
</div>
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>
I'm learing how to plot graphs with D3 and I want to plot on the graph an area ,or similar, to indicate that the dates of the weekend are different than the rest (I have attach and image to explain myself better). What I have right now is the Fiddle I show later.
As you can see, on the data, there are days that don't have values and their respective days are missing.
JSFiddle of what I have accoplish right now:
JSFiddle
var data = [
{"date":"1-May-13","close":58.13},
{"date":"30-Apr-13","close":53.98},
{"date":"27-Apr-13","close":67.00},
{"date":"26-Apr-13","close":89.70},
{"date":"25-Apr-13","close":99.00},
{"date":"24-Apr-13","close":130.28},
{"date":"23-Apr-13","close":166.70},
{"date":"20-Apr-13","close":234.98},
{"date":"19-Apr-13","close":345.44},
{"date":"18-Apr-13","close":443.34},
];
var margin = {top: 20, right: 50, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) { return "$" + formatValue(d); };
var x = d3.time.scale()
.range([0, width]);
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");
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
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 + ")");
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
data.sort(function(a, b) {
return a.date - b.date;
});
x.domain([data[0].date, data[data.length - 1].date]);
y.domain(d3.extent(data, function(d) { return d.close; }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
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("Price ($)");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
focus.select("text").text(formatCurrency(d.close));
}
});
CSS:
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;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
And an image of what I want to accomplish:
Given your x scale domain, which can be better defined with:
x.domain(d3.extent(data, function(d) {
return d.date;
}))
We can populate an array with all the Saturdays between the first date (which is x.domain()[0]) and the last date (which is x.domain()[1]). We only need to find the Saturdays: the bars' width will be Saturday + 2 days (which will cover the whole Saturday and the whole Sunday).
There are several functions to do this, here is one:
function findSat(date1, date2) {
if (date1 > date2) return false;
var saturdays = [];
while (date1 < date2) {
if (date1.getDay() === 6) saturdays.push(new Date(date1));
date1.setDate(date1.getDate() + 1);
}
return saturdays;
}
Using that function, we can populate an array with all the Saturdays between your first and last date:
var rectDate = findSat(x.domain()[0], x.domain()[1]);
Now, we use that rectDate array to create the rectangles:
var rects = svg.selectAll(".rects")
.data(rectDate)
.enter()
.append("rect")
.attr("y", margin.top)
.attr("height", height - margin.bottom)
.attr("x", d => x(d))
.attr("width", d => x(d3.time.day.offset(d, +2)) - x(d))
.attr("fill", "yellow");
Notice that, for the width, we subtract "Saturday + 2 days" from Saturday:
.attr("width", d => x(d3.time.day.offset(d, +2)) - x(d))
Here is your updated fiddle: http://jsfiddle.net/36yaot6t/
And here the same code, in a Stack snippet:
var data = [{
"date": "1-May-13",
"close": 58.13
}, {
"date": "30-Apr-13",
"close": 53.98
}, {
"date": "27-Apr-13",
"close": 67.00
}, {
"date": "26-Apr-13",
"close": 89.70
}, {
"date": "25-Apr-13",
"close": 99.00
}, {
"date": "24-Apr-13",
"close": 130.28
}, {
"date": "23-Apr-13",
"close": 166.70
}, {
"date": "20-Apr-13",
"close": 234.98
}, {
"date": "19-Apr-13",
"close": 345.44
}, {
"date": "18-Apr-13",
"close": 443.34
}, ];
var margin = {
top: 20,
right: 50,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse,
bisectDate = d3.bisector(function(d) {
return d.date;
}).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) {
return "$" + formatValue(d);
};
var x = d3.time.scale()
.range([0, width]);
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");
var line = d3.svg.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.close);
});
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 + ")");
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
data.sort(function(a, b) {
return a.date - b.date;
});
x.domain(d3.extent(data, function(d) {
return d.date;
}))
y.domain(d3.extent(data, function(d) {
return d.close;
}));
function findSat(date1, date2) {
if (date1 > date2) return false;
var saturdays = [];
while (date1 < date2) {
if (date1.getDay() === 6) saturdays.push(new Date(date1));
date1.setDate(date1.getDate() + 1);
}
return saturdays;
}
var rectDate = findSat(x.domain()[0], x.domain()[1]);
var rects = svg.selectAll(".rects")
.data(rectDate)
.enter()
.append("rect")
.attr("y", margin.top)
.attr("height", height - margin.bottom)
.attr("x", d => x(d))
.attr("width", d => x(d3.time.day.offset(d, +2)) - x(d))
.attr("fill", "yellow");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
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("Price ($)");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() {
focus.style("display", null);
})
.on("mouseout", function() {
focus.style("display", "none");
})
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
focus.select("text").text(formatCurrency(d.close));
}
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;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
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>