License: html5csv.js is dual-licensed and may be used under your choice of GPLv3 free software license or MIT open source license.
Quickly create apps that generate, "upload", "download", slice, analyze, plot, edit and store CSV tabular data...
... all without a server . Or with a server, too. Extendable.
This 6 year old code library is largely unmaintained.
I am somewhat surprised by the popularity of this library. I initially developed it as a learning experience and for data analysis in Javascript apps. I have since moved to Plotly for charting. For data analysis working in python and Jupyter is more mainstream than coding at a lower, more detailed level in Javascript.
From time to time I'll get some email about current applications. One company used this code to help manage commercial buildings. This code enabled them to see charts and then get the .csv data files from another web-based system. Another company had used the random table generator herein to run their computerized kiosk games in a small casino in Asia. Feel free to let me know if you have come up with a unique or unexpected application.
The following unpaid volunteer roles are available:
- co-maintainers
- contributors
Some prior Javascript experience required. Data science background a plus.
Tell me what you would like to improve or work on. One overriding goal was to keep the library very simple. For example, an undergraduate with a bit of website experience should be able to use this library and Jquery to make a demonstration website out of research data.
Here are some obvious needs:
- standardize documentation and improve readability
- portfolio of examples (this library can do multiple regression and principal components analysis)
- pluggable additions
- additional "made simple" machine learning techniques
Email: drpaulbrewer@eaftc.com
- jQuery
- LZString (for compression)
- numeric.js (for analysis)
- qunit (for unit testing)
The optional libraries are authored by others and distributed under the MIT-License. Verbatim copies recent as of August 2013 are included in the external-free subdirectory.
JSFiddle for Example 1: Hello World in html5csv
In every introductory language class there is usually a "Hello World" program that teaches the basics of how to get the language to do something by having it print "Hello World".
Usually in a "Hello World" example one shows the boilerplate code that is common to most applications and the procedures for getting the code to run. Usually, the "Hello World" example merely prints "Hello World".
Here, we want to work with tabular or matrix data, so we need to go a little further.
Example 1 will:
- create some data
- Hello and World as the column headings
- Various names and their planets as the values.
- show how to get this data into CSV.begin()
- Create and display an HTML table from the data.
- Save the data in browser local storage, so it will still be there tomorrow, or at least for Example 2.
For HTML Boilerplate you would need to load at least jQuery and html5csv.js. Optionally you could load LZString for automatic (de)compression of objects being stored into local storage.
example1.html
<!DOCTYPE html5>
<html>
<head>
<title>html5csv Example 1: Hello World</title>
</head>
<body>
<div id='output'></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="./external-free/lz-string-1.3.0.js"></script>
<script src="./html5csv.js"></script>
<script src="./example1.js"></script>
</body>
</html>
example1.js
CSV.
begin([
["Hello","World"],
["Paul","Earth"],
["Marvin","Mars"],
["Spock","Vulcan"]
]).
table("output",{header:1,caption:"My First html5csv program"}).
save("local/helloWorld").
go();
- CSV. accesses the CSV object created by html5csv.js CSV. is the only global object
created by html5csv, on
window
. - begin selects data to fetch into the CSV engine. The chain of methods starting with begin and ending with go or finalize is queued internally as a CSV workflow.
- table will generates a table in the div named "output". If the div does not exist, it is appended to document.body
- save will save the table data (and some meta data) in HTML 5 browser localStorage with key "local/helloWorld", using LZString compression if available;
- go() starts the chain of methods, or CSV workflow, executing. Execution of each step is asynchronous and involves a brief delay in setTimeout before going to the next step.
JSFiddle Example 2 Downloading HelloWorld.csv
Prerequisite: Example 1 loads data that will be used by Example 2. Do Example 1 first.
Example #2 may not work on all browsers, but recent Chrome and Firefox seem ok.
Code for IE11 was also added Jan 2015.
Credit: The serverless download code was inspired by Stack Overflow answers from adeneo for FF/Chrome and Manu Sharma for IE11 to Export javascript data to csv file without server interaction
In HTML, load jQuery, LZstring if you used it in example 1, and html5csv.js, and then generating a download is a Javascript one-liner (and can also be tried from the console):
CSV.begin("local/helloWorld").download("HelloWorld.csv").go();
Here, we access the data created in example 1.
It was stored away in the browser, and it will stay there until explicitly deleted.
We are going to take that data, and generate a CSV file called "HelloWorld.csv" and output it to the user. The data downloads directly from the browser. No server is involved.
The user will not have to click on a link, it is pushed at him.
For a better user experience, this code could be triggered by a click in the
usual way, such as $('#someButtton').on('click', function(){ CSV.begin.....go(); });
If you are working with the jsFiddle example,
you could execute a localStorage.clear()
within the jsFiddle javascript window
to clear the local storage
.
Local Storage is stored by site, so if you go to another website, it will not be accessible, but it will become
available again when the browser is pointed at the site that stored it. Otherwise, to clear the data from a browser, do a general
a "delete cookies, storage, and other site and plugin data" from the browsers control panel.
A name like session/helloWorld
(instead of local/helloWorld
) would delete
data when the session tab or window is closed instead of keeping it potentially
forever... because then the data will be stored in HTML 5 session storage
instead
of HTML 5 local storage
.
Names with slants that are not local/ or session/ must be mapped by a plugin, possibly to a server. No plugins are currently available, but one is under development and testing. Names beginning with a / are interpreted as local URLs, to run through an ajax get. The ajax get feature will be documented after some additional testing.
Input capabilities include:
- prompting the user for an input file (in CSV format)
- scraping an HTML table
- reading local and session storage, which was demonstrated above
- creating special arrays of uniform or normal random variables
- arrays prefilled with zero, a number, or a diagonal,
- arrays generated by a user supplied function
- reading from URLs via ajax (same origin restriction applies unless the server sends a CORS header or supports JSONP)
<input type='file' id='choose' />
Note: this code does not immediately read the file chosen in #choose
, it attaches an event listener to the #choose
file input and waits for a change. See Issue #12 for more discussion.
CSV.begin('#choose').....go();
Works the same way, but there is no HTML input element.
The name in CSV.begin(name) can be a valid jQuery selector like #divId, and if there are table rows as descendents it will gather the data.
-
A 5x10 matrix of uniform [0,1] Random Variables
CSV.begin('%U', {dim: [5,10]}).do-stuff...go();
-
A 1000x2 matrix of Normal (mean=0,var=1) Random Variables naming the columns E1 and E2 in the first row
CSV.begin('%N', {dim: [1000,2], header:['E1','E2'}).do-stuff...go();
-
A 5x5 matrix with 1 along the diagonal
CSV.begin('%I', {dim: [5,5]}).do-stuff....go();
orCSV.begin('%D', {diag: [1,1,1,1,1]}).do-stuff....go();
-
A 100x100 matrix with values given by a function of row i, column j over [0,l-1]
CSV.begin('%F', {dim:[100,100], func: function(i,j){ return (1+i)/(1+j); }})......go();
go takes a Javascript function
as a parameter.
We call this function the "final callback" function, because it is executed at the end of the workflow or when an error occurs.
If you don't supply a final callback function, a default is supplied for you:
default final callback: function(e,D){ if(e) console.log(e) }
The default will log all errors to the console log.
But you can tell go() to do something useful with the data at the end of the CSV work flow... for example, you can pass the data rows to another function, or modify them and start another CSV workflow from the modified rows.
Let's say there is a dashboad function in your app that wants rows of data supplied as dashboard('draw', rows).
If e is null, the data rows are in D.rows and the meta data (if any) is in D.meta.
We could write an appropriate finalCallback as an anonymous function inline in the CSV workflow.
CSV.......go(
function(e,D){
if (e) return console.log(e); //something went wrong and we return
// if OK, then call our custom "dashboard" function as discussed
dashboard('draw', D.rows);
});
Warning: CSV.....go(callback) is asynchronous, don't fall prey to the asynchronous/global-var anti-pattern
Do not set a global variable in the final callback and expect to retrieve the data immediately after go returns.
These accesses will almost always fail, because ...go(callback)
or ...go()
returns almost immediately, before the workflow has had
time to finish.
The correct approach is to put all activity that depends on the final returned data in the final Callback.
If you are a beginner and use to the imperative style of coding, (first do this, then do that) this may involve a shift in your thinking towards a more functional style of coding (when event X happens, let function handleX handle it). The browser environment generally favors such a shift of thinking in terms of functions that responsd to user clicks or changes in forms.
Trying to use a callback as a way to return data into a global variable is a common AJAX anti-pattern, and questions appear on Stack Overflow every week about this regarding ajax calls: why the ajax doesn't work or why the return value disappears outside of the ajax success function.
Although CSV.....go() in many cases could have been implemented synchronously, htm5csv.js makes all workflow asynchronous to give clear expectations and also allow the browser a pause to process other events between potentially intensive tasks.
Asynchronous workflows can appear when involving user editing of input, supervised machine learning, as well as ajax interactions with a server, when necessary.
Possibly, you want to do something a little more serious now, like generate or upload numerical data, run a regression, or plot data.
More documentation, still a bit rough, can be found in the wiki.
If unsure about the wiki, look in the html5csv source code
For more examples, read through the unit tests in qtestcsv.js
Since Feb.2016, every commit to html5csv is automatically tested in Firefox by travis-ci, generating the clickable "build" badge at the top of this page.
You can also run the unit tests in your own browser using the Qunit page. Note that the code and tests come from the gh-pages branch, which is not updated as frequently as the main branch.