i want to include scrollbar and navigator, range selector functionality in my line graph . something similar to http://www.highcharts.com/products/highstock Can this be done on d3 if so give me a link on a tutorial or code.
the code is
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = {top: 430, right: 10, bottom: 30, left: 40},
width = 2000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%Y-%m-%d").parse;
var formatTime = d3.time.format("%e %B");
var x = d3.time.scale().range([0, width]);
var x2= d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(25);
var xAxis2 = d3.svg.axis().scale(x2).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var valueline = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x(d.date); }).y(function(d) { return y(d.close); });
var valueline2 = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x2(d.date); }).y(function(d) { return y2(d.close); });
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var svg = d3.select("body").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.json("data/data2.php", function(error, data) { data.forEach(function(d,i) {
//document.write(d.date);
d.date = parseDate(d.date);
//document.write(d.date);
d.close = +d.close;
//document.write(d.close);
arr[i]=d.close;
len=i+1;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([min-10, max+10]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path") // Add the valueline path.
.datum(data)
.attr("class","valueline")
.attr("d", valueline);
focus.selectAll("dot")
.data(data)
.enter().append("a")
.attr("xlink:href",function(d,i){if(d.close>=usl||d.close<=lsl||signal8[i]==8||signal8dw[i]==8||signal6up[i]==6||signal6dw[i]==6)return "http://en.wikipedia.org";})
.append("circle")
.attr("r", 2)
.style("fill", function(d,i) { // <== Add these
if(d.close==0) {return "none"}
if((ul[i]==9999)||(dl[i]==9999)) {return "red"}
else if(signal8[i]==8 ){ return "orange" }
else if(signal8dw[i]==8 ){return "gold"}
else if(signal6up[i]==6 ){return "indianred"}
else if(signal6dw[i]==6 ){return "#FF5C33"}
else { return "steelblue" } // <== Add these
;})
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.close); })
.on("mouseover", function(d,i) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(function(){
if(d.close==0)
{return}
if(ul[i]==9999)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " UPPER "}
else if(dl[i]==9999)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " LOWER "}
else if(signal8[i]==8)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " ( hello1 )"}
else if(signal8dw[i]==8)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " ( hello1 )"}
else if(signal6up[i]==6)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " ( hello1 )"}
else if(signal6dw[i]==6)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " ( hello1 )"}
else {return formatTime(d.date) + "<br/><b>" + d.close+ "</b>"}
;})
context.append("path") // Add the valueline path.
.attr("d", valueline2(data));
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
});
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".valueline").attr("d",valueline);
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.date = parseDate(d.date);
d.close = +d.close;
return d;
}
the above code is a snippet of the overall code. here when im executing im getting a parse error d="". where am i wrong. and i have drawn a few limit lines in the graph which i have not included in the above code. the bottom brush is working but the main graph is not getting updated as per the brush.
i want to update the dots too. what should i include the brushed function.
For the point marks, you again need a selectAll, and then reset the cx property to match the modified x scale:
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
//change the x-scale on the focus graph to match the brush extent
//(or reset it to the full domain if the brush is empty)
focus.selectAll(".valueline").attr("d",valueline);
// redraw the lines (using the updated scale)
focus.selectAll("dot").select("circle")
.attr("cx", function(d) { return x(d.date); });
//update the x position of the dots based on the updated x-scale
focus.select(".x.axis").call(xAxis);
//redraw the x-axis based on the updated x-scale
}
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = {top: 430, right: 10, bottom: 30, left: 40},
width = 2000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%Y-%m-%d").parse;
var formatTime = d3.time.format("%e %B");
var x = d3.time.scale().range([0, width]);
var x2= d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(25);
var xAxis2 = d3.svg.axis().scale(x2).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var valueline = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x(d.date); }).y(function(d) { return y(d.close); });
var valueline2 = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x2(d.date); }).y(function(d) { return y2(d.close); });
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var svg = d3.select("body").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.json("data/data2.php", function(error, data) { data.forEach(function(d,i) {
//document.write(d.date);
d.date = parseDate(d.date);
//document.write(d.date);
d.close = +d.close;
//document.write(d.close);
arr[i]=d.close;
len=i+1;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([min-10, max+10]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path") // Add the valueline path.
.datum(data)
.attr("class","valueline")
.attr("d", valueline);
context.append("path") // Add the valueline path.
.attr("d", valueline2(data));
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
});
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.selectAll(".valueline").attr("d",valueline); // selectAll is the answer
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.date = parseDate(d.date);
d.close = +d.close;
return d;
}
Related
Arrow head works fine on line draw but direction is wrong on axis!
live_update()
function live_update() {
var data1 = []
var n = 20
for (var i=0;i<=n;i++) {
data1.push({x:i,y:i*i})
}
var data2 = []
for (var i=0;i<=n;i++) {
data2.push({x:i,y:Math.sin(2*Math.PI/n*i)})
}
var toggle = 1
var div = d3.select('body').append('div')
div.append('button')
.text("update")
.on('click',(event,d) => {
console.log('click')
if (toggle == 0) {
update(data1)
toggle = 1
}else{
update(data2)
toggle = 0
}
})
var margin = {top: 10, right: 30, bottom: 30, left: 50},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.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 + ")")
.attr('class','box')
var aw = 6
var ah = 4
svg
.append("defs")
.append("marker")
.attr("id", "arrow")
.attr("refX", aw+1)
.attr("refY", ah/2+1)
.attr("markerWidth", aw+2)
.attr("markerHeight", ah+2)
.attr("orient", "auto")
.append("path")
.attr("d", ['M',1+aw/5,1+ah/2,'L',1,1,1+aw,1+ah/2,1,1+ah,'z'].join(' '));
svg.append('line').attr('class','avline')
var x = d3.scaleLinear().range([0,width]);
var xAxis = d3.axisBottom().scale(x);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.attr("class","myXaxis")
var y = d3.scaleLinear().range([height, 0]);
var yAxis = d3.axisLeft().scale(y);
svg.append("g")
.attr("class","myYaxis")
function update(data) {
var duration = 1000
var xmax = d3.max(data, function(d) { return d.x })
x.domain([d3.min(data,d => d.x), xmax]);
var xaxis = svg.selectAll(".myXaxis").transition()
.duration(duration)
.call(xAxis);
var ymin = d3.min(data,d => d.y)
y.domain([ymin, d3.max(data, function(d) { return d.y }) ]);
var yaxis = svg.selectAll(".myYaxis")
.transition()
.duration(duration)
.call(yAxis);
var frame = d3.select('.box')
frame.selectAll(".lineTest1")
.data([data])
.join("path")
.attr("class","lineTest1")
.transition()
.duration(duration)
.attr("d", d3.line()
.x(function(d) { return x(d.x); })
.y(function(d) { return y(d.y); }))
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 2.5)
.attr("marker-end", "url(#arrow)");
frame.selectAll(".lineTest2")
.data(data)
.join('circle')
.attr('class','lineTest2')
.attr('fill','red')
.transition()
.duration(duration)
.attr('cx',d => x(d.x))
.attr('r',3)
.attr('cy',d => y(d.y))
frame.selectAll(".lineTest3")
.data(data)
.join('path')
.attr('class','lineTest3')
.attr('stroke','gray')
.transition()
.duration(duration)
.attr('d',(d,i) => {
var ax = x(d.x)
var ay = y(d.y)
var bx = ax
var by = y(ymin)
var path = ['M',ax,ay,'L',bx,by]
return path.join(' ')
})
d3.select('.avline')
.attr('stroke','gray')
.transition()
.duration(duration)
.attr('x1',x(0))
.attr('y1',y(0))
.attr('x2',x(xmax))
.attr('y2',y(0))
xaxis.select("path")
.attr("marker-end", "url(#arrow)");
yaxis.select("path")
.attr("marker-end", "url(#arrow)");
}
update(data1)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
I have data in a streamgraph stack layout and the desired aesthetic I'm after is to assign an arbitrary series as the center line(s). Series above those lines (as determined by their index in the data) will stack on top and series below that line will stack below.
Here's a jsFidde.
In this example, I'd like the MS and the RC series to be single horizontal lines with the other groups stacked above and below them, respectively. (As opposed to the data index, I could also set the middle series based on some data attribute, in this example, oldest date would make sense.)
I think the solution would require passing my own offset function but I'm having a hard time figuring out how the built-in ones do what they do.
HTML
<div class="chart">
JS
// Adapted from https://gist.github.com/WillTurman/4631136
var data = [
{"key":"DJ","value":0,"date":"1/8/13"},
{"key":"DJ","value":0,"date":"1/9/13"},
{"key":"DJ","value":0,"date":"1/10/13"},
{"key":"DJ","value":1,"date":"1/11/13"},
{"key":"DJ","value":1,"date":"1/12/13"},
{"key":"MS","value":0,"date":"1/8/13"},
{"key":"MS","value":1,"date":"1/9/13"},
{"key":"MS","value":1,"date":"1/10/13"},
{"key":"MS","value":1,"date":"1/11/13"},
{"key":"MS","value":1,"date":"1/12/13"},
{"key":"RC","value":0,"date":"1/8/13"},
{"key":"RC","value":1,"date":"1/9/13"},
{"key":"RC","value":1,"date":"1/10/13"},
{"key":"RC","value":1,"date":"1/11/13"},
{"key":"RC","value":1,"date":"1/12/13"},
{"key":"CG","value":0,"date":"1/8/13"},
{"key":"CG","value":0,"date":"1/9/13"},
{"key":"CG","value":0,"date":"1/10/13"},
{"key":"CG","value":0,"date":"1/11/13"},
{"key":"CG","value":1,"date":"1/12/13"},
{"key":"RI","value":0,"date":"1/8/13"},
{"key":"RI","value":0,"date":"1/9/13"},
{"key":"RI","value":0,"date":"1/10/13"},
{"key":"RI","value":0,"date":"1/11/13"},
{"key":"RI","value":1,"date":"1/12/13"}
]
chart(data, "pink");
var datearray = [];
var colorrange = [];
function chart(data, color) {
if (color == "blue") {
colorrange = ["#045A8D", "#2B8CBE", "#74A9CF", "#A6BDDB", "#D0D1E6", "#F1EEF6"];
}
else if (color == "pink") {
colorrange = ["#980043", "#DD1C77", "#DF65B0", "#C994C7", "#D4B9DA", "#F1EEF6"];
}
else if (color == "orange") {
colorrange = ["#B30000", "#E34A33", "#FC8D59", "#FDBB84", "#FDD49E", "#FEF0D9"];
}
strokecolor = colorrange[0];
var format = d3.time.format("%m/%d/%y");
var margin = {top: 20, right: 40, bottom: 30, left: 30};
var width = document.body.clientWidth - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;
var tooltip = d3.select("body")
.append("div")
.attr("class", "remove")
.style("position", "absolute")
.style("z-index", "20")
.style("visibility", "hidden")
.style("top", "30px")
.style("left", "55px");
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height-10, 0]);
var z = d3.scale.ordinal()
.range(colorrange);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.weeks);
var yAxis = d3.svg.axis()
.scale(y);
var yAxisr = d3.svg.axis()
.scale(y);
var stack = d3.layout.stack()
.offset("silhouette")
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.value; });
var nest = d3.nest()
.key(function(d) { return d.key; });
var area = d3.svg.area()
.interpolate("linear")
.x(function(d) { return x(d.date); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
var svg = d3.select(".chart").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.date = format.parse(d.date);
d.value = +d.value;
});
var layers = stack(nest.entries(data));
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
svg.selectAll(".layer")
.data(layers)
.enter().append("path")
.attr("class", "layer")
.attr("d", function(d) { return area(d.values); })
.style("fill", function(d, i) { return z(i); });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis.orient("right"));
svg.append("g")
.attr("class", "y axis")
.call(yAxis.orient("left"));
svg.selectAll(".layer")
.attr("opacity", 1)
.on("mouseover", function(d, i) {
svg.selectAll(".layer").transition()
.duration(250)
.attr("opacity", function(d, j) {
return j != i ? 0.6 : 1;
})})
.on("mousemove", function(d, i) {
mousex = d3.mouse(this);
mousex = mousex[0];
var invertedx = x.invert(mousex);
invertedx = invertedx.getMonth() + invertedx.getDate();
var selected = (d.values);
for (var k = 0; k < selected.length; k++) {
datearray[k] = selected[k].date
datearray[k] = datearray[k].getMonth() + datearray[k].getDate();
}
mousedate = datearray.indexOf(invertedx);
pro = d.values[mousedate].value;
d3.select(this)
.classed("hover", true)
.attr("stroke", strokecolor)
.attr("stroke-width", "0.5px"),
tooltip.html( "<p>" + d.key + "<br>" + pro + "</p>" ).style("visibility", "visible");
})
.on("mouseout", function(d, i) {
svg.selectAll(".layer")
.transition()
.duration(250)
.attr("opacity", "1");
d3.select(this)
.classed("hover", false)
.attr("stroke-width", "0px"), tooltip.html( "<p>" + d.key + "<br>" + pro + "</p>" ).style("visibility", "hidden");
})
var vertical = d3.select(".chart")
.append("div")
.attr("class", "remove")
.style("position", "absolute")
.style("z-index", "19")
.style("width", "1px")
.style("height", "380px")
.style("top", "10px")
.style("bottom", "30px")
.style("left", "0px")
.style("background", "#fff");
d3.select(".chart")
.on("mousemove", function(){
mousex = d3.mouse(this);
mousex = mousex[0] + 5;
vertical.style("left", mousex + "px" )})
.on("mouseover", function(){
mousex = d3.mouse(this);
mousex = mousex[0] + 5;
vertical.style("left", mousex + "px")});
}
I'm trying to learn d3.js focus + context via brushing using Twitter Data Analysis. I'm trying to generate the time series plot from the data given, but it's not coming up as it should. I have created fiddle. Could someone please take a look at it, and give me a suggestion on how I can fix this?
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = { top: 430, right: 10, bottom: 20, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%Y-%m-%d %I:%M:%S").parse;
var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var area = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.count); });
var area2 = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x2(d.date); })
.y0(height2)
.y1(function(d) { return y2(d.count); });
var svg = d3.select(".trend-graph").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id","clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.csv("/TwitterProject/slides/results.csv", type, function(error, data){
x.domain(d3.extent(data.map(function(d) { return d.date; })));
y.domain([0, d3.max(data.map(function(d) { return d.count; }))])
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class","y axis")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class","area")
.attr("d", area2);
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
});
function brushed(){
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.date = parseDate(d.date);
d.count = +d.count;
return d;
}
JSFiddle
Also, the y-axis is showing up wrong. I think the problem is somewhere counting the "counts" per minute, but I couldn't figure out how to fix this.
The plot is supposed to look like this.
EDIT:
Changes I made:
var bins = {};
x.domain(d3.extent(data.map(function(d) { return d.date; })));
//y.domain([0, d3.max(data.map(function(d) { return d.count; }))]).
y.domain([0, bins]).range([height, 0]);
x2.domain(x.domain());
y2.domain(y.domain()).range([height2, 0]);
function type(d) {
d.date = parseDate(d.date);
d.count = +d.count;
var key = d.date.toDateString();
bins[key] = bins[key] || 0;
bins[key] += d.count;
console.log(bins);
return d;
}
Your data has a resolution of one second, so you're going to get a very noisy graph (in fact exactly what you're getting). You probably want to do some binning, where you aggregate the data to make it less noisy.
In principle, the code looks like this (to aggregate by the minute):
function type(d) {
d.date = parseDate(d.date);
d.count = +d.count;
d.date.setSeconds(0);
var key = df(d.date);
bins[key] = bins[key] || 0;
bins[key] += d.count;
return d;
}
and then inside d3.csv:
var binData = d3.entries(bins);
binData.forEach(function(d) { d.key = parseDate(d.key); });
binData.sort(function(a,b) { return b.key - a.key; });
There's a bit of additional cruft because Date objects don't play nice as associative array keys. Now you have elements with key (date) and value in binData, which you can use to create the graph.
Complete demo here.
i have used d3 chart. my data range is 600 to 1400.
when onLoad the charts shows the correct range.
the problem is when i scroll down its goes away like top 4000, bottom -2000.
how can i stop this.
the range show not be exceed.
regards,
Subash
this is my code
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 50
},
width = 1000,
height = 150;
d3.select("rect")
.filter(function(d) { return d.value === max; })
.classed("max", true);
var x = d3.time.scale()
.domain(d3.extent(data, function (d) {
return d.date;
}))
.range([0, width]);
//var y = (d3.scale.linear().domain(['100', '1000']))
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 xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.hour)
//var xAxis = d3.svg.axis()
// .scale(x)
// .tickValues([1, 2, 3, 5, 8, 13, 21]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
var zoom = d3.behavior.zoom().x(x).y(y).on("zoom", refresh);
var zoomRect = false;
d3.select("#zoom-rect").on("change", function () {
zoomRect = this.checked;
});
var svg = d3.select("#realtimechart").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)
.append("g")
.on("mousedown", function () {
if (!zoomRect) return;
var e = this,
origin = d3.mouse(e),
rect = svg.append("rect").attr("class", "zoom");
d3.select("#realtimechart").classed("noselect", true);
origin[0] = Math.max(0, Math.min(width, origin[0]));
origin[1] = Math.max(0, Math.min(height, origin[1]));
d3.select(window)
.on("mousemove.zoomRect", function () {
var m = d3.mouse(e);
m[0] = Math.max(0, Math.min(width, m[0]));
m[1] = Math.max(0, Math.min(height, m[1]));
rect.attr("x", Math.min(origin[0], m[0]))
.attr("y", Math.min(origin[1], m[1]))
.attr("width", Math.abs(m[0] - origin[0]))
.attr("height", Math.abs(m[1] - origin[1]));
})
.on("mouseup.zoomRect", function () {
d3.select(window).on("mousemove.zoomRect", null).on("mouseup.zoomRect", null);
d3.select("#realtimechart").classed("noselect", false);
var m = d3.mouse(e);
m[0] = Math.max(0, Math.min(width, m[0]));
m[1] = Math.max(0, Math.min(height, m[1]));
if (m[0] !== origin[0] && m[1] !== origin[1]) {
zoom.x(x.domain([origin[0], m[0]].map(x.invert).sort()))
.y(y.domain([origin[1], m[1]].map(y.invert).sort()));
}
rect.remove();
refresh();
}, true);
d3.event.stopPropagation();
});
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);
};
svg.append("rect")
.attr("width", width)
.attr("height", height);
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", "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 refresh() {
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);
}
We are plotting a multilinear graph using d3.v2.js .
We are using ordinal scale for x-axis and linear scale for y-axis as we have labels(string) to be shown in x-axis
and numbers to be shown in y-axis.
In some cases graph appears to be fine , but in some cases it plots x-axis and y-axis independently and y-axis values are not in sync with x-axis values.
Also plotting starts from 0 instead of first x-axis value.
Any pointers to this issue would be of great help.
Thanks in advance.
Please find the code below.
function plotMOAGraph(data , sigPathways){
var margin = {top: 20, right: 80, bottom: 30, left: 100},
width = 960 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var x = d3.scale.ordinal(
(d3.range(0,sigPathways.length))).rangeBands([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.pathway); })
.y(function(d) { return y(d.score); });
var svg = d3.select("#graphDiv").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", 450 + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "pathway"; }));
var entityNames = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {pathway: d.pathway, score: +d[name]};
})
};
});
x.domain(sigPathways);
y.domain([
d3.min(entityNames, function(c) { return d3.min(c.values, function(v) { return v.score; }); }),
d3.max(entityNames, function(c) { return d3.max(c.values, function(v) { return v.score; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("dy", "9em")
.attr("dx","40em")
.style("text-anchor", "end")
.text("Pathways");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "-4em")
.style("text-anchor", "end")
.text("Pathway Scores");
var tooltip = d3.select("#graphDiv")
.append("div")
.style("visibility", "hidden")
;
var rotateXAxis = function(d) {
var name = d.substr(0, 15);
if(name !== d) {
name = name + " ... ";
}
var el = d3.select(this);
el.text('').attr("transform", "rotate(-45)").attr("text-anchor", "end").on("mouseover", showTooltip).on("mouseout",hideTooltip);
var tspan = el.append('tspan').text(name);
tspan.attr('x', 0).attr('dy', '0');
};
svg.selectAll('g.x.axis g text').each(rotateXAxis);
function showTooltip(d) {
tooltip.text(d).style("position","absolute")
.style("top", (d3.event.pageY)-10+"px")
.style("left", (d3.event.pageX)-300+"px")
.style("visibility", "visible")
.style("font-size", "12px");
}
function hideTooltip() {
tooltip.style("visibility", "hidden");
}
var entityName = svg.selectAll(".entityName")
.data(entityNames)
.enter().append("g")
.attr("class", "entityName");
entityName.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values); })
.style("stroke", function(d) {return color(d.name); });
entityName.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.pathway) + "," + y(d.value.score) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
}