I'm new to D3.js and CodeMirror (and to StackOverflow as well, please pardon my mistakes) and I want to try some cool stuff for my newest project, so these two are my best bet but I had some problem. Please help me noticing what I'm doing wrong, and what the best solution to make this program work out. I'm glad we have good forum here.
So, long story short, I'm trying to build a visualization tools by using D3.js and CodeMirror as my editor. For example, this is what I try to visualize, but instead of reading the morley.csv
data (hard-coded), I want to input the data from my CodeMirror editor. So this is what I write for the editor:
<textarea id="values"></textarea>
<script>
var editor = CodeMirror.fromTextArea(values, {
lineNumbers: true,
matchBrackets: true,
theme : '3024-day'
});
</script>
<a id="gen" class="btn btn-primary btn-block" role="button">Generate Visualization</a>
And this for the visualization builder:
<div class="row" id="chart">
<script>
d3.select("#gen").on("click", function(){
d3.event.preventDefault();
d3.select("#chart svg").remove();
var dataset = editor.getValue();
var margin = {top: 10, right: 50, bottom: 20, left: 50},
width = 120 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var min = Infinity,
max = -Infinity;
var chart = d3.box()
.whiskers(iqr(1.5))
.width(width)
.height(height);
d3.csv(dataset, function(error, csv) {
if (error) throw error;
var data = [];
csv.forEach(function(x) {
var e = Math.floor(x.Expt - 1),
r = Math.floor(x.Run - 1),
s = Math.floor(x.Speed),
d = data[e];
if (!d) d = data[e] = [s];
else d.push(s);
if (s > max) max = s;
if (s < min) min = s;
});
chart.domain([min, max]);
var svg = d3.select("#chart").selectAll("svg")
.data(data)
.enter().append("svg")
.attr("class", "box")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.bottom + margin.top)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(chart);
setInterval(function() {
svg.datum(randomize).call(chart.duration(1000));
}, 2000);
});
function randomize(d) {
if (!d.randomizer) d.randomizer = randomizer(d);
return d.map(d.randomizer);
}
function randomizer(d) {
var k = d3.max(d) * .02;
return function(d) {
return Math.max(min, Math.min(max, d + k * (Math.random() - .5)));
};
}
function iqr(k) {
return function(d, i) {
var q1 = d.quartiles[0],
q3 = d.quartiles[2],
iqr = (q3 - q1) * k,
i = -1,
j = d.length;
while (d[++i] < q1 - iqr);
while (d[--j] > q3 + iqr);
return [i, j];
};
}
});
</script>
</div>
Let's just assumed I used the same morley.csv
for my input data.
Somehow it didn't work as I planned. I don't understand what I'm missing here, but my best guess it must have something to do with how d3.csv
can't parse my input from textarea values
. The output div chart
is always show nothing..
Thanks for helping out, although I'm new here. Any help is more than appreciated.
1.
Change d3.csv()
to d3.csv.parse()
or d3.csvParse()
in the newer versions. The former only accepts a file name, the latter accepts a string of CSV data.
Debug and make sure your dataset variable is truly a comma separated string.
2. Also, if all that you need is a flat array like [1,2,3], I think you need to take all of that code out of the callback function and just do this:
data = d3.csv.parse(dataset);
Then just continue with your existing code after that.
The reason to have a callback function in the csv.parse call is only to structure the returned array; e.g. if your array elements are objects with multiple values inside of them, you'd set that up in the callback function.