D3 Zooming in graph - javascript
i have tried using D3.zoom behavior in my scatterplot graph.
But the problem i am having now is that, i can only zoom my graph ONLY when i mouseover my DOT.
Any reasons why? I want it to be able to zoom in anywhere as long as my mouse is pointing inside the graph.
And also, my X axis doesn't stays at the bottom... it gets zoomed in as well
Is it possible to just let the X Axis stay constant at the bottom?
here are my codes...
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 650 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%S").parse;
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var zoom = d3.behavior.zoom()
.scaleExtent([0.95, 10])
.on("zoom", zoomed);
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var valueline = d3.svg.line()
.x(function(d) { return x(d.ArtDateTime); })
.y(function(d) { return y(d.Ranking); });
var svg = d3.select(".graph")
.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 + ")")
.call(zoom);
function zoomed() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
svg.selectAll("g")
.attr("width", width)
.attr("height", height);
}
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(4)
}
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(4)
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
d3.csv("FinalCSVFile.csv", function(error, data) {
data.forEach(function(d) {
d.ArtDateTime = parseDate(d.ArtDateTime);
d.Ranking = +d.Ranking;
});
x.domain(d3.extent(data, function(d) { return d.ArtDateTime; }));
y.domain([0, d3.max(data, function(d) { return d.Ranking; })]);
// Add the X Axis
svg.append("g")
.transition()
.duration(300)
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append('g')
.transition()
.duration(300)
.attr('class', 'grid')
.attr('transform', 'translate(0,' + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
svg.append('g')
.transition()
.duration(300)
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 5)
.attr("cx", function(d) { return x(d.ArtDateTime);})
.attr("cy", function(d) { return y(d.Ranking * 3); })
.on("mouseover", function(d) {
var xPosition = parseFloat(d3.select(this).attr("cx"));
var yPosition = parseFloat(d3.select(this).attr("cy"));
d3.select(this)
.transition()
.duration(20)
.style("fill", "red");
d3.select("#box")
.transition()
.duration(300)
.style("left", xPosition + 80 + "px")
.style("top", yPosition + 140 +"px" )
.select("#ranking")
.text(d.Ranking)
d3.select("#box")
.select("#startDT")
.text(d.startDateTime)
d3.select("#box")
.select("#senCONT")
.text(d.sentenceContent)
d3.select("#tooltip")
.classed("hidden", false);
})
.on("mouseout", function() {
d3.select("#tooltip")
.classed("hidden", true);
});
});
The reason you can't zoom in on the white areas is because there is actually nothing there to zoom in on. Paste this code below into your jsfiddle example at line 39 (after you've created the svg variable) to append a background rectangle behind your graph that you can zoom in on.
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "#fff");
Related
How to dynamically create append svg line using d3js?
I am attempting to draw markers to a zoomable / pannable graph. My current version is available at https://jsfiddle.net/n2enn80o/ raw = {"l2":[-58,-44,-31,-21,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-9,-7,-5,-3,-1,2,4,8,11,14,17,20,24,28,32,37,41,46,51,56,60,64,69,73,77,82,84,87,87,87,87,85,82,77,73,66,60,53,46,39,33,26,20,13,8,4,-1,-6,-10,-14,-16,-19,-22,-25,-26,-27,-28,-29,-30,-31,-31,-32,-32,-32,-32,-31,-31,-31,-31,-31,-30,-31,-30,-30,-30,-30,-29,-28,-27,-27,-27,-27,-27,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-25,-25,-24,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-22,-22,-22,-21,-21,-21,-21,-20,-20,-20,-20,-19,-18,-16,-13,-10,-6,-2,1,4,7,9,12,14,16,16,16,15,13,9,6,2,-1,-4,-7,-10,-11,-12,-14,-15,-16,-17,-18,-19,-19,-20,-20,-20,-20,-20,-20,-20,-24,-32,-45,-54,-50,-25,25,97,182,252,270,220,126,35,-25,-53,-65,-71,-70,-60,-46,-32,-22,-18,-16,-16,-15,-14,-13,-13,-12,-11,-10,-8,-7,-5,-3,-1,1,4,7,10,14,17,21,24,28,32,36,40,45,50,55,59,64,69,72,77,81,84,87,88,88,87,84,82,77,73,67,61,54,47,39,33,26,20,14,9,4,-1,-6,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-30,-30,-31,-32,-32,-32,-31,-31,-32,-31,-31,-31,-31,-30,-30,-29,-29,-29,-29,-28,-28,-27,-27,-28,-28,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-26,-26,-25,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-23,-23,-23,-23,-24,-22,-22,-22,-22,-22,-22,-22,-21,-22,-20,-20,-20,-20,-20,-19,-18,-16,-13,-10,-8,-3,0,4,7,9,11,13,15,16,16,16,14,11,6,2,-2,-4,-7,-9,-11,-12,-14,-16,-17,-18,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-23,-30,-43,-54,-53,-30,17,88,172,245,271,230,138,45,-19,-50,-63,-70,-70,-61,-48,-34,-23,-18,-17,-16,-16,-15,-14,-13,-13,-11,-10,-8,-7,-5,-3,-1,1,4,7,9,13,16,20,23,27,31,36,40,44,49,54,59,63,68,73,76,81,83,86,88,87,87,85,82,78,73,68,62,55,48,40,33,27,20,14,9,4,0,-5,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-29,-30,-31,-31,-32,-31,-32,-32,-32,-32], "startts":1357714800000,"marker1":[50,100]}; var data =[]; for(var i=0;i<raw.l2.length;i++) { var marker = Number.NaN; for(var j=0;j<raw.marker1.length;j++) { if(i==raw.marker1[j]) { marker=i; break; } } var obj = {"date":raw.startts+(1/244.140625*1000)*i, "value":raw.l2[i]/75,"marker":marker} data.push(obj) } margin = { top: 20, right: 20, bottom: 20, left: 45 }; width = 1800 - margin.left - margin.right; height = 600 - margin.top - margin.bottom; var x = d3.time.scale() .domain(d3.extent(data, function (d) { return d.date; })) .range([0, width]); var y = d3.scale.linear() .domain(d3.extent(data, function (d) { return d.value; })) .range([height, 0]); var line = d3.svg.line() .x(function (d) { return x(d.date); }) .y(function (d) { return y(d.value); }); var zoom = d3.behavior.zoom() .x(x) .y(y) .on("zoom", zoomed); 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); svg.append("svg:rect") .attr("width", width) .attr("height", height) .attr("class", "plot"); var make_x_axis = function () { return d3.svg.axis() .scale(x) .orient("bottom") .ticks(5); }; var make_y_axis = function () { return d3.svg.axis() .scale(y) .orient("left") .ticks(5); }; var xAxis = d3.svg.axis() .scale(x) .orient("bottom") .ticks(5); svg.append("svg:g") .attr("class", "x axis") .attr("transform", "translate(0, " + height + ")") .call(xAxis); var yAxis = d3.svg.axis() .scale(y) .orient("left") .ticks(5); svg.append("g") .attr("class", "y axis") .call(yAxis); var marker = svg.append("line") .attr("x1",100) .attr("y1", 0) .attr("x2",100) .attr("y2", height) .attr("class", "marker") svg.append("text") .attr("x", 100) .attr("y", 0) .attr("dy", ".35em") .attr("dx", 5) .attr("class", "marker-text") .text(function(d) { return "test"; }); 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)"); chartBody.append("svg:path") .datum(data) .attr("class", "line") .attr("d", line); function zoomed() { console.log(d3.event.translate); console.log(d3.event.scale); 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("")); svg.select(".line") .attr("class", "line") .attr("d", line); } I have been able to add static lines to my d3 plot in the example, what i am trying to achieve is to make the marker line along with the text "test" to be moving along with the graph. What I have tried is to use a d3.svg.line() with a line generator, but it ends up not getting the reference to d. Another version I have attempted is to create a function as below but that does not get the reference of d, and draws the line at zero. Here i attempted to draw the line if and only if the marker tag was present in the data. By default when populating the data i have ensured that it has Number.NaN when i dont need to draw the marker. var marker = svg.append("line") .attr("x1",function(d) { if(d.marker!=Number.NaN) return x(d.date); }) .attr("y1", 0) .attr("x2",function(d) { if(d.marker!=Number.NaN) return x(d.date); }) .attr("y2", height) .attr("class", "marker")
I have made a couple of small changes, as per my reply to your question. Inside your zoom handler zoomed() you need to change the x1 & x2 attributes of marker, and the x attr of markerText. This function fires on each zoom event to move stuff around or redraw stuff according to your zoom, and your axes. raw = {"l2":[-58,-44,-31,-21,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-9,-7,-5,-3,-1,2,4,8,11,14,17,20,24,28,32,37,41,46,51,56,60,64,69,73,77,82,84,87,87,87,87,85,82,77,73,66,60,53,46,39,33,26,20,13,8,4,-1,-6,-10,-14,-16,-19,-22,-25,-26,-27,-28,-29,-30,-31,-31,-32,-32,-32,-32,-31,-31,-31,-31,-31,-30,-31,-30,-30,-30,-30,-29,-28,-27,-27,-27,-27,-27,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-25,-25,-24,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-22,-22,-22,-21,-21,-21,-21,-20,-20,-20,-20,-19,-18,-16,-13,-10,-6,-2,1,4,7,9,12,14,16,16,16,15,13,9,6,2,-1,-4,-7,-10,-11,-12,-14,-15,-16,-17,-18,-19,-19,-20,-20,-20,-20,-20,-20,-20,-24,-32,-45,-54,-50,-25,25,97,182,252,270,220,126,35,-25,-53,-65,-71,-70,-60,-46,-32,-22,-18,-16,-16,-15,-14,-13,-13,-12,-11,-10,-8,-7,-5,-3,-1,1,4,7,10,14,17,21,24,28,32,36,40,45,50,55,59,64,69,72,77,81,84,87,88,88,87,84,82,77,73,67,61,54,47,39,33,26,20,14,9,4,-1,-6,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-30,-30,-31,-32,-32,-32,-31,-31,-32,-31,-31,-31,-31,-30,-30,-29,-29,-29,-29,-28,-28,-27,-27,-28,-28,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-26,-26,-25,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-23,-23,-23,-23,-24,-22,-22,-22,-22,-22,-22,-22,-21,-22,-20,-20,-20,-20,-20,-19,-18,-16,-13,-10,-8,-3,0,4,7,9,11,13,15,16,16,16,14,11,6,2,-2,-4,-7,-9,-11,-12,-14,-16,-17,-18,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-23,-30,-43,-54,-53,-30,17,88,172,245,271,230,138,45,-19,-50,-63,-70,-70,-61,-48,-34,-23,-18,-17,-16,-16,-15,-14,-13,-13,-11,-10,-8,-7,-5,-3,-1,1,4,7,9,13,16,20,23,27,31,36,40,44,49,54,59,63,68,73,76,81,83,86,88,87,87,85,82,78,73,68,62,55,48,40,33,27,20,14,9,4,0,-5,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-29,-30,-31,-31,-32,-31,-32,-32,-32,-32], "startts":1357714800000,"marker1":[50,100]}; var data =[]; for(var i=0;i<raw.l2.length;i++) { var marker = Number.NaN; for(var j=0;j<raw.marker1.length;j++) { if(i==raw.marker1[j]) { marker=i; break; } } var obj = {"date":raw.startts+(1/244.140625*1000)*i, "value":raw.l2[i]/75,"marker":marker} data.push(obj) } margin = { top: 20, right: 20, bottom: 20, left: 45 }; width = 1800 - margin.left - margin.right; height = 600 - margin.top - margin.bottom; var x = d3.time.scale() .domain(d3.extent(data, function (d) { return d.date; })) .range([0, width]); var y = d3.scale.linear() .domain(d3.extent(data, function (d) { return d.value; })) .range([height, 0]); var line = d3.svg.line() .x(function (d) { return x(d.date); }) .y(function (d) { return y(d.value); }); var zoom = d3.behavior.zoom() .x(x) .y(y) .on("zoom", zoomed); 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); svg.append("svg:rect") .attr("width", width) .attr("height", height) .attr("class", "plot"); var make_x_axis = function () { return d3.svg.axis() .scale(x) .orient("bottom") .ticks(5); }; var make_y_axis = function () { return d3.svg.axis() .scale(y) .orient("left") .ticks(5); }; var xAxis = d3.svg.axis() .scale(x) .orient("bottom") .ticks(5); svg.append("svg:g") .attr("class", "x axis") .attr("transform", "translate(0, " + height + ")") .call(xAxis); var yAxis = d3.svg.axis() .scale(y) .orient("left") .ticks(5); 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("")); // Moved this after you append your grids var marker = svg.append("line") .attr("x1",100) .attr("y1", 0) .attr("x2",100) .attr("y2", height) .attr("class", "marker") // Moved this after you append your grids & saved it to a var for later use var markerText = svg.append("text") .attr("x", 100) .attr("y", 0) .attr("dy", ".35em") .attr("dx", 5) .attr("class", "marker-text") .text(function(d) { return "test"; }); 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)"); chartBody.append("svg:path") .datum(data) .attr("class", "line") .attr("d", line); function zoomed() { console.log(d3.event.translate); console.log(d3.event.scale); 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("")); svg.select(".line") .attr("class", "line") .attr("d", line); // Position at the start time according to your x scale. x(val) // It's not clear from your question where you want to position it var markerPos = x(raw.startts); // Move marker to position marker.attr("x1", markerPos ).attr("x2", markerPos ); // Move marker text to position markerText.attr("x", markerPos ); } Fiddle: https://jsfiddle.net/kqnLfkvw/1/
This can be solved by using d3 axis. A working example is available at https://jsfiddle.net/3gww76s0/ var make_x_marker = function (scale=1, transform=[0,0]) { console.log(transform) var markers =[]; var markerLabels={}; for (i=0; i<raw.marker1.length; i++) { var value=transform[0]+scale*(1/244.140625*1000)*raw.marker1[i]; markers.push(value) markerLabels[value]="A"+Math.floor(Math.random()*26); } return d3.svg.axis() .orient("top") .tickValues(markers) .tickSize(height-15) .tickFormat(function(d){return markerLabels[d]}) };
use img instead of text label in d3.js line chart
Fiddle Example I couldn't get ordinal scales to work with zooming and panning to achieve horizontally scroll-able effect so I have settled for scale.linear() to use numeric values for axis ticks. I was wondering if it is possible to superimpose the text label in g.tick with an image element. I have come up with this code after .call(xAxis) svg.append("svg:g") .attr("class", "x axis") .attr("transform", "translate(0, " + height + ")") .call(xAxis) .selectAll(".tick text").each(function(k,i){ console.log(data[k]["img"]); var r = document.createElement('image') r.setAttribute('x',0) r.setAttribute('y',9) r.setAttribute('xlink:href',data[k]["img"]) r.setAttribute('width',50) r.setAttribute('height',50) this.parentNode.insertBefore(r,this); }) I saw that the elements are prepended in g.tick but the images are nowhere to be seen. Is it because of the x and y values? Also, how can I bind the image links from the JSON data to the image element? I have tried data[k]["img"] but it gave me Cannot read property 'img' of undefined. var img = "https://www.gravatar.com/avatar/904fd39461599f72d580fadf3a73115b?s=128&d=identicon&r=PG&f=1"; var data = [{"item":1,"diameter":"15.00","img":img},{"item":2,"diameter":"10.00","img":img}, {"item":3,"diameter":"25.00","img":img},{"item":4,"diameter":"7.00","img":img}, {"item":5,"diameter":"35.00","img":img},{"item":6,"diameter":"15.00","img":img}, {"item":7,"diameter":"12.00","img":img},{"item":8,"diameter":"10.00","img":img}, {"item":9,"diameter":"17.00","img":img},{"item":10,"diameter":"13.00","img":img}, {"item":11,"diameter":"5.00","img":img},{"item":12,"diameter":"10.00","img":img}, ]; function line_chart(field,el){ margin = { top: 20, right: 20, bottom: 20, left: 45 }, tickno = 10, width = 960 - margin.left - margin.right, height = 450 - margin.top - margin.bottom, x = d3.scale.linear().domain(d3.extent(data, function (d) { return d.item; })).range([0, width]), ymax = d3.max(data,function(d){ return (parseInt(d[field])+1); }), ymin = d3.min(data,function(d){ return d[field]; }), xmax = d3.max(data,function(d){ return d.name; }), y = d3.scale.linear() .domain([ymin,ymax]) .range([height, 0]); var line = d3.svg.line() .x(function (d) { return x(d.item); }) .y(function (d) { return y(d[field]); }); var zoom = d3.behavior.zoom() .x(x) .scaleExtent([1, 1]) .y(y) .on("zoom", zoomed); svg = d3.select(el) .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); svg.append("svg:rect") .attr("width", width) .attr("height", height) .attr("class", "plot"); var make_x_axis = function () { return d3.svg.axis() .scale(x) .orient("bottom") .ticks(tickno); }; var make_y_axis = function () { return d3.svg.axis() .scale(y) .orient("left") .ticks(tickno); }; var xAxis = d3.svg.axis() .scale(x) .orient("bottom") .ticks(tickno); svg.append("svg:g") .attr("class", "x axis") .attr("transform", "translate(0, " + height + ")") .call(xAxis) .selectAll(".tick text").each(function(data){ var r = document.createElement('image') r.setAttribute('x',0) r.setAttribute('y',9) r.setAttribute('xlink:href','https://www.gravatar.com/avatar/904fd39461599f72d580fadf3a73115b?s=32&d=identicon&r=PG&f=1') r.setAttribute('width',50) r.setAttribute('height',50) this.parentNode.insertBefore(r,this); }) var yAxis = d3.svg.axis() .scale(y) .orient("left") .ticks(tickno); 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)"); chartBody.append("svg:path") .datum(data) .attr("class", "line") .attr("d", line); svg.append('g').attr('class','dots').selectAll(".dot").data(data).enter().append("circle").attr("r",3.5) .attr("cx",function(d){return x(d.item);}) .attr("cy",function(d){return y(d[field]);}) function zoomed() { console.log(d3.event.translate); console.log(d3.event.scale); svg.select(".dots") .attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); svg.selectAll(".dots circle").attr("r", function(){ return (3.5 * d3.event.scale); }); 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("")); svg.select(".line") .attr("class", "line") .attr("d", line); svg.selectAll(".dots circle").attr("r", function(){ return (3.5 * d3.event.scale); }); } } line_chart('diameter','#area')
Your image doesn't display because your width is too small. Also, it's a bit cleaner if you append the images the d3 way: .selectAll(".tick").each(function(d,i){ d3.select(this) .append('image') .attr('xlink:href', data[i].img) .attr('x',0) .attr('width',128) .attr('height',128); }) Updated fiddle.
how to left align ticks in d3 bar chart
i created a stacked bar graph. on the y axis side i have ticks with varying lengths. what i am trying to accomplish is to align the text in the tick to the left. this is my example:http://jsfiddle.net/2khbceut/2/ html <title>Diverging Stacked Bar Chart with D3.js</title> <body> <div id="figure" align="center" style="margin-bottom: 50px;"></div> </body> javascript $(document).ready(getTopolegy()); function getTopolegy(){ var data = null; var links = parseTopology(data); createChart(links); } function parseTopology(data){ var links=[{1:5,2:5,3:10,N:20,link_name: "Link CHGIL21CRS-SFXCA21CRS"}, {1:5,2:5,3:10,N:20,link_name: "Link NYCNY21CRS-NYCNY22CRS"}]; return links; } function jsonNameToId(name){ switch (allocated_priority) { case "allocated_priority": return 1; case "allocated_default": return 2; case "spare_capacity": return 3; case "total": return "N"; default: return 999; } } function createChart(data){ var margin = {top: 50, right: 20, bottom: 10, left: 210}, width = 1000 - margin.left - margin.right, height = 100 - margin.top - margin.bottom; var y = d3.scale.ordinal() .rangeRoundBands([0, height], .3); var x = d3.scale.linear() .rangeRound([0, width]); var color = d3.scale.ordinal() .range(["#cccccc", "#92c6db", "#086fad"]); var xAxis = d3.svg.axis() .scale(x) .orient("top"); var yAxis = d3.svg.axis() .scale(y) .orient("left") var svg = d3.select("#figure").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .attr("id", "d3-plot") .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); color.domain(["Allocated Priority %", "Allocated Default %", "Spare Capacity %"]); // d3.csv("js/raw_data.csv", function(error, data) { data.forEach(function(d) { d["Allocated Priority %"] = +d[1]*100/d.N; d["Allocated Default %"] = +d[2]*100/d.N; d["Spare Capacity %"] = +d[3]*100/d.N; var x0 = 0; var idx = 0; d.boxes = color.domain().map(function(name) { return {name: name, x0: x0, x1: x0 += +d[name], N: +d.N, n: +d[idx += 1]}; }); }); var min_val = d3.min(data, function(d) { return d.boxes["0"].x0; }); var max_val = d3.max(data, function(d) { return d.boxes["2"].x1; }); x.domain([min_val, max_val]).nice(); y.domain(data.map(function(d) { return d.link_name; })); svg.append("g") .attr("class", "x axis") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis) var vakken = svg.selectAll(".Link") .data(data) .enter().append("g") .attr("class", "bar") .attr("transform", function(d) { return "translate(0," + y(d.link_name) + ")"; }); var bars = vakken.selectAll("rect") .data(function(d) { return d.boxes; }) .enter().append("g").attr("class", "subbar"); bars.append("rect") .attr("height", y.rangeBand()) .attr("x", function(d) { return x(d.x0); }) .attr("width", function(d) { return x(d.x1) - x(d.x0); }) .style("fill", function(d) { return color(d.name); }); bars.append("text") .attr("x", function(d) { return x(d.x0); }) .attr("y", y.rangeBand()/2) .attr("dy", "0.5em") .attr("dx", "0.5em") .style("font" ,"10px sans-serif") .style("text-anchor", "begin") .text(function(d) { return d.n !== 0 && (d.x1-d.x0)>3 ? d.n : "" }); vakken.insert("rect",":first-child") .attr("height", y.rangeBand()) .attr("x", "1") .attr("width", width) .attr("fill-opacity", "0.5") .style("fill", "#F5F5F5") .attr("class", function(d,index) { return index%2==0 ? "even" : "uneven"; }); svg.append("g") .attr("class", "y axis") .append("line") .attr("x1", x(0)) .attr("x2", x(0)) .attr("y2", height); var startp = svg.append("g").attr("class", "legendbox").attr("id", "mylegendbox"); // this is not nice, we should calculate the bounding box and use that var legend_tabs = [0, 150, 300]; var legend = startp.selectAll(".legend") .data(color.domain().slice()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(" + legend_tabs[i] + ",-45)"; }); legend.append("rect") .attr("x", 0) .attr("width", 18) .attr("height", 18) .style("fill", color); legend.append("text") .attr("x", 22) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "begin") .style("font" ,"10px sans-serif") .text(function(d) { return d; }); d3.selectAll(".axis path") .style("fill", "none") .style("stroke", "#000") .style("shape-rendering", "crispEdges") d3.selectAll(".axis line") .style("fill", "none") .style("stroke", "#000") .style("shape-rendering", "crispEdges") var movesize = width/2 - startp.node().getBBox().width/2; d3.selectAll(".legendbox").attr("transform", "translate(" + movesize + ",0)"); // }); } as can be seen the current positioning of the tick text is to the right. i tried the following idea: svg.append("g") .attr("class", "y axis") .call(yAxis) .selectAll("text") .style("text-anchor", "start"); but it did not position the ticks in the desired alignment. any ideas?
You can make the Y axis right-oriented, which will have the effect of positioning all the labels to the right of the axis, left-aligning them: var yAxis = d3.svg.axis() .scale(y) .orient("right")// <- 1st step At that point the labels would disappear, because they'll get covered up by the bars of the graph. But then you can shift all those left-aligned labels some constant distance in the negative X direction, such that they're back on the left side of the Y axis, but still left-aligned the way you wanted. tickPadding() is a way to shift them: var yAxis = d3.svg.axis() .scale(y) .orient("right") .tickPadding(-180) Here's your example, modified with the above: http://jsfiddle.net/2khbceut/3/ Maybe hardcoding the -180 is ok for you. If you need that amount to be dynamic, you can compute it using getBBox() on each text element of the axis and taking the maximum width to be the negative offset.
You can set the text-anchor to "start" and adjust the x position with translate, I added the code below in the chart model "boxPlotChart.js" g.select('.nv-y.nv-axis').selectAll('.tick').selectAll('text') .style('text-anchor','start') .attr('transform', function(d,i,j) { return 'translate(-14,0)' }); g.select('.nv-y.nv-axis').selectAll('.nv-axisMaxMin').selectAll('text') .style('text-anchor','start') .attr('transform', function(d,i,j) { return 'translate(-16,0)' });
D3: Panning along date x axis
I'm trying to display dates in the x axis and at the same time zoom it when you scroll. So, I have this code: <script type="text/javascript"> var data = [ [{'x':20111001,'y':1},{'x':20111002,'y':6},{'x':20111003,'y':11},{'x':20111004,'y':1},{'x':20111005,'y':2},{'x':20111006,'y':12},{'x':20111007,'y':2},{'x':20111008,'y':3},{'x':20111009,'y':13},{'x':20111010,'y':3}], [{'x':20111001,'y':2},{'x':20111002,'y':2},{'x':20111003,'y':12},{'x':20111004,'y':2},{'x':20111005,'y':3},{'x':20111006,'y':1},{'x':20111007,'y':2},{'x':20111008,'y':7},{'x':20111009,'y':2},{'x':20111010,'y':7}], [{'x':20111001,'y':3},{'x':20111002,'y':10},{'x':20111003,'y':13},{'x':20111004,'y':3},{'x':20111005,'y':12},{'x':20111006,'y':14},{'x':20111007,'y':6},{'x':20111008,'y':1},{'x':20111009,'y':7},{'x':20111010,'y':9}], [{'x':20111001,'y':4},{'x':20111002,'y':4},{'x':20111003,'y':14},{'x':20111004,'y':14},{'x':20111005,'y':10},{'x':20111006,'y':15},{'x':20111007,'y':3},{'x':20111008,'y':0},{'x':20111009,'y':3},{'x':20111010,'y':12}] ]; var colors = [ 'steelblue', 'green', 'red', 'purple' ] var b =[]; var parseDate = d3.time.format("%Y%m%d").parse; data.forEach(function (d) { f = d; f.forEach(function(f){ b.push(parseDate(String(f.x))); }) }) var margin = {top: 20, right: 30, bottom: 30, left: 50}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var x = d3.time.scale() .domain([d3.extent(b)]) .range([0, width]); var y = d3.scale.linear() .domain([-1, 16]) .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .tickSize(-height) .tickPadding(10) .tickSubdivide(true) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .tickPadding(10) .tickSize(-width) .tickSubdivide(true) .orient("left"); var zoom = d3.behavior.zoom() .x(x) .y(y) .scaleExtent([1, 10]) .on("zoom", zoomed); var svg = d3.select("body").append("svg") .call(zoom) .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("g") .attr("class", "y axis") .append("text") .attr("class", "axis-label") .attr("transform", "rotate(-90)") .attr("y", (-margin.left) + 10) .attr("x", -height/2) .style("text-anchor", "end") .text("Ventas (Miles €)"); svg.append("clipPath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); var line = d3.svg.line() .interpolate("linear") .x(function(d) { return x(d.x); }) .y(function(d) { return y(d.y); }); svg.selectAll('.line') .data(data) .enter() .append("path") .attr("class", "line") .transition() .attr("clip-path", "url(#clip)") .attr('stroke', function(d,i){ return colors[i%colors.length]; }) .attr("d", line); var div = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); var points = svg.selectAll('.dots') .data(data) .enter() .append("g") .attr("class", "dots") .attr("clip-path", "url(#clip)"); points.selectAll('.dot') .data(function(d, index){ var a = []; d.forEach(function(point,i){ a.push({'index': index, 'point': point}); }); return a; }) .enter() .append('circle') .attr('class','dot') .attr("r", 2.5) .attr('fill', function(d,i){ return colors[d.index%colors.length]; }) .attr("transform", function(d) { return "translate(" + x(d.point.x) + "," + y(d.point.y) + ")"; } ).on("mouseover", function(d) { div.transition() .duration(200) .style("opacity", .9); div .html(d.point.x + "K<br/>" + d.point.y) .style("left", (d3.event.pageX) + "px") .style("top", (d3.event.pageY) + "px"); }) .on("mouseout", function(d) { div.transition() .duration(500) .style("opacity", 0); }) 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) + ")"; } ); } </script> I can make it with numbers but can't implement it with dates. I've checked other examples and how they make it but can't find the way to code it in my chart. I'd like to know how to display dates on x axis.
Is your question how to make the axis dates instead of just numbers? Or is it how to make the axis pannable? If it's the first, use code like this: var x=d3.time.scale() .domain([minDate,maxDate]) The minDate and maxDate have to be javascript Date objects.
how to plot data from JSON object on .svg file using D3.js
Image is appending as a background which is not clear. Able to plot data on svg element which is created in this code. But want to plot json data on image/.svg file with the following.. Will appreciate if any references... $(function(){ makePlot(); // $('#zoomReset').on('click',function(e){ // e.preventDefault(); // //$('#chart').empty(); // console.log("sadf"); // makePlot(); // }); }); var makePlot = function() { d3.json("scatter-data-2010.json", function(dataset) { //Width and height var margin = {top: 80, right: 10, bottom: 60, left: 80}, width = 600 - margin.left - margin.right, height = 600 - margin.top - margin.bottom; var centered = undefined; //Create SVG element tooltip = d3.select("body").append("div") .attr("class", "plan_tooltip") .style("position", "absolute") .style("z-index", "10") .style("visibility", "hidden") .text(""); var svg = d3.select("#vis") .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("defs").append("clipPath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); /// Set Scales and Distortions var xScale = d3.scale.linear() .domain([d3.min(dataset, function(d) { return d['n_workers_change']; }), d3.max(dataset, function(d) { return d['n_workers_change']; })]) .range([0, width]); var yScale = d3.scale.linear() .domain([d3.min(dataset, function(d) { return d['earnings_change']; }), d3.max(dataset, function(d) { return d['earnings_change']; })]) .range([height,0]); var color_scale = d3.scale.category20(); //Add 2 more colors to category 20 because there are 22 parent industry categories var color_scale_range = color_scale.range(); color_scale_range.push("#e6550d","#6baed6") radiusScale = d3.scale.sqrt() .domain([d3.min(dataset, function(d) { return d['n_workers_y']; }), d3.max(dataset, function(d) { return d['n_workers_y']; }) ]) .range([3, 15]); svg.append("defs") .append("pattern") .attr("id", "background") .attr("width", width) .attr("height", height) .append("image") .attr("xlink:href", "http://www.e-pint.com/epint.jpg") .attr("width", width) .attr("height", height); var rect = svg.append("rect") .attr("class", "background") .attr("pointer-events", "all") //.attr("fill","none") .attr("fill","url(#background)") .attr("width", width) .attr("height", height) .call(d3.behavior.zoom().x(xScale).y(yScale).on("zoom", redraw)); // Tooltips for Dots set_tooltip_label = function (d) { var company_name; tooltip.html(d.category + "<br><strong>N Workers in 2010 (thousands)</strong>: " + d['n_workers_y'] + "<br><strong>Med. Wkly Earnings in 2010 ($)</strong>: " + d.earnings_y + "<br><strong> Category</strong>: " + d.parent_name ); if (!(event === undefined)) { tooltip.style("top", (event.pageY - 10) + "px").style("left", (event.pageX + 10) + "px") } }; var circles = svg.selectAll("circle") .data(dataset) .enter() .append("circle") .attr("clip-path", "url(#clip)") // Set cx, cy in the redraw function .attr("r", function(d) { return radiusScale(d['n_workers_y']); }) .attr("fill", function(d) { return color_scale(d.parent_id) }) .on("mouseover", function () { return tooltip.style("visibility", "visible") }).on("mousemove", function (d) { set_tooltip_label(d); }).on("mouseout", function () { tooltip.style("visibility", "hidden"); }); // Define X axis var xAxis = d3.svg.axis() .scale(xScale) .orient("bottom") .ticks(5) .tickSize(-height) .tickFormat(d3.format("s")); // Define Y axis var yAxis = d3.svg.axis() .scale(yScale) .orient("left") .ticks(10) .tickFormat(function(d) { return d + " %"; }) .tickSize(-width); // Create X axis svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + (height) + ")") .call(xAxis); // Create Y axis svg.append("g") .attr("class", "y axis") .attr("transform", "translate(" + 0 + ",0)") .call(yAxis); // Add Label to X Axis svg.append("text") .attr("class", "x label") .attr("text-anchor", "middle") .attr("x", width - width/2) .attr("y", height + margin.bottom/2) .text("Percent Change in Number of Workers in Industry"); // Add label to Y Axis svg.append("text") .attr("class", "y label") .attr("text-anchor", "middle") .attr("y", -margin.left + 5) .attr("x", 0 - (height/2)) .attr("dy", "1em") .attr("transform", "rotate(-90)") .text("Percent Change in Inflation Adjusted Median Weekly Earnings"); // Add title svg.append("text") .attr("class", " title") .attr("text-anchor","middle") .attr("x", width/2) .attr("y", -margin.top/2) .text("Changes in Employment and Salary by Industry, 2003 - 2010"); // Add subtitle svg.append("text") .attr("class", "subtitle") .attr("text-anchor","middle") .attr("x", width/2) .attr("y", -margin.top/2 + 15) .text("Scroll and drag to zoom/pan, hover for details."); var objects = svg.append("svg") .attr("class", "objects") .attr("width", width) .attr("height", height); //Create main 0,0 axis lines: hAxisLine = objects.append("svg:line") .attr("class", "axisLine hAxisLine"); vAxisLine = objects.append("svg:line") .attr("class", "axisLine vAxisLine"); // Zoom/pan behavior: function redraw(duration) { var duration = typeof duration !== 'undefined' ? duration : 0; if (d3.event){ //console.log("In the zoom function now"); //console.log(d3.event.scale); //console.log(d3.event.translate); svg.select(".x.axis").call(xAxis); svg.select(".y.axis").call(yAxis); } hAxisLine.transition().duration(duration) .attr("x1",0) .attr("y1",0) .attr("x2",width) .attr("y2",0) .attr("transform", "translate(0," + (yScale(0)) + ")"); vAxisLine.transition().duration(duration) .attr("x1",xScale(0)) .attr("y1",yScale(height)) .attr("x2",xScale(0)) .attr("y2",yScale(-height)); circles.transition().duration(duration) .attr("cx", function(d) { return xScale(d['n_workers_change']); }) .attr("cy", function(d) { return yScale(d['earnings_change']); }) }; // <-------- End of zoom function redraw(0); // call zoom to place elements }); // end of json loading section };
You need to define the background image as a pattern and then fill the rect with that pattern: svg.append("defs") .append("pattern") .attr("id", "background") .attr("width", width) .attr("height", height) .append("image") .attr("xlink:href", "http://www.e-pint.com/epint.jpg") .attr("width", width) .attr("height", height); svg.append("rect") .attr("fill", "url(#background)");