How to unsqueezed the y-axis in D3.js - javascript

I have a this script which try to plot the x and y-axis:
var margin = {top: 100, right: 100, bottom: 100, left: 100},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain(["apple", "orange", "banana"])
.rangePoints([0, width]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
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")
.call(xAxis);
var y = d3.scale.ordinal()
.domain(["1", "2", "3"])
.rangePoints([0, 3]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
As you can see upon running the code the y-axis is squeezed down. How can I unsqueezed it?

You need to set your y range correctly
var y = d3.scale.ordinal()
.domain(["1", "2", "3"])
.rangePoints([height, 0]);
From the documentation (https://github.com/mbostock/d3/wiki/Ordinal-Scales#ordinal_rangePoints),
# ordinal.rangePoints(interval[, padding])
Sets the output range from the specified continuous interval. The
array interval contains two elements representing the minimum and
maximum numeric value. This interval is subdivided into n
evenly-spaced points, where n is the number of (unique) values in the
input domain.
You input domain has 3 values which you want to space out over the height of the chart.
Stack Snippet
You might also want to translate your x axis to the bottom (if not, just revert the translate on the x axis)
var margin = {top: 100, right: 100, bottom: 100, left: 100},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain(["apple", "orange", "banana"])
.rangePoints([0, width]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
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")
.call(xAxis)
.attr("transform", "translate(0, " + height + ")");;
var y = d3.scale.ordinal()
.domain(["1", "2", "3"])
.rangePoints([height, 0]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>

Related

How to add custom tick labels in d3.js?

I want to add custom tick labels on the x axis,like 1,2,3,4,3,2,1 in this pattern. But the code that I am using doesn't show the decreasing numbers.
var margin = {
top: 100,
right: 100,
bottom: 100,
left: 100
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain([1, 2, 3, 4, 5, 4, 3, 2, 1])
.rangePoints([0, width]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
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")
.call(xAxis);
Any kind of help would be appreciated. Thanks.
Little hack it needed to solve this issue.
Cause
d3.scale.ordinal(), domain calculation in purely mathematical logic. Each
domain associated with a range. ( f(x)=y ).
Duplication not allowed because it will make ambiguity
Solution
Create linear scale with total item in the axis as domain [0, itemLength]
While creating axis use tickFormat to find out the index of the element
var margin = {
top: 100,
right: 100,
bottom: 100,
left: 100
},
width = 560 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var xdata = ["1", "2", "3", "4", "5", "4", "3", "2", "1", "0"];
var linear = d3.scale.linear()
.domain([0, 10])
.range([0, width]);
var xAxis = d3.svg.axis()
.scale(linear)
.orient("bottom");
var axis = d3.svg.axis()
.scale(linear)
.orient("top")
.ticks(10)
.tickFormat(function (d) {
return xdata[d];
});
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")
.call(axis);
.axis path, line {
fill: none;
stroke: #000;
stroke-linecap: round;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

D3.js Adjust labels closer to each other

I'm graphing data with long Y-axis labels (temperature ranges). How do I adjust the labels so that they're centered on the ticks when they're rotated 90 degrees and don't run off the edge of the graph? I've attempted to use this.getBBox() to apply a transform based on the iteration of the label, but that doesn't seem to work.
Thanks!
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 100, right: 100, bottom: 100, left: 100},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var categories = {
temperature: ["29-30°C - Red","31-33° C - Green","> 33° C - Blue"],
sleep: ["7 - 8 hours", "5 - 6 hours", "4 or less hours"]
}
var mindate = new Date(2012,0,1),
maxdate = new Date(2012,0,31);
var xScale = d3.time.scale()
.domain([mindate, maxdate]) // values between for month of january
.range([0, width - margin.right]);
var xAxis = d3.svg.axis()
.orient("bottom")
.scale(xScale);
var yKey = "temperature";
var yScale = d3.scale.ordinal()
.domain(categories[yKey])
.rangePoints([0, height]);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
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", "yAxis axis")
.call(yAxis)
.selectAll("text")
.attr("x", 10)
.attr("y",20)
.attr("transform", "rotate(90)")
.style("text-anchor", "start")
</script>
Here's what I've tried but this doesn't seem to move the labels much. I'm not sure how to set the "x" inside the following function without using a translate.
d3.selectAll(".yAxis text")
.attr("transform", function(d,i) {
return "translate(" + -20 + "," + ((this.getBBox().width/(i+2))) + ")rotate(-90)"
})
Aha! The answer is that d3.scale.ordinal has a padding setting, so all I have to do is change my yScale to
var yScale = d3.scale.ordinal()
.domain(categories[yKey])
.rangePoints([0, height],1);
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 100, right: 100, bottom: 100, left: 100},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var categories = {
temperature: ["29-30°C - Red","31-33° C - Green","> 33° C - Blue"],
sleep: ["7 - 8 hours", "5 - 6 hours", "4 or less hours"]
}
var mindate = new Date(2012,0,1),
maxdate = new Date(2012,0,31);
var xScale = d3.time.scale()
.domain([mindate, maxdate]) // values between for month of january
.range([0, width - margin.right]);
var xAxis = d3.svg.axis()
.orient("bottom")
.scale(xScale);
var yKey = "temperature";
var yScale = d3.scale.ordinal()
.domain(categories[yKey])
.rangePoints([0, height],1);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
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", "yAxis axis")
.call(yAxis)
.selectAll("text")
.attr("x", 10)
.attr("y",20)
.attr("transform", "rotate(90)")
.style("text-anchor", "middle")
</script>

How to display d3 elements on a gridster box?

I am trying to create an area chart using d3, using this array:
var jsonResObj = {
initial_hours: [
1800, 1700, 1030, 1130, 950, 1249, 1225, 1821, 1250,
1505, 38, 130, 1520, 1600, 1330, 1930, 1806, 1535
]
};
The code for the axis and the chart is here:
var margin = {top: 20, right: 20, bottom: 40, left: 50},
width = 350 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom,
days = jsonResObj.initial_hours.length;
var x = d3.scale.linear()
.domain([0, days])
.range([0, width]);
var y = d3.scale.linear()
.domain([0, d3.max(jsonResObj.initial_hours)])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var area = d3.svg.area()
.x(function(d) { return x(days); })
.y0(height)
.y1(function(d) { return y(jsonResObj.initial_hours); });
var svg = d3.select("#box1").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("path")
.datum(jsonResObj)
.attr("class", "area")
.attr("d", area);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
My Gridster box:
<li data-sizey="3" data-sizex="3" data-col="3" data-row="1">
<div class="gridster-box" id="box1">
<div class="handle-resize"></div>
</div>
</li>
When I load my page, only the axes show up and the area selector
is 0px * 0px
How do I draw these area charts in my gridster box?
You need to transform the data so each data point is an object containing the x and y properties and can properly be accessed by your area function.
The way you have it currently, there is no way for d3 to know which day or hour an area data point is referring to.
See code below showing changes to the area function to refer to the day and hour properties of the data object passed via function(d). The data transformation is right after the svg variable declaration. Here's a working fiddle of the solution.
var jsonResObj = {
initial_hours: [
1800, 1700, 1030, 1130, 950, 1249, 1225, 1821, 1250,1505, 38, 130, 1520, 1600, 1330, 1930, 1806, 1535
]
};
var margin = {top: 20, right: 20, bottom: 40, left: 50},
width = 350 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom,
days = jsonResObj.initial_hours.length;
var x = d3.scale.linear()
.domain([0, days])
.range([0, width]);
var y = d3.scale.linear()
.domain([0, d3.max(jsonResObj.initial_hours)])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var area = d3.svg.area()
.x(function(d) { return x(d.day); })
.y0(height)
.y1(function(d) { return y(d.hour); });
var svg = d3.select("#box1").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 data = [];
jsonResObj.initial_hours.forEach(function(d,i){
data.push({day: i, hour: d})
});
svg.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(0,0)")
.call(yAxis);

Function is not correctly plotted + cosmetic questions d3js

I have two questions. I am trying to plot a function with d3.js. I have already come far, but I have two problems.
My code currently; https://jsfiddle.net/v0du66ey/
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.grid .tick {
stroke: lightgrey;
opacity: 0.7;
}
.grid path {
stroke-width: 0;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 50, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
padding = 50;
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 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 data = [];
for (var k = 0; k < 100; k++) {
data.push({x: k, y: k});
}
var line = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
// Define x domain
x.domain([-10, 10]);
// Define y domain
y.domain([-10, 10]);
// Add x axis
svg.append("g")
.attr("class","x axis")
.attr("transform","translate(0," + height + ")")
.call(xAxis)
// Add y axis
svg.append("g")
.attr("class","y axis")
.call(yAxis);
// Add x grid
svg.append("g")
.attr("class","grid")
.attr("transform","translate(0," + height + ")")
.call(xAxis
.tickSize(-height,-height,0)
.tickFormat("")
);
// Add y grid
svg.append("g")
.attr("class","grid")
.call(yAxis
.tickSize(-width,-width,0)
.tickFormat("")
);
// Add x axis label
svg.append("text")
.attr("transform", "translate(" + (width / 2) + "," + (height + margin.bottom) + ")")
.style("font-size","15")
.style("text-anchor", "middle")
.text("x axis");
// Add y axis label
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y",0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("font-size","15")
.style("text-anchor", "middle")
.text("y axis");
svg.append("path")
.attr("class", "line")
.attr("d",line(data));
</script>
As you can see the function which I have defined, y = x. Is not correctly plotted along its entire domain. It goes for x from -10 to approx 2.5 and y from 10 to approx 7.5. What goes wrong here? I do not namely see it.
Furthermore I have a cosmetic question. I am trying to create a border around the whole plot on the axis and trying to get the ticks bars to point to the inside of the graph instead of outside. In other words, I want to have it more looking like, a Matlab plot,
About cosmetic question: you need to set innerTickSize(), outerTickSize() and tickPadding() on your axises with a negative numbers.
About main question:
as far as you have scales you should set line's x and y data as a result of scale functions.
so your line code will look like this:
var line = d3.svg.line()
.x(function(d) { return x(d.x); })
.y(function(d) { return y(d.y); })
.interpolate("linear");
Here is jsfiddle with updated sample http://jsfiddle.net/n3Lndkum/

d3.js multiple series line chart - color of each series

With a multiple series line chart D3.js is it possible to manually specify the colour of each line?
data.csv
source_,track_index,alt,dist
series1,xxx,100,100
series1,xxx,200,200
series2,xxx,100,100
series2,xxx,200,200
.html file
<!DOCTYPE html>
<style>
body { font: 12px Arial;}
path {stroke: steelblue;stroke-width: 2;fill: none;}
.axis path,.axis line {fill: none;stroke: grey;stroke-width: 1;shape-rendering: crispEdges;}
.line {fill: none;stroke: steelblue;stroke-width: 1.5px;}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 30, right: 20, bottom: 30, left: 50},width = 1400 - margin.left - margin.right,height = 600 - margin.top - margin.bottom;
var parseDate = d3.time.format("%b %Y").parse; // Parse the date / time
var color = d3.scale.category10();
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 alt_line = d3.svg.line()
.x(function(d) { return x(d.dist_); })
.y(function(d) { return y(d.alt_); });
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("/data.csv", function(error, data) {
data.forEach(function(d) {
d.dist_ = d.dist;
d.alt_ = d.alt;
});
x.domain([0, 30]);
y.domain([0, 3000]);
var dataNest = d3.nest()
.key(function(d) {return d.source_;})
.entries(data);
dataNest.forEach(function(d) {
svg.append("path")
.attr("class", "line")
.attr("d", alt_line(d.values));
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
</script>
</body>

Categories