I am trying to render 2 graphs on the same page: chart graph and a linear graph
in html i have two divs which bind to the 2 different graphs respectively like so:
<div id="svg-container">
<div id="svg-container-avg">
The first graph that i import in html is this linear 'average' graph that just doesn't display the path or the x axis.
It works fine if i delete the chart graph which is imported straight after. I would automatically assume that there are some sort of dependencies between the two graphs, but i cannot find anything...
my first import, linear graph: scns-avg.js file contains this
// Set the dimensions of the canvas / graph
var margin = {
top: 30,
right: 20,
bottom: 70,
left: 50
},
width = 800 - margin.left - margin.right,
height = 350 - margin.top - margin.bottom;
var x = d3.scale.linear().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
var valueline = d3.svg.line()
.x(function(d) {
return x(d.scnsID);
})
.y(function(d) {
return y(d.average);
});
var svg2 = d3.select("#svg-container-avg")
.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 + ")");
// Get the data
d3.json("scns-avg-data-retrieval.php", function(error, data) {
data.forEach(function(d) {
d.scnsID = d.scnsID;
d.average = +d.average;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.scnsID;
}));
y.domain([0, d3.max(data, function(d) {
return d.average;
})]);
svg2.append("path") // Add the valueline path.
.style("stroke", "rgba(13, 183, 196, 0.9)")
.attr("d", valueline(data));
svg2.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) {
return x(d.scnsID);
})
.attr("cy", function(d) {
return y(d.average);
})
svg2.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg2.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
});
My Data structor in JSON:
[{"date":"11-Mar-16","average":"3.18","scnsID":"2"},{"date":"12-Mar-16","average":"3.09","scnsID":"3"},{"date":"15-Mar-16","average":"3.16","scnsID":"4"},{"date":"17-Mar-16","average":"3.20","scnsID":"5"}]
When trying to run the html page with both graphs being imported the scns-avg.js throws up in the console Error: Invalid value for attribute d="M43,2.8124999999999902LNaN,15.46875000000002LNaN,5.6249999999999805L471,0"
which points to valueline(data) in this part of the code
svg2.append("path")
.style("stroke", "rgba(13, 183, 196, 0.9)")
.attr("d", valueline(data));
That is dependent on this piece of code, so the problem must be lying here, but for 6 hours now i can't find the solution to this..
var valueline = d3.svg.line()
.x(function(d) { return x(d.scnsID); })
.y(function(d) { return y(d.average); });
My chart graph that gets imported next and if disabled the linear graph renders properly is as follows below:
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Frequency:</strong> <span style='color:rgba(13, 183, 196, 0.9)'>" + d.average + "</span>";
});
var svg = d3.select("#svg-container").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.call(tip);
// Get the data
d3.json("scns-data-retrieval.php", function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.question = d.question;
d.average = +d.average;
});
x.domain(data.map(function(d) { return d.question; }));
y.domain([0, 5]);
legendSpace = width/5;
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 3))
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Level of need for help:");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.question); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.average); })
.attr("height", function(d) { return height - y(d.average); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
});
function type(d) {
d.average = +d.average;
return d;
};
data structure in JSON:
[{"question":1,"average":3.3333333333333},{"question":2,"average":2.5},{"question":3,"average":4},{"question":4,"average":2.75},{"question":5,"average":2.75},{"question":6,"average":2.75},{"question":7,"average":3},{"question":8,"average":3},{"question":9,"average":2.75},{"question":10,"average":3.25},{"question":11,"average":3.25},{"question":12,"average":3.5},{"question":13,"average":3},{"question":14,"average":3.25},{"question":15,"average":3.5},{"question":16,"average":3.5},{"question":17,"average":3.25},{"question":18,"average":3.75},{"question":19,"average":3.5},{"question":20,"average":3},{"question":21,"average":3},{"question":22,"average":3.5},{"question":23,"average":3.25},{"question":24,"average":3.75},{"question":25,"average":3.75},{"question":26,"average":3.75},{"question":27,"average":3.5},{"question":28,"average":2.75},{"question":29,"average":2.25},{"question":30,"average":3.5},{"question":31,"average":3},{"question":32,"average":3}]
I can't do this anymore and it's driving me crazy so i am now turning to the power of stackoverflow!
After some mad research and trial and error i have fixed this problem.
When you are trying to render more than 1 graph, if they are of different type and not lets say - multiple linear graphs, but something like a linear graph with a bar chart the variable scope is getting mixed up and it's not restricted to the javascript file once it's imported into html.
To fix this problem every graph js file has to wrapped in (function(){ All your graph code goes here })();
This restricts the variable scope to just the function.
I am having an issue using d3 to create a bar chart where the column overflows the and the y axis labels are incorrect. Here is a fiddle http://jsfiddle.net/fajgvj9v/ that shows the issue. The data is parsing the <pre id="data"> tag to simulate a CSV I am using. If you change the value of 'a' to 5000 from 4000 it renders as expected.
<pre id="data">
name,count
a, 4000
b, 500
</pre>
yTitle = "Items";
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var y = d3.scale.linear()
.rangeRound([height, 0]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svg = d3.select("#malware_by_os").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = d3.csv.parse( d3.select("pre#data").text() );
console.log(data);
var xLbl = d3.keys(data[0])[0];
var yLbl = d3.keys(data[0])[1];
data.sort(function(a, b) {
return b[yLbl] - a[yLbl];
});
x.domain(data.map(function(d) {
return d[xLbl];
}));
y.domain([0, d3.max(data, function(d) {
return d[yLbl];
})]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(yTitle);
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d[xLbl]);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d[yLbl]);
})
.attr("height", function(d) {
return height - y(d[yLbl]);
});
The max function needs to convert to a number using +
y.domain([0, d3.max(data, function(d) {
return d[yLbl];
})]);
should be
y.domain([0, d3.max(data, function(d) {
return +d[yLbl];
})]);
I have a big problem.
I use d3 to visualize my (poll)data. (So Questions and answers) It works fine except one problem.
Sometimes it doesn't visualize the data like they are. For example one time d3 get all right data about d3.json. But the graph is not right. It should load 300 answers in the first bars but it just show 50. I tested it and the json works.
I tried to filter the graph and I got the same problem.
This is my d3 code.
<div>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
var margin = {
top: 20,
right: 30,
bottom: 30,
left: 430
},
width = 1400 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var xScale = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var yScale = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10);
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("class", "chart");
var chart = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("getdata.php", function(error, data) {
xScale.domain(data.map(function(d) {
return d.text;
}));
yScale.domain([0, d3.max(data, function(d) {
return d.count;
})]);
chart.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return xScale(d.text);
})
.attr("y", function(d) {
return yScale(d.count);
})
.attr("height", function(d) {
return height - yScale(d.count);
})
.attr("width", xScale.rangeBand())
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
chart.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Antworten");
});
function type(d) {
d.count = +d.text;
return d;
}
</script>
</div>
I guess the problem starts here. But I don't know why. The problem doesn't appear at every question. Only at a few or when I try to use my filter.
Maybe it happens when two values have a big difference?
Update:
It is like: D3 doesn't want to lose the smallest bar. So other bars must based on that smallest. And then the values are not correct for the bigger bars. Maybe the Y scale depends on the smallest bar.
I am having a lot of trouble with D3 bar chart where the length of the data I get from search is variable. I used the D3 bar chart example and built this. However as data length goes up, the graph gets less and less legible. The problem seems to be the range gets confused when it is beyond 100 points or so.
Code is below:
function makegraph(data,ctype) {
//var data=xdata.splice(-900)
var gwidth=data.length*2;
if(gwidth < 800) gwidth=800;
//gwidth=800
var margin = {top: 9, right: 20, bottom: 30, left: 90},
width = gwidth - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
//x=d3.scale.linear().domain([0,1]).range(0,width)
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(function(d) { if (d % 10) return ""; else return d;})
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
// .ticks(10, "%");
d3.select("svg").remove()
var svg = d3.select("#graphchart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var line = d3.svg.line()
.x(function(d) { return x(d.rowid); })
.y(function(d) { return y(d[ctype]); });
x.domain(data.map(function(d) { return d.rowid; }));
var ymax=d3.max(data, function(d) { return d[ctype]; });
var ymin=d3.min(data, function(d) { return d[ctype]; });
y.domain([ymin, ymax]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", Math.log10(ymax))
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Bytes");
// console.log(x.rangeBand())
var bar = svg.selectAll(".bar")
.data(data);
bar.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.rowid); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d[ctype]); })
.attr("height", function(d) { var xya= height - y(d[ctype]); /* console.log(xya+":"+d[ctype]); */ return height - y(d[ctype]); })
/* .attr("title", function(d) { return d['bytes']+" Bytes at "+d.stime; }) */
.on("mouseover", function(d) { $("#graphinfo").html(d3.format('0,000')(d['bytes'])+" Bytes at "+d.stime) })
.on("mouseout",function(d) { $("#graphinfo").html(' ')})
.on("click",function(d) { tablegraph(d)});
$('.bar').tooltip()
}
Do you have suggestions how I can make this graph so that the bar chart will grow horizontally for larger data sets? Thanks for any help and suggestions!
Vijay
I looking any chart library which has configuration for custom y-axis values. I want to customize the y-axis like ( 0 to 3). I seen D3 and other chart libraries, the Y-axis automatically generates the values. I my design there is only one filed and on one for compare on the x-axis.
Which chart library is most suited for this condition to make this happen. If any example already on google, please share...
If you are looking for a D3 solution then you can refer my fiddle below:
http://jsfiddle.net/cyril123/7ftuumv4/2/
code:
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
//specify data here
data = [{letter: "1", value: 1.3}]
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.range([height, 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 + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//as you have a fixed x axis value and single data
x.domain([data[0].letter]);
//as you have a fixed range for y axis
y.domain([0, 3]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value");
//make the bar chart
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });