Below code draws a circle and an x axis. There are a couple of problems. The y axis is not displayed but it is being added :
svgContainer.append('g')
.attr("class", "axis")
.call(yAxis);
The x axis is not being aligned to bottom but I have set the orientation to bottom :
orient("bottom").ticks(5);
here is complete code :
<!DOCTYPE html>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<script>
var svgContainer = d3.select("body").append("svg")
.attr("width", 1000)
.attr("height", 1000);
var circle = svgContainer.append("circle")
.attr("cx", 150)
.attr("cy", 150)
.attr("r", 100)
.attr("fill", "none")
.attr("stroke" , "red")
.attr("stroke-width" , 2);
var x = d3.scale.linear().range([0, 1000]);
var y = d3.scale.linear().range([0, 1000]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
svgContainer.append('g')
.attr("class", "axis")
.call(xAxis);
svgContainer.append('g')
.attr("class", "axis")
.call(yAxis);
</script>
</body>
</html>
fiddle : http://jsfiddle.net/zzz8svuq/1/
Why are these issues occurring ?
Setting the orientation only affects the placement of the labels with respect to the axis line, D3 won't automatically position the axis on the canvas for you. The way this is usually done is to set a margin for the axes and offset the containers accordingly:
svgContainer.append('g')
.attr("class", "axis")
.attr("transform", "translate(" + margin + "," + (1000 - margin) + ")")
.call(xAxis);
svgContainer.append('g')
.attr("class", "axis")
.attr("transform", "translate(" + margin + ",0)")
.call(yAxis);
Complete demo here.
Related
I have the following example:
Please note that this code is just a combination of code I have found online.
Is there a way to prevent the Axis label/title from overlapping the axis scale/numbers? For example here the label is overlapping the numbers. In this example I could manually hardcode the label to be positioned more to the left which would work. However, what happens when we use changing data?
Say the data in the graph changes such that the y axis number may be in the 10s in one example but the next data set may have values in the 1,000,000's. Is it possible to make the graph/axis titles more dynamic/responsive to changing number lengths?
Is this something that can be done in the chart setup or is this as css issue. All suggestions or solutions are welcome.
I do not have much experience with D3.js so this may be a very simple issue to fix, I hope someone can help.
Thank you
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
var width = 400,
height = 400;
var margin = {top: 50, bottom: 50, left: 50, right: 50}
var data = [0, 15, 20, 25, 30];
// Append SVG
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
// Create scale
var scale = d3.scaleLinear()
.domain([ d3.max(data) , d3.min(data)])
.range([0, width - 100]);
var yAxis = d3.axisLeft()
.scale(scale);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + eval(margin.left-3) + ",0)")
.call(yAxis);
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("y", 6)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("My testing title");
d3.selectAll(".tick text")
.attr("x", "-20");
</script>
</body>
I usually go with the title coming down the right side:
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + eval(margin.left-3) + ",0)")
.call(yAxis)
.append("text")
.text("Title")
.attr("transform","rotate(90)")
.attr("y",-2)
.style('fill','black')
.style("text-anchor","start")
I have a chart with alot of data that means I have a scroller over the x axis.
when I scroll over the X axis Y axis disappear.
can i set to Y axis position fixed. ( always see this Y axis)?
https://jsfiddle.net/ou28se1z/1/
I tried to add .attr("position", "fixed") but it doesnt work
//Add Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.attr("position", "fixed")
.call(yAxis);
I also tried to do .style("position", "fixed")
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.style("position", "fixed")
.call(yAxis);
but its not work
http://codepen.io/brantwills/pen/igsoc
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.selectAll('path.line').attr('d', line);
points.selectAll('circle').attr("transform", function(d) {
return "translate(" + x(d.point.x) + "," + y(d.point.y) + ")"; }
);
}
I'm looking for some times now to allow zooming into one or the other (or both) directions X/Y on a d3.js chart. Here is my simple chart :
var margin = parseInt(attrs.margin) || {top: 20, right: 20, bottom: 20, left: 20},
padding = parseInt(attrs.padding) || 30;
var svg = d3.select(ele[0]).append('svg')
.style('width', '100%');
var width = 960 - margin.left - margin.right - padding,
height = 500 - margin.top - margin.bottom;
// X scale
var x = d3.scale.linear().domain([d3.min(data, function(d){return d.x;}), d3.max(data, function(d){return d.x})]).range([0, width]);
// Y scale
var y = d3.scale.linear().domain([0, d3.max(data, function(d){return d.y;})]).range([height, 0]);
svg.call(d3.behavior.zoom().x(x).y(x).on("zoom", zoomed));
// create a line function that can convert data[] into x and y points
var line = d3.svg.line()
.interpolate("basis")
// assign the X function to plot our line as we wish
.x(function(d,i) { return x(d.x); })
.y(function(d) { return y(d.y); });
// Add an SVG element with the desired dimensions and margin.
svg.attr("width", width + margin.left + margin.right + padding)
.attr("height", height + margin.top + margin.bottom);
var g = svg.append("g").attr("transform", "translate(60," + margin.top + ")");
// create Axis
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
// Add the x-axis.
g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + 0 + "," + height + ")")
.call(xAxis);
// Add the y-axis to the left
g.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + 0 +",0)")
.call(yAxis);
// objects for the zooming clipping
var clip = g.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);
var chartBody = g.append("g")
.attr("clip-path", "url(#clip)");
chartBody.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.select(".line")
.attr("class", "line")
.attr("d", line);
}
Is there a way to use a key modifier when zooming (for example when shift+mouse wheel, only zoom X) ?
Working with one bar chart with d3.js I am unable to align ticks in x axis with bars.
In left and right verges the ticks are ok, but not in the middle.
Here is the code:
var formatDate = d3.time.format("%e %b");
var height = 325;
var xTimeScale = d3.time.scale()
.domain([new Date(data[0].date), d3.time.day.offset(new Date(data[data.length - 2].date), 1)])
.range([30, width]);
var xAxis = d3.svg.axis()
.scale(xTimeScale)
.orient("bottom")
.ticks(d3.time.days, .1)
.tickFormat(formatDate);
chart.append("g")
.attr("class", "xaxis axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
chart.selectAll(".xaxis text")
.attr("transform", function(d) {return "translate(" + this.getBBox().height * -2 + "," + this.getBBox().height + ")rotate(-45)";});
What am I missing?
Thanks in advance.
Update: Here is the jsFiddle updated with chrtan suggestions.
My problem now is to align text with the center of bar and not in left.
From the looks of your graph, you lost a bar's worth of space. If all the bars are supposed to be left-aligned against a tick, that final bar you have should be to the right of the January 31st tick.
You might need to add the February 1st tick by perhaps changing the [data.length - 2] to [data.length - 1] in the domain() for your xTimeScale.
Then for display purposes, you could probably remove the last tick axis text with:
d3.select(chart.selectAll(".xaxis text")[0].pop()).remove();
The inner selectAll should get the array containing your xAxis tick texts and then pop the very last tick. This last tick should then be removed by the outer select.
An example with an auto time ticks with d3.js
// set domain for axis
var x_domain = d3.extent(data, function(d) { return new Date(d.date); });
//format date
var date_format = d3.time.format('%Y %B');
var vis = d3.select("#graph")
.append("svg:svg")
.attr('class', 'chart')
.attr("width", width)
.attr("height", height);
var yScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.data; })]).nice()
.range([height - padding, padding]);
var xScale = d3.time.scale()
.domain(x_domain)
.range([padding, width - padding]);
// define the y axis
var yAxis = d3.svg.axis()
.orient("left")
.scale(yScale);
// define the x axis
var xAxis = d3.svg.axis()
.orient("bottom")
.scale(xScale)
.tickFormat(date_format);
// draw y axis with labels and move in from the size by the amount of padding
vis.append("g")
.attr("class", "axis")
.attr("transform", "translate("+padding+",0)")
.call(yAxis);
// draw x axis with labels and move to the bottom of the chart area
vis.append("g")
.attr("class", "xaxis axis")
.attr("transform", "translate(0," + (height - padding) + ")")
.call(xAxis);
// and set data in graph...
a great example : http://bl.ocks.org/phoebebright/3061203
I have a basic line graph with two lines. When I click a button, one of the two lines will draw on the graph.
I use stroke-dasharray to draw the lines.
Would anyone know how I could add tooltips to my lines?
Does using stroke-dasharray make it harder?
Heres my code.
var button=d3.select("#button");
//defines canvas (area in which graph is placed)
var margin = {top: 30, right: 20, bottom: 50, left: 60},
width = 800 - margin.left - margin.right,
height = 700 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse;
//OUTPUT RANGE
var x = d3.time.scale()
.range([0, width]);
//OUTPUT RANGE
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);
//assigns coordinates for each piece of data
var valueline = d3.svg.line()
.interpolate("interpolation")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
//second line data
var valueline2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.open); });
//create area for 'area' below line
var area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.close); });
//creates area to draw graph
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
//groups content
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5)
}
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(30)
}
// csv callback function
d3.csv("myData3.csv", function(data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
d.open = +d.open;
});
//INPUT DOMAINS
//.extent() returns min and max values of argument
x.domain(d3.extent(data, function(d) { return d.date; }));
//returns max of whichever set of data is bigger
y.domain([0, d3.max(data, function(d) { return Math.max(d.close, d.open); })]);
d3.select("#button1").on("click", function(){
var path = svg.append("path") // Add the valueline path.
.attr("class", "line")
.attr("d", valueline(data))
.attr("stroke", "steelblue")
.attr("stroke-width", "5")
.attr("fill", "none");
var totalLength = path.node().getTotalLength();
path
.attr("stroke-dasharray", totalLength + "30" * 30)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
.attr("stroke-dashoffset", 0);
})
d3.select("#button2").on("click", function(){
var path2 = svg.append("path") // Add the valueline path.
.attr("class", "line2")
.attr("d", valueline2(data))
.attr("stroke", "steelblue")
.attr("stroke-width", "5")
.attr("fill", "none");
var totalLength = path2.node().getTotalLength();
path2
.attr("stroke-dasharray", totalLength + "30" * 30)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
.attr("stroke-dashoffset", 0)
})
svg.append("g") // Add the X Axis
.attr("class", "x axis")
//moves x axis to bottom of graph
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
//text label for x-axis
svg.append("text") // text label for the x axis
.attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom - 5 ) + ")")
.style("text-anchor", "middle")
.text("Date");
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
//text label for y-axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
//adds extra left padding as original y pos = 0
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Value");
//adding a title to the graph
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("Graph");
//draw x axis grid
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
//draw y axis grid
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
});<!--d3.csv close-->
Thanks in advance!
The easiest way to add a tooltip is to append an svg:title element to the elements you want to have a tooltip for. It will be displayed by the browser automatically when you hover over the element. It works for all kinds of elements as well.
So your code would need to look something like
var path = svg.append("path") // Add the valueline path.
.attr("class", "line")
.attr("d", valueline(data))
.attr("stroke", "steelblue")
.attr("stroke-width", "5")
.attr("fill", "none")
.append("title").text("whatever");
If you need more sophisticated functionality, you could try for example tipsy, which works in a similar way.