Im new to d3js, i want to arrange the grid lines manually , i will share what result im getting and what i want. please check the screenshot ,two different images are there.
1st image is the output that im getting from the code below, but i want my result like the second image.
[<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Line Chart</title>
<style>
.axis path,
.axis line{
fill: none;
stroke: black;
}
.line{
fill: none;
stroke: blue;
stroke-width: 2px;
}
.tick text{
font-size: 12px;
}
.tick line{
opacity: 1;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
var margin = {top: 20, right: 100, bottom: 30, left: 100},
width = 350 ;
height = 350 ;
var dataset = \[
{x: 0, y: 0},
{x: 1, y: 0.5},
{x: 2, y: 1},
{x: 3, y: 1.5},
{x: 4, y: 2},
{x: 5, y: 2.5},
{x: 6, y: 3},
\];
var xScale = d3.scale.linear()
.domain(\[0, d3.max(dataset, function(d){ return d.x; })\])
.range(\[0, width\]);
var yScale = d3.scale.linear()
.domain(\[0, d3.max(dataset, function(d){ return d.y; })\])
.range(\[height, 0\]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.innerTickSize(-height)
.outerTickSize(0)
.tickPadding(10);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.innerTickSize(-width)
.outerTickSize(0)
.tickPadding(10);
var line = d3.svg.line()
.x(function(d) { return xScale(d.x); })
.y(function(d) { return yScale(d.y); });
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 + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
svg.append("path")
.data(\[dataset\])
.attr("class", "line")
.attr("d", line);
</script>
</body>
</html>]
Just set the number of ticks in the x axis generator:
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.innerTickSize(-height)
.outerTickSize(0)
.tickPadding(10)
.ticks(5);
Here is a demo:
var margin = {top: 20, right: 100, bottom: 30, left: 100},
width = 350 ;
height = 350 ;
var dataset = [
{x: 0, y: 0},
{x: 1, y: 0.5},
{x: 2, y: 1},
{x: 3, y: 1.5},
{x: 4, y: 2},
{x: 5, y: 2.5},
{x: 6, y: 3},
];
var xScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d){ return d.x; })])
.range([0, width]);
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d){ return d.y; })])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.innerTickSize(-height)
.outerTickSize(0)
.tickPadding(10)
.ticks(5);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.innerTickSize(-width)
.outerTickSize(0)
.tickPadding(10);
var line = d3.svg.line()
.x(function(d) { return xScale(d.x); })
.y(function(d) { return yScale(d.y); });
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 + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
svg.append("path")
.data([dataset])
.attr("class", "line")
.attr("d", line);
.axis path,
.axis line{
fill: none;
stroke: black;
}
.line{
fill: none;
stroke: blue;
stroke-width: 2px;
}
.tick text{
font-size: 12px;
}
.tick line{
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Related
I created a simple d3js vertical bar chart. I understand that typically, to create gridlines, I would use the "tickSize" call, and give them a height or width similar to that of the axis.
var yGridLine = d3.svg.axis()
.scale(yScale)
.tickSize(-width, 0 ,0)
.tickFormat("")
.orient("left");
The above code would create horizontal gridlines. So if I want to create vertical gridlines, then I would modify the orientation and reference axix (something similar to the following untested yet hypothetically correct code)
var xGridLine = d3.svg.axis()
.scale(xScale)
.tickSize(-height, 0 ,0)
.tickFormat("");
Now, the problem is, when using this approach, then the vertical gridlines are created in the middle of the vertical bars (or in the case of horizontal bar charts, then horizontal gridline are created in the middle of the horizontal bars), which is not visually pleasant and not according to requirements. What I want is to have the vertical gridlines appear between the vertical bars (i.e., at the centre points between the ticks). How do I do that?
Example
In this link, you will find a number of charts, where the vertical gridlines are between the ticks, not at the centre. This is what I like to achieve, and my question is how do I achieve that?
Thanks.
The whole code:
var data = [{
name: "Hemant",
age: 20
}, {
name: "Vinay",
age: 55
}, {
name: "Vikas",
age: 56
}, {
name: "Arun",
age: 88
}, {
name: "Varun",
age: 34
}, {
name: "Ajay",
age: 77
}],
w = 600,
h = 300,
margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
var mySvg = d3.select("body").append("svg").attr({
width: w,
height: h
}).append("g")
.attr("transform", 'translate(' + margin.left + ',' + margin.top + ')');
var xScale = d3.scale.ordinal()
.domain(data.map(function(d) {
return d.name;
}))
.rangeBands([0, width]);
var yScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) {
return d.age;
})])
.range([height, 0]);
var linearColorScale = d3.scale.linear()
.domain([0, data.length])
.range(["#e74c3c", "#8e44ad"]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
var yGridLine = d3.svg.axis()
.scale(yScale)
.tickSize(-width, 0, 0)
.tickFormat("")
.orient("left");
var ordinalColorScale = d3.scale.category20();
mySvg.append("g")
.classed("gridLine", true)
.attr("transform", "translate(0,0)")
.call(yGridLine);
mySvg.selectAll("rect").data(data).enter()
.append("rect")
.attr("x", function(d) {
return xScale(d.name);
})
.attr("y", function(d, i) {
return yScale(d.age);
})
.attr("width", function(d) {
return xScale.rangeBand();
})
.attr("height", function(d) {
return height - yScale(d.age)
})
.style("fill", function(d, i) {
return ordinalColorScale(i);
})
mySvg.selectAll("text").data(data)
.enter()
.append("text")
.classed("bar", true)
.attr("x", function(d) {
return xScale(d.name) + xScale.rangeBand() / 2;
})
.attr("dx", 0)
.attr("y", function(d, i) {
return yScale(d.age);
})
.attr("dy", -6)
.text(function(d, i) {
return d.age;
});
mySvg.append("g")
.classed("axis", true)
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
mySvg.append("g")
.classed("axis", true)
.attr("transform", "translate(0,0)")
.call(yAxis);
svg {
border: 1px solid #ccc;
}
svg rect {
shape-rendering: crispedges;
}
.bar {
fill: #000;
text-anchor: middle;
font-size: 20px;
}
.axis path,
.axis line {
fill: none;
shape-rendering: crispedges;
stroke: #666;
}
.gridLine path,
.gridLine line {
fill: none;
shape-rendering: crispedges;
stroke: #e4e4e4;
}
<script src="http://d3js.org/d3.v3.min.js"></script>
You could achieve this by simply translating .gridLines by xScale.rangeBand() / 2 - i.e. half the width of a bar.
var data = [{
name: "Hemant",
age: 20
}, {
name: "Vinay",
age: 55
}, {
name: "Vikas",
age: 56
}, {
name: "Arun",
age: 88
}, {
name: "Varun",
age: 34
}, {
name: "Ajay",
age: 77
}],
w = 600,
h = 300,
margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
var mySvg = d3.select("body").append("svg").attr({
width: w,
height: h
}).append("g")
.attr("transform", 'translate(' + margin.left + ',' + margin.top + ')');
var xScale = d3.scale.ordinal()
.domain(data.map(function(d) {
return d.name;
}))
.rangeBands([0, width]);
var yScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) {
return d.age;
})])
.range([height, 0]);
var linearColorScale = d3.scale.linear()
.domain([0, data.length])
.range(["#e74c3c", "#8e44ad"]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
var yGridLine = d3.svg.axis()
.scale(xScale)
.tickSize(-height, 0, 0)
.tickFormat("");
var ordinalColorScale = d3.scale.category20();
mySvg.append("g")
.classed("gridLine", true)
.attr("transform", "translate(" + [xScale.rangeBand() / 2, height] + ")")
.call(yGridLine);
mySvg.selectAll("rect").data(data).enter()
.append("rect")
.attr("x", function(d) {
return xScale(d.name);
})
.attr("y", function(d, i) {
return yScale(d.age);
})
.attr("width", function(d) {
return xScale.rangeBand();
})
.attr("height", function(d) {
return height - yScale(d.age)
})
.style("fill", function(d, i) {
return ordinalColorScale(i);
})
mySvg.selectAll("text").data(data)
.enter()
.append("text")
.classed("bar", true)
.attr("x", function(d) {
return xScale(d.name) + xScale.rangeBand() / 2;
})
.attr("dx", 0)
.attr("y", function(d, i) {
return yScale(d.age);
})
.attr("dy", -6)
.text(function(d, i) {
return d.age;
});
mySvg.append("g")
.classed("axis", true)
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
mySvg.append("g")
.classed("axis", true)
.attr("transform", "translate(0,0)")
.call(yAxis);
svg {
border: 1px solid #ccc;
}
svg rect {
shape-rendering: crispedges;
}
.bar {
fill: #000;
text-anchor: middle;
font-size: 20px;
}
.axis path,
.axis line {
fill: none;
shape-rendering: crispedges;
stroke: #666;
}
.gridLine path,
.gridLine line {
fill: none;
shape-rendering: crispedges;
stroke: #e4e4e4;
}
<script src="http://d3js.org/d3.v3.min.js"></script>
I am new to d3 and am trying to draw mean line through all the bars in the bar chart but not quite able to achieve that. Below is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: #444;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script>
var data=[
{"letter": "BU", "higher": .08,"lower": .05},
{"letter": "AU", "higher": .05,"lower": .03},
{"letter": "LA", "higher": .04,"lower": .02}
]
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x2 = d3.scale.ordinal()
.rangeBands([0, width], 0);
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(formatPercent);
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.higher = +d.higher;
d.lower = +d.lower;
});
x.domain(data.map(function(d) { return d.letter; }));
x2.domain(data.map(function(d) { return d.letter; }));
y.domain([0, d3.max(data, function(d) { return d.higher; })]);
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("Frequency");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.higher); })
.attr("height", function(d) { return height - y(d.higher-d.lower); });
var dataSum = d3.mean(data, function(d) { return (d.higher + d.lower); });
var line = d3.svg.line()
.x(function(d, i) {
return x(d.letter) + i; })
.y(function(d, i) { return y(dataSum/data.length); });
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
</script>
</body>
</html>
The proper code is here'http://jsbin.com/beyakumohi/1/edit?html' . The line should pass through center of each bars but it only happens for the 3rd bar and that too it do not cross it. Is there any mistake in my code.
d3.mean will give you the mean value of the full array. Meaning, that in this case you will get the mean of:
data[0].higher + data[0].lower + data[1].higher + data[1].lower + data[2].higher + data[2].lower
In this case I would say it is more appropiate to edit your line function as following
var line = d3.svg.line()
.x(function(d, i) {
return x(d.letter); })
.y(function(d, i) { return y((d.higher + d.lower) / 2); });
I'm trying to add some padding between my bars, but can't control,say understand, it accurately.
Here's the code snippet I'm following from here:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.bar {
fill: steelblue;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
</style>
<svg class="chart"></svg>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
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 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.tsv("data.tsv", type, function(error, data) {
x.domain(data.map(function(d) { return d.name; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
chart.append("g")
.attr("class", "y axis")
.call(yAxis);
chart.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.attr("width", x.rangeBand());
});
function type(d) {
d.value = +d.value; // coerce to number
return d;
}
</script>
Data.dsv file content:
name value
A 12
B 13
C 22
D 5
Then, we you load it and query from developer's console, you know
> x.range()
[24, 258, 492, 726]
> x.rangeBand()
211
, but I wondered how these numbers be determined, the internal calcuation.Any help would be much appreciated!
I've created a line graph with d3.nest() objects, but I need the fill color for each segment to be based on another variable. I thought I could just do it based on the gradient from the data file, but it actually needs to be computed over the distance of the segment. Right now, everything is coming back as one color when it should be
if gradient < -10
color = red
if gradient < -5
color = green
if gradient < 0
color = white
if gradient < 5
color = yellow
if gradient < 10
color = black
else
color = blue
Here's a Plunk
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 12px Arial;
}
text.shadow {
stroke: #fff;
stroke-width: 2.5px;
opacity: 0.9;
}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.grid .tick {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
.area {
stroke-width: 0;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 30, right: 20, bottom: 35, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var color = d3.scale.ordinal()
.domain([-10,-5,0,5,10])
.range(['red','green','white','yellow','black','blue']);
var x = d3.scale.linear().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
var area = d3.svg.area()
.x(function(d) { return x(d.distance); })
.y0(height)
.y1(function(d) { return y(d.elevation); });
var valueline = d3.svg.line()
.x(function(d) { return x(d.distance); })
.y(function(d) { return y(d.elevation); });
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 + ")");
// function for the x grid lines
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5)
}
// function for the y grid lines
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
}
// Get the data
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.distance = +d.distance;
d.elevation = +d.elevation;
d.gradient = +d.gradient;
});
var dataGroup = d3.nest()
.key(function(d) {
return d.grade;
})
.entries(data);
dataGroup.forEach(function(group, i) {
if(i < dataGroup.length - 1) {
group.values.push(dataGroup[i+1].values[0])
}
})
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.distance; }));
y.domain([0, d3.max(data, function(d) { return d.elevation; })]);
dataGroup.forEach(function(d, i){
svg.append("path")
.datum(d.values)
.attr("class", "area")
.attr("d", area);
});
svg.selectAll(".area")
.style("fill", function(d) { return color(d.gradient); });
// Draw the x Grid lines
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
// Draw the y Grid lines
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
// Add the valueline path.
svg.append("path")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// Add the text label for the X axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height+margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Distance");
// Add the text label for the Y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("x", margin.top - (height / 2))
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("");
// Add the title
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Elevation Graph");
});
</script>
</body>
The issue is with this call:
svg.selectAll(".area")
.style("fill", function(d) { return color(d.gradient); });
Here, "d" is an array of objects of length one or two depending on the index. I don't know which object's gradient you wish to use, but my naive solution without understanding your data would be to use d[0]. Here's the Plunk.
When running the following code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
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;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%e-%m-%Y").parse;
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.value); });
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 + ")");
d3.csv("http://localhost/webserver/data/downloads.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain(d3.extent(data, function(d) { return d.value; }));
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);
});
</script>
I get the following error:
Uncaught TypeError: Cannot read property 'length' of undefined d3.v3.js:7296
That line has the following description:
function d3_time_parse(date, template, string, j) {
var c, p, i = 0, n = template.length, m = string.length;
My source data looks like the following:
Date;Value
23-4-2012;12
24-4-2012;10
25-4-2012;13
26-4-2012;24
27-4-2012;45
your csv should have comma , as a separator and attributes are case sensitive. Try this:
date,value
23-4-2012,12
24-4-2012,10
25-4-2012,13
26-4-2012,24
27-4-2012,45