Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3js take data from an array instead of a file

I have found this excellent d3js chart here. However in my case I want this chart to take value from an array instead of a tsv file. I want to make it to take values from a table []. How I can do that? because it uses a function for that, and I do not know where I should put my array.

Using d3-tip to add tooltips to a d3 bar chart. <!DOCTYPE html> <meta charset="utf-8"> <style>  body {   font: 10px sans-serif; }  .axis path, .axis line {   fill: none;   stroke: #000;   shape-rendering: crispEdges; }  .bar {   fill: orange; }  .bar:hover {   fill: orangered ; }  .x.axis path {   display: none; }  .d3-tip {   line-height: 1;   font-weight: bold;   padding: 12px;   background: rgba(0, 0, 0, 0.8);   color: #fff;   border-radius: 2px; }  /* Creates a small triangle extender for the tooltip */ .d3-tip:after {   box-sizing: border-box;   display: inline;   font-size: 10px;   width: 100%;   line-height: 1;   color: rgba(0, 0, 0, 0.8);   content: "\25BC";   position: absolute;   text-align: center; }  /* Style northward tooltips differently */ .d3-tip.n:after {   margin: -1px 0 0 0;   top: 100%;   left: 0; } </style> <body> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script> <script>  var margin = {top: 40, right: 20, bottom: 30, left: 40},     width = 960 - margin.left - margin.right,     height = 500 - margin.top - margin.bottom;  var formatPercent = d3.format(".0%");  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")     .tickFormat(formatPercent);  var tip = d3.tip()   .attr('class', 'd3-tip')   .offset([-10, 0])   .html(function(d) {     return "<strong>Frequency:</strong> <span style='color:red'>" + d.frequency + "</span>";   })  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 + ")");  svg.call(tip);  d3.tsv("data.tsv", type, function(error, data) {   x.domain(data.map(function(d) { return d.letter; }));   y.domain([0, d3.max(data, function(d) { return d.frequency; })]);    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("Frequency");    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.frequency); })       .attr("height", function(d) { return height - y(d.frequency); })       .on('mouseover', tip.show)       .on('mouseout', tip.hide)  });  function type(d) {   d.frequency = +d.frequency;   return d; }  </script> 

Thanks a lot

like image 817
Jim Blum Avatar asked Feb 07 '14 22:02

Jim Blum


People also ask

How do I import a CSV file into D3 JS?

D3 provides the following methods to load different types of data from external files. Sends http request to the specified url to load . csv file or data and executes callback function with parsed csv data objects. Sends http request to the specified url to load .

What can d3js do?

D3 allows you to bind arbitrary data to a Document Object Model (DOM), and then apply data-driven transformations to the document. For example, you can use D3 to generate an HTML table from an array of numbers. Or, use the same data to create an interactive SVG bar chart with smooth transitions and interaction.

Is D3 js still relevant?

The JavaScript ecosystem has completely changed during this time, in terms of libraries, best practices and even language features. Nevertheless, D3 is still here. And it's more popular than ever.

Is the syntax to read JSON data in D3?

json() function is used to fetch the JSON file. If this function got an init parameter, then this is called along with the fetch operation. Syntax: d3.


2 Answers

The D3 gallery has a lot of good examples, but a lot of the examples loads their data from a tab-separated values file. This is a nice way to separate data and visualization in short examples, but it can be a bit confusing if you are new to D3 and JavaScript, since it requires some basic knowledge about both d3.tsv() and callback functions to understand what is going on.

Disclaimer: The following sections will give some very simplified explanations.

What is d3.tsv() doing?

d3.tsv() is basically responsible for loading the data from data.tsv, parse it into a variable called data, and send this variable to a callback function.

d3.tsv("data.tsv", type, function(error, data) { <- This is the callback function!   // This code is executed when the data.tsv file is loaded. }); 

As soon as the data is loaded, it is sent as the data argument to the function. Then the code inside the callback function is executed. Since we don't need the callback function for anything else than as an argument to the d3.tsv() function, we make it directly as an anonymous function, instead of giving it a name like usual.

This kind of use of callback and anonymous functions is very typical of JavaScript, and is well worth reading up on. Understand JavaScript Callback Functions and Use Them and Understanding JavaScript Callbacks should get you started.

Let's see how we can use this information to rewrite our code.

How can I rewrite the example to use data from a local variable?

First we have to make variable containing our data. Let's call it "data", the same as in our callback function, and give it the values from the example.

var data = [   {letter: "A", frequency: .08167},   {letter: "B", frequency: .01492},   {letter: "C", frequency: .02780},   {letter: "D", frequency: .04253},   {letter: "E", frequency: .12702},   {letter: "F", frequency: .02288},   {letter: "G", frequency: .02022},   {letter: "H", frequency: .06094},   {letter: "I", frequency: .06973},   {letter: "J", frequency: .00153},   {letter: "K", frequency: .00747},   {letter: "L", frequency: .04025},   {letter: "M", frequency: .02517},   {letter: "N", frequency: .06749},   {letter: "O", frequency: .07507},   {letter: "P", frequency: .01929},   {letter: "Q", frequency: .00098},   {letter: "R", frequency: .05987},   {letter: "S", frequency: .06333},   {letter: "T", frequency: .09056},   {letter: "U", frequency: .02758},   {letter: "V", frequency: .01037},   {letter: "W", frequency: .02465},   {letter: "X", frequency: .00150},   {letter: "Y", frequency: .01971},   {letter: "Z", frequency: .00074} ]; 

Put this variable somewhere before the call to d3.tsv, as the code in the callback function is dependent on this variable.

I have choose to represent the data as a list of objects with a letter and frequency property. This is an easy way to do it, since it closely resembles the way d3.tsv() would parse the .tsv file. This means that we don't have to change the code in the callback function, since it already expects a variable with data in this format. You can change this if you like, but remember to change how the callback code uses the "data" variable.

Now we can remove the code related to the d3.tsv call, just leaving the code contained in the callback function. So this code:

d3.tsv("data.tsv", type, function(error, data) {   x.domain(data.map(function(d) { return d.letter; }));   // code omitted.   .on('mouseout', tip.hide) }); 

Becomes this code:

x.domain(data.map(function(d) { return d.letter; })); // code omitted. .on('mouseout', tip.hide) 

Now the example should be working fine. You can play around with this strategy for rewriting other examples in the D3 gallery as well.

Finally, I have included the code for the new index.html file. A working example can be found at JSFiddle.

<!DOCTYPE html> <meta charset="utf-8"> <style>  body {   font: 10px sans-serif; }  .axis path, .axis line {   fill: none;   stroke: #000;   shape-rendering: crispEdges; }  .bar {   fill: orange; }  .bar:hover {   fill: orangered ; }  .x.axis path {   display: none; }  .d3-tip {   line-height: 1;   font-weight: bold;   padding: 12px;   background: rgba(0, 0, 0, 0.8);   color: #fff;   border-radius: 2px; }  /* Creates a small triangle extender for the tooltip */ .d3-tip:after {   box-sizing: border-box;   display: inline;   font-size: 10px;   width: 100%;   line-height: 1;   color: rgba(0, 0, 0, 0.8);   content: "\25BC";   position: absolute;   text-align: center; }  /* Style northward tooltips differently */ .d3-tip.n:after {   margin: -1px 0 0 0;   top: 100%;   left: 0; } </style> <body> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script> <script>  var margin = {top: 40, right: 20, bottom: 30, left: 40},     width = 960 - margin.left - margin.right,     height = 500 - margin.top - margin.bottom;  var formatPercent = d3.format(".0%");  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")     .tickFormat(formatPercent);  var tip = d3.tip()   .attr('class', 'd3-tip')   .offset([-10, 0])   .html(function(d) {     return "<strong>Frequency:</strong> <span style='color:red'>" + d.frequency + "</span>";   })  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 + ")");  svg.call(tip);  // The new data variable. var data = [   {letter: "A", frequency: .08167},   {letter: "B", frequency: .01492},   {letter: "C", frequency: .02780},   {letter: "D", frequency: .04253},   {letter: "E", frequency: .12702},   {letter: "F", frequency: .02288},   {letter: "G", frequency: .02022},   {letter: "H", frequency: .06094},   {letter: "I", frequency: .06973},   {letter: "J", frequency: .00153},   {letter: "K", frequency: .00747},   {letter: "L", frequency: .04025},   {letter: "M", frequency: .02517},   {letter: "N", frequency: .06749},   {letter: "O", frequency: .07507},   {letter: "P", frequency: .01929},   {letter: "Q", frequency: .00098},   {letter: "R", frequency: .05987},   {letter: "S", frequency: .06333},   {letter: "T", frequency: .09056},   {letter: "U", frequency: .02758},   {letter: "V", frequency: .01037},   {letter: "W", frequency: .02465},   {letter: "X", frequency: .00150},   {letter: "Y", frequency: .01971},   {letter: "Z", frequency: .00074} ];  // The following code was contained in the callback function. x.domain(data.map(function(d) { return d.letter; })); y.domain([0, d3.max(data, function(d) { return d.frequency; })]);  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("Frequency");  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.frequency); })     .attr("height", function(d) { return height - y(d.frequency); })     .on('mouseover', tip.show)     .on('mouseout', tip.hide)  function type(d) {   d.frequency = +d.frequency;   return d; }  </script> 
like image 174
Teodor Avatar answered Oct 08 '22 10:10

Teodor


The whole d3.tsv() stuff (or d3.json() or whatever) is optional. So just strip it with its callback and use your data directly:

var fruits = ['apple', 'mango', 'banana', 'orange']; d3.select('ul')     .selectAll('li')     .data(fruits)     .enter()     .append('li')     .text(function(d) { return d; }); 

PS: Thats why you will not find a d3.data() function or whatever, I was searching it for a while ;-)

like image 23
flori Avatar answered Oct 08 '22 10:10

flori