I have tried to make a set of x and y axis with this code and I'm stumped as to why they are not showing up. I want it to display a set of axis with ranges of -10 to 10, and the red line to sit above these axes. I am not sure why specifically the axis aren't working at this stage, the latter portion of my code has the axis code in it.
//variable declaration
var width = 500;
var height = 300;
var margin = 10;
//svg setup
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append('g')
.attr("transform", "translate(" + margin + "," + margin + ")" )
//line setup
svg.append('line')
.attr({
x1: 0,
y1: 0,
x2: 250,
y2: 250
});
//scales and axis setup
var scaleX = d3.scale.linear()
.range([-10, 10])
.domain([0, width])
var scaleY = d3.scale.linear()
.range([-10, 10])
.domain([height, 0])
var axisX = d3.svg.axis()
.scale(scaleX)
.orient("bottom");
var axisY = d3.svg.axis()
.scale(scaleY)
.orient("left");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + "," + height/2 + ")")
.call(axisX);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width/2 + "," + "0)")
.call(axisY);
There were some mistakes,like mapping goes from domain to range not range to domain and use of Svg instead of svg and svg.scale instead of d3.scale etc
see for yourself
https://jsfiddle.net/dango_x_daikazoku/33g9pLqe/4/
var width = 500;
var height = 300;
var margin = 30;
//svg setup
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append('g')
.attr("transform", "translate(" + margin + "," + margin + ")");
//line setup
//scales and axis setup
var scaleX = d3.scale.linear()
.domain([-10, 10])
.range([0, width])
var scaleY = d3.scale.linear()
.domain([-10, 10])
.range([height, 0])
var axisY = d3.svg.axis()
.scale(scaleY)
.orient("left");
var axisX = d3.svg.axis()
.scale(scaleX)
.orient("bottom");
svg.append("g")
.attr('class', 'y-axis axis')
.call(axisY);
svg.append("g")
.attr('class', 'x-axis axis')
.call(axisX)
.attr('transform', 'translate( 0, 250)')
Related
I'm trying to achieve an zoom option with x axis as date format.
Here's the code sample:
var margin = {
top: 20,
right: 20,
bottom: 40,
left: 100
},
svgWidth = 800,
svgHeight = 500,
width = svgWidth - margin.left - margin.right,
height = svgHeight - margin.top - margin.bottom;
svg = d3.select('body')
.append("svg")
.attr("style", "width: " + svgWidth + "px\; height: " + svgHeight + "px\;");
var x = d3.scaleUtc().range([0, width])
.domain([new Date("3/12/2017"), new Date("3/30/2017")]);
var y = d3.scaleBand()
.range([height, 0])
.padding(0.1)
.domain(["test"])
var xAxis = d3.axisBottom(x)
.tickFormat(d3.utcFormat("%m-%d"));
var yAxis = d3.axisLeft(y);
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([0, 0], [width, height])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
var xLine = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + height + ")")
.attr("class", "xAxis")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "middle");
var yLine = svg.append("g")
.attr("transform", "translate(" + margin.left + ", 0)")
.attr("class", "yAxis")
.call(yAxis)
.selectAll("text")
.attr("class", "cateName")
.style("text-anchor", "end");
svg.call(zoom);
function zoomed() {
xLine.call(xAxis.scale(d3.event.transform.rescaleX(x)));
};
The idea is very simple, when you pan horizontally, the xAxis will adjust the position. However, when you click the SVG, all labels in x axis will disappear.
I tried to look into it but it seems that my x in source code is NaN.
Why is this happening? Am I missing something?
The JSFiddle is here: https://jsfiddle.net/amyytnt0/1/
Thanks for your help!
Looks like I made a very simple mistake:
The zoom.translateExtent() should be in 1 argument, not 2.
So the fix should be:
zoom.translateExtent([[0, 0], [width, height]])
Answer found here: https://github.com/d3/d3-zoom/issues/73#issuecomment-263326469
I am using d3 to build a piano roll editor (which looks kind of like this). I need the rectangles to always be snapped onto the grid so when I pan or zoom the shapes will stay relative to the grid lines. It doesn't matter if the vertical grid lines redraw as I move in and out, but the number of horizontal grid lines should always stay the same, and the rectangle shapes are always locked on. An example of it not quite working can be seen here: http://jsfiddle.net/jgab3103/e05qj4hy/
I can see lots of d3 zoom type of examples around the place but I can't find anything to address this kind of issue. I think I am just not understanding how to scale shapes properly when working with the the zoom function. Also, in trying to get this to work I am noticing the panning and zooming seems to have become a bit unreliable, not sure why.
Anyway, if anyone had any ideas on how to solve this, it would be greatly appreciated. The code which is on the jsfiddle is below:
UPDATE: Just to (hopefully!) clarify - both horizontal and vertical axis need to zoom. The constraint is that the number of horizontal grid lines needs to stay the same and the shapes must be locked on to the grid lines so the dimensions never change. If a rectangle starts with a width and height of 1, this always needs to be retained when zooming.
//Data for note shapes
var noteData = [
{frequency: 3, duration:1, startPoint: 1},
{frequency: 6, duration:1, startPoint: 2},
{frequency: 5, duration:1, startPoint: 3},
{frequency: 4, duration:1, startPoint: 4}
];
margin = {
top: 20,
right: 20,
bottom: 20,
left: 45
};
width = 400 - margin.left - margin.right;
height = 200 - margin.top - margin.bottom;
//SCALES
var xScale = d3.scale.linear()
.domain([0,width])
.range([0, width])
var yScale = d3.scale.linear()
.domain([0,width])
.range([0, height]);
var heightScale = d3.scale.linear()
.domain([0,100])
.range([0,height]);
//Set up zoom
var zoom = d3.behavior.zoom()
.x(xScale)
.y(yScale)
.scaleExtent([1,100])
.scale([50])
.on("zoom", zoomed);
// Create SVG space and centre it
svg = d3.select('#chart')
.append("svg:svg")
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append("svg:g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
// Append a rect on top
var rect = svg.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr("class", "plot");
var noteRange = d3.range(0,88);
var measureRange = d3.range(0,16);
var make_x_axis = function () {
return d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(10);
};
var make_y_axis = function () {
return d3.svg.axis()
.scale(yScale)
.orient("left")
.tickValues(noteRange);
};
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(10);
//.tickValues([2,5,7,9]);
svg.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + height + ")")
.call(xAxis);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.tickValues(noteRange);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "x grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.append("g")
.attr("class", "y grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
var clip = svg.append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);
var chartBody = svg.append("g")
.attr("clip-path", "url(#clip)");
var rectGroup = svg.append("g")
var notes = rectGroup
.selectAll("rect")
.data(noteData)
.enter()
.append("rect")
.attr("x",function(d){
return xScale(d.startPoint)
})
.attr("y",function(d){
return yScale(d.frequency)
})
.attr("width",function(d) {
return 50;
})
.attr('class', 'rect')
.attr("height", function(d) {
return 23;
})
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.select(".x.grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.select(".y.grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
rectGroup.selectAll("rect")
.attr('class', 'rect')
.attr("x",function(d){
return xScale(d.startPoint);
})
.attr("y",function(d){
return yScale(d.frequency);
})
.attr('width', function(d) {
return 50;
})
.attr("height", function(d) {
return 23;
})
}
If you don't want yScale to be updated by the zoom behavior, just remove the line .y(yScale) and you should be good to go.
The zoom behavior will be constructed simply:
var zoom = d3.behavior.zoom()
.x(xScale)
.scaleExtent([1,100])
.scale([50])
.on("zoom", zoomed);
and it will only update the xScale.
I'm drawing a simple line chart with axes.
// Set the scales
var x = d3.scale.ordinal()
.domain(data.map(function(d) {
return d.labels;}))
.rangeRoundBands([0, width], 0);
var y = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.values; })])
.range([height, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
// draw line graph
var line = d3.svg.line()
.x(function(d) { return x(d.labels); })
.y(function(d) { return y(d.values); })
.interpolate("linear");
// Create the SVG 'canvas'
var svg = d3.select("body").append("svg")
.attr("class", "chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom).append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")");
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")
.attr("d",line(data))
.attr("stroke", color)
.attr("stroke-width", 2)
.attr("fill", "none");
Here you can see that it works, but the line starts from the y-axis so that the values don't correspond to the labels: http://jsfiddle.net/5r63j/12/
It may be fixed by replacing the .rangeRoundBands([0, width], 0); by .rangePoints([0, width], 0);, so that the values correspond to the labels and it's quite good, but there is no padding between the y-axis and the line.
Is it possible to move the start point of the line itself?
Close but not quite! :)
Instead of:
.rangePoints([0, width], 0);
you just use
.rangePoints([0, width], 0.5);
And you will get this:
Here is jsfiddle.
Documentation for second parameter of rangePoints() is here. Illustration for parameter meaning:
I have a current zoom function I just learned to use in D3. However when I use it, it only moves my and zooms the axis of the graph not the objects on it.
I'm very knew to D3 and would like some help please.
My source code of the javascript is posted below:
//Setting generic width and height values for our SVG.
var margin = {top: 60, right: 0, bottom: 60, left: 40},
width = 1024 - 70 - margin.left - margin.right,
height = 668 - margin.top - margin.bottom;
//Other variable declarations.
//Creating scales used to scale everything to the size of the SVG.
var xScale = d3.scale.linear()
.domain([0, 1024])
.range([0, width]);
var yScale = d3.scale.linear()
.domain([1, 768])
.range([height, 0]);
//Creates an xAxis variable that can be used in our SVG.
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
//Zoom command ...
var zoom = d3.behavior.zoom()
.x(xScale)
.y(yScale)
.scaleExtent([1, 10])
.on("zoom", zoomed);
// The mark '#' indicates an ID. IF '#' isn't included argument expected is a tag such as "svg" or "p" etc..
var SVG = d3.select("#mainSVG")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
//Create background. The mouse must be over an object on the graph for the zoom to work. The rectangle will cover the entire graph.
var rect = SVG.append("rect")
.attr("width", width)
.attr("height", height);
//This selects 4 circles (non-existent, there requires data-binding) and appends them all below enter.
//The amount of numbers in data is the amount of circles to be appended in the enter() section.
var circle = SVG
.selectAll("circle")
.data([40,100,400,1900])
.enter()
.append("circle")
.attr("cx",function(d){return xScale(d)})
.attr("cy",function(d){return xScale(d)})
.attr("r",20);
//This appends a circles to our SVG.
var circle = SVG
.append("circle")
.attr("cx",function(d){ return xScale(d)})
.attr("cy",300)
.attr("r",20);
//Showing the axis that we created earlier in the script for both X and Y.
var xAxisGroup = SVG.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var yAxisGroup = SVG.append("g")
.attr("class", "y axis")
.call(yAxis);
function zoomed() {
SVG.select(".x.axis").call(xAxis);
SVG.select(".y.axis").call(yAxis);
}
You also need to redraw all the elements with the changed axes on zoom -- D3 won't do this for you automatically:
function zoomed() {
SVG.select(".x.axis").call(xAxis);
SVG.select(".y.axis").call(yAxis);
SVG.selectAll("circle")
.attr("cx",function(d){return xScale(d)})
.attr("cy",function(d){return xScale(d)});
}
I'm playing again with d3.js the javascript library. I am able to create a chart with 2 numeric axes but now I want to have one numeric axis and one axis with a date. Unfortunately I'm not able to do this.
First of all, thats the code that is not running:
d3.json('builds.json',
function(data){
var format = d3.time.format("%Y-%m-%d");
data.forEach(function(d) {
d.finished_at = format.parse(d.finished_at);
});
var margin = {top: 40, right: 40, bottom: 40, left: 40},
width = 960,
height = 500;
var x = d3.time.scale()
.domain(d3.extent(data, function(d) { return d.finished_at; }))
.range([0, width - margin.right - margin.left]);
var y = d3.scale.linear()
.domain(d3.extent(data, function(d) { return d.result; }))
.range([height - margin.top - margin.bottom, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function(d) { return x(d.finished_at); })
.attr("cy", function(d) { return y(d.result); })
.attr("r", 6);
svg.append("g") // Render the axis by calling a <g> selection.
.attr("transform", "translate(0," + y.range()[0] + ")") //setzt x-achse an null punkt von y-achse
.call(xAxis);
svg.append("g")
.call(yAxis);
});
The variable finished_at looks like this: "finished_at":"2011-11-20" and I tried to parse it.
But the output is the following:
Can anybody please help me?
The problem likely lies with your data. You will need to confirm that all of the finished_at values in your JSON are in the correct format.
Your code appears to work perfectly well with a small working JSON dataset: http://bl.ocks.org/4162693