<html> <head>
<title>Sparklines.js</title>
<!--[if IE]><script type="text/javascript" src="excanvas.js"></script><![endif]-->
<script type="text/javascript" src="processing.js"></script>
<script type="text/javascript" src="sparklines.js"></script>
</head>
<script>
var setup_sparklines = function() {
var opts = {};
var data = [100,500,300,200,400,500,400,400,100,200];
new Sparkline('simple1', data).draw();
opts = {'left_padding':50,'right_padding':50,'top_padding':25, 'bottom_padding':25};
new Sparkline('simple2',data, opts).draw();
opts = {'left_padding':0,'right_padding':0,'top_padding':0, 'bottom_padding':0};
new Sparkline('simple3',data, opts).draw();
opts = {"background_color":"#FFEEDD","line_color":"#001122"};
new Sparkline('simple4',data, opts).draw();
opts = {"percentile_lines":[0.5]};
new Sparkline('simple5a',data,opts).draw();
opts = {"percentile_lines":[0.25,0.75]};
new Sparkline('simple5',data,opts).draw();
opts = {"percentile_lines":[0.25,0.75],"fill_between_percentile_lines":true};
new Sparkline('simple6',data,opts).draw();
var data2 = [100,200,500,1000,600,900,300,500,800,800,900,1000,50,40,200,100,900,300,400,
400,600,700,800,900,700,800,50,100,100];
opts = {"percentile_lines":[0.25,0.5,0.75],"fill_between_percentile_lines":true};
new Sparkline('simple7',data2,opts).draw();
opts = {"percentile_lines":[0.25,0.5,0.75],"fill_between_percentile_lines":true,
"left_padding":1,"right_padding":1,"top_padding":1,"bottom_padding":1,
"background_color":"#FFFFFF","line_color":"#444444","percentile_line_color":"#AAAAFF",
"percentile_fill_color":"#CCCCFF"};
new Sparkline('simple8', data2, opts).draw();
var data3 = [120,130,80,100,90,105,95,60,70,75,70,90,100,110,120,130,150,100,50,80,90,100,110,110];
opts = {"value_lines":[80,120],"top_padding":5,"bottom_padding":0,"fill_between_value_lines":true};
new Sparkline('simple9', data3, opts).draw();
opts ={"value_lines":[90,110],"top_padding":5,"bottom_padding":0,
"fill_between_value_lines":true,
"percentile_lines":[0.25,0.75],
"percentile_line_color":"#FF6666"};
new Sparkline('simple10', data3, opts).draw();
new Sparkline('simple11', data3, opts).draw();
new Sparkline('simple12', data3, opts).draw();
new BarSparkline('bar1',data3).draw();
opts = {'percentile_lines':[0.25,0.75],"fill_between_percentile_lines":true};
new BarSparkline('bar2',data3,opts).draw();
opts = {'percentiile_lines':[0.25,0.75],"fill_between_percentile_lines":true,"extend_markings":false};
new BarSparkline('bar3',data3,opts).draw();
opts = {'percentile_lines':[0.25,0.75],"fill_between_percentile_lines":true,
'padding_between_bars':2,"left_padding":30,"right_padding":30,
'marking_padding':16};
new BarSparkline('bar4',data3,opts).draw();
opts = {'value_lines':[85,115]};
new BarSparkline('bar5',data3,opts).draw();
opts = {'value_lines':[80,120],"fill_between_value_lines":true,"padding_between_bars":0,"bottom_padding":1};
new BarSparkline('bar6',data3,opts).draw();
new BarSparkline('test1',[530],opts).draw();
new Sparkline('test2',[1],opts).draw();
};
</script>
<body onload="setup_sparklines();">
<h1 id="top">Sparklines.js</h1>
<ul>
<li> <a href="#overview">Overview</a> </li>
<li> <a href="#data">Data Formats</a> </li>
<li> <a href="#scaling">Scaling Data</a> </li>
<li> <a href="#lines">Line Sparklines</a> </li>
<li> <a href="#bars">Bar Sparklines</a> </li>
<li> <a href="#custom">Customizing Sparklines</a> </li>
<li> <a href="#download">Download</a> </li>
<li> <a href="#source">Source Code</a> </li>
<li> <a href="#about">About</a> </li>
<li> <a href="#contact">Contact</a> </li>
<li> <a href="#license">License</a> </li>
</ul>
<p id="overview">
Sparklines.js is a simple javascript utility for building sparklines.
It has support for displaying lines at percentile points (for example,
the 0.25 percentile point is the equivalent of Q1, 0.5 is Q2 (the
median), and 0.75 is Q3), and at fixed values in terms of your data
set. (You might want lines at 80,120 in a chart of blood pressure
values, for example, where the data points would be something like
100,50,60,70,100 and so on, to indicate the points outside of normal range.)
</p>
<p>
The sparklines will size themselves appropriately to any size canvas
they are given. Be wary that charts can tell very different stories
depending on how they are sized, and that you are responsible for
giving a reasonable size for the chart to display itself on.
</p>
<p>
Charts can be displayed via line charts, or via bar charts, and allow
for a high degree of customization. In addition, there is support for
demarcating absolute values within the values, and also support for
displaying lines at certain percentiles (for example, you might wish
to display lines at the 25th and 75th percentile). Beyond that, it is
possible to fill in the areas between two percentile or two absolute
value lines, which is a helpful visualization to showing which values
lie between the two points.
</p>
<p>
Other statistical analysis functions will likely be added over time.
Feel free to <a href="#contact">suggest</a> anything that you feel
is missing.
</p>
<p> Oh, and if you're just here for a minute, here are some of my
favorite sparklines from the examples:<p>
<ul>
<li> <a href="#simple7">simple7</a></li>
<li> <a href="#simple8">simple8</a></li>
<li> <a href="#simple11">simple11</a></li>
<li> <a href="#bar4">bar4</a></li>
<li> <a href="#bar6">bar6</a></li>
</ul>
<p>
Sparklines.js is currently piggybacking off of Processing.js to
provide its rendering, but will likely remove that dependency once
the pace of development slows down and it becomes clear which
features will need to be extracted. Processing.js is excellent
for prototyping projects, and is very pleasant to work with,
and the decoupling's justification is reduction of filesize by
removing functionality that is not used by (the fairly simple
demands of) Sparklines.js.
</p>
<hr>
<h2 id="data"> Data Sources </h2>
<p>
A quick note about the format of data sources that are given to the
sparklines. The expected standard data is simple: an array of height
values (absolute values, since they'll be scaled to the size of the
sparkline). However, you might want to pass it a
much more complex data set. You have two options. First, you can
extract the heights form your data set before passing it to the
sparkline, or you can write a function that instructions the sparkline
how to do that itself.
</p>
<p>
Here is a simple example demonstrating how the later method works.
</p>
<pre><code>var a = {'height':100,'name':"A"};
var b = {'height':150','name'="B"};
var data = [a,b];
var extract = function(x) { return x.height; };
var opts = {"parse_height":extract};
new Sparkline("canvas_id", data, opts).draw();</code></pre>
<p>
This should allow sufficient flexibility for using custom data sets
with sparklines.
</p>
<hr>
<h2 id="scaling"> Scaling Data </h2>
<p>
Scaling data is very simple. By default BarSparklines scale from
<em>zero</em> to <em>max</em>, and LineSparklines scale from
<em>min</em> to </em>max</em>. However, you can customize this
behavior.
</p>
<p>
For example, a line sparkline scaling from <em>zero</em> to
<em>max</em>.
</p>
<pre><code>var opts = {'scale_from':0};
var data = [1,2,3,4,5,6];
new Sparkline("canvas_id",data,opts).draw();</code></pre>
<p>
And a bar sparkline scaling from <em>min</em> to
<em>max</em> is easy as well.
</p>
<pre><code>var opts = {'scale_from':undefined};
var data = [1,2,3,4,5,6];
new BarSparkline("canvas_id",data,opts).draw();</code></pre>
<p>And finaly a line sparkline scaling from 50 to 150.</p>
<pre><code>var opts = {'scale_from':50,'scale_to':150};
var data = [1,2,3,4,5,6];
new Sparkline("canvas_id",data,opts).draw();</code></pre>
<p>
This should provide sufficient flexibility to size the
chart's viewport to emphasize the trend in the data that
is particularly interesting to you.
</p>
<hr>
<h2 id="lines""> Line Sparklines </h2>
<p>
The first type of Sparkline is the line sparkline, which represents
data in a simple line format. Be wary that they can tell strikingly
different stories depending on their height and width.
</p>
<hr>
<p> A simple sparkline. </p>
<pre><code>var data = [100,500,300,200,400,500,400,400,100,200];
new Sparkline('simple1', data).draw();</code></pre>
<canvas width="300" height="50" id="simple1" ></canvas>
<hr>
<p> The same sparkline, with excessive padding, in a taller
canvas. </p>
<pre><code>var data = [100,500,300,200,400,500,400,400,100,200];
var opts = {'left_padding':50,'right_padding':50,'top_padding':25, 'bottom_padding':25};
new Sparkline('simple2',data, opts).draw();</code></pre>
<canvas width="300" height="100" id="simple2" ></canvas>
<hr>
<p> The same sparkline, with no padding, drawn in a longer canvas. </p>
<pre><code>var data = [100,500,300,200,400,500,400,400,100,200];
var opts = {'left_padding':0,'right_padding':0,'top_padding':0, 'bottom_padding':0};
new Sparkline('simple3',data, opts).draw();</code></pre>
<canvas width="500" height="50" id="simple3" ></canvas>
<hr>
<p> Let's change up the colors. </p>
<pre><code>var data = [100,500,300,200,400,500,400,400,100,200];
var opts = {"background_color":"#FFEEDD","line_color":"#001122"};
new Sparkline('simple4',data, opts).draw();</code></pre>
<canvas width="500" height="50" id="simple4" ></canvas>
<hr>
<p> Well, it would be kind of neat to see the median (Q2). </p>
<pre><code>var data = [100,500,300,200,400,500,400,400,100,200];
var opts = {"percentile_lines":[0.5]};
new Sparkline('simple5a',data,opts).draw();</code></pre>
<canvas width="500" height="50" id="simple5a" ></canvas>
<hr>
<p> Well, lets remove the line at Q2, and have them at Q1 and Q3 instead. </p>
<pre><code>var data = [100,500,300,200,400,500,400,400,100,200];
var opts = {"percentile_lines":[0.25,0.75]};
new Sparkline('simple5',data,opts).draw();</code></pre>
<canvas width="500" height="50" id="simple5" ></canvas>
<hr>
<p> It would kind of helpful to color the interquartile range. </p>
<pre><code>var data = [100,500,300,200,400,500,400,400,100,200];
var opts = {"percentile_lines":[0.25,0.75],"fill_between_percentile_lines":true};
new Sparkline('simple6',data,opts).draw();</code></pre>
<canvas width="500" height="50" id="simple6" ></canvas>
<hr>
<p>
Lets see that with Q1, Q2, and Q3, with the iterquartile range
colored, and a richer dataset.
</p>
<pre><code>var data2 = [100,200,500,1000,600,900,300,500,800,800,900,1000,50,40,200,100,900,300,400,400,600,700,800,900,700,800,50,100,100];
var opts = {"percentile_lines":[0.25,0.5,0.75],"fill_between_percentile_lines":true};
new Sparkline('simple7',data2,opts).draw();</code></pre>
<canvas width="500" height="50" id="simple7" ></canvas>
<hr>
<p>
Okay, now lets customize the hell out of this, and shrink it down to a
much smaller size that might fit well in a blog entry or merged into a
simple webapplication.
</p>
<pre><code>var data2 = [100,200,500,1000,600,900,300,500,800,800,900,1000,50,40,200,100,900,300,400,400,600,700,800,900,700,800,50,100,100];
var opts = {
"percentile_lines":[0.25,0.5,0.75],"fill_between_percentile_lines":true,
"left_padding":1,"right_padding":1,"top_padding":1,"bottom_padding":1,
"background_color":"#FFFFFF","line_color":"#444444","percentile_line_color":"#AAAAFF",
"percentile_fill_color":"#CCCCFF"
};
new Sparkline('simple8', data2, opts).draw();</code></pre>
<canvas width="100" height="25" id="simple8" ></canvas>
<hr>
<p>
But, you might not want to draw lines at the quartiles (or at
whatever arbitrary percentile of entries), you might want to draw
lines at certain values instead. For example, you might want to
indicate the normal range of blood pressure in a patient.
</p>
<pre><code>var data3 =
[120,130,80,100,90,105,95,60,70,75,70,90,100,110,120,130,150,100,50,80,90,100,110,110];
var opts = {"value_lines":[80,120],"top_padding":5,"bottom_padding":0,"fill_between_value_lines":true};
new Sparkline('simple9', data3, opts).draw();</code></pre>
<canvas width="200" height="50" id="simple9" ></canvas>
<hr>
<p>
For fun, lets add some percentile lines into the mix as well.
</p>
<pre><code>var data3 =
[120,130,80,100,90,105,95,60,70,75,70,90,100,110,120,130,150,100,50,80,90,100,110,110];
var opts ={"value_lines":[90,110],"top_padding":5,
"bottom_padding":0,"fill_between_value_lines":true,
"percentile_lines":[0.25,0.75],"percentile_line_color":"#FF6666"
};
new Sparkline('simple10', data3, opts).draw();
new Sparkline('simple10', data3, opts).draw();</code></pre>
<canvas width="500" height="200" id="simple10" ></canvas>
<p> Lets see that at a few different sizes. The one above it 500px by
200px. Lets try it at 300px by 100px.
</p>
<canvas width="300" height="100" id="simple11" ></canvas>
<p>
And maybe at 100px by 50px. (Although, we'd really want to reduce
the padding, since its a bit too much at this small size.)
</p>
<canvas width="100" height="50" id="simple12" ></canvas>
<hr>
<h2 id="bars"> Bar Sparklines </h2>
<p>
Bar sparklines can be clearer about conveying some
types of information than line sparklines. They are
more explicit about exact quatities, but are often
less effective at exposing trends within the data
they are graphing.
</p>
<hr>
<p> Lets start with the simplest of bar sparklines. </p>
<pre><code>var data3 =
[120,130,80,100,90,105,95,60,70,75,70,90,100,110,120,130,150,100,50,80,90,100,110,110];
new Sparkline('bar11', data3).draw();</code></pre>
<canvas width="500" height="200" id="bar1" ></canvas>
<hr>
<p> And add a nice filled region between Q1 and Q3. </p>
<pre><code>var data3 = [120,130,80,100,90,105,95,60,70,75,70,90,100,110,120,130,150,100,50,80,90,100,110,110];
var opts = {'percentile_lines':[0.25,0.75],"fill_between_percentile_lines":true};
new Sparkline('bar2', data3).draw();</code></pre>
<canvas width="500" height="200" id="bar2" ></canvas>
<hr>
<p> Notice that the percentile lines and fill between them extend
beyond the bars. Personally, I think that looks better, but you may
want to disable that. </p>
<pre><code>var data3 = [120,130,80,100,90,105,95,60,70,75,70,90,100,110,120,130,150,100,50,80,90,100,110,110];
var opts ={'percentile_lines':[0.25,0.75],"fill_between_percentile_lines":true, "extend_markings":false};
new Sparkline('bar3', data3).draw();</code></pre>
<canvas width="500" height="200" id="bar3" ></canvas>
<hr>
<p>
Maybe we want less space between lines, and some extra padding
from the sides, and while we're at it lets make that extra padding for
the percentile lines and filling a bit wider as well.
</p>
<pre><code>var data3 =[120,130,80,100,90,105,95,60,70,75,70,90,100,110,120,130,150,100,50,80,90,100,110,110];
var opts = {'percentile_lines':[0.25,0.75],"fill_between_percentile_lines":true,
'padding_between_bars':2,"left_padding":30,"right_padding":30,
'marking_padding':16};
new Sparkline('bar4', data3).draw();</code></pre>
</code></pre>
<canvas width="500" height="200" id="bar4" ></canvas>
<hr>
<p>
Our old friends, value lines, are still available to draw lines at
values instead of at percentiles points.
</p>
<pre><code>var data3 =[120,130,80,100,90,105,95,60,70,75,70,90,100,110,120,130,150,100,50,80,90,100,110,110];
var opts = {'value_lines':[85,115]};
new BarSparkline('bar5',data3,opts).draw();</code></pre>
<canvas width="400" height="150" id="bar5" ></canvas>
<hr>
<p>
And we can fill between the value lines too. And take away the spacing
between bars, if we feel like it.
</p>
<pre><code>var data3 =[120,130,80,100,90,105,95,60,70,75,70,90,100,110,120,130,150,100,50,80,90,100,110,110];
var opts = {'value_lines':[80,120],"fill_between_value_lines":true,"padding_between_bars":0,"bottom_padding":3};
new BarSparkline('bar6',data3,opts).draw();</code></pre>
<canvas width="500" height="100" id="bar6"></canvas>
<hr>
<h2 id="custom"> Customizing Sparklines </h2>
<p>
The simplest way to customize a sparkline is to pass in a
dictionary of modified attributes. This is the technique
that is used in all the examples on this page. It looks
something like this:
</p>
<pre><code>var data = [100,500,300,200,400,500,400,400,100,200];
var opts = {'left_padding':50,'right_padding':50,'top_padding':25, 'bottom_padding':25};
new Sparkline('simple2',data, opts).draw();</code></pre>
<p>
If you end up doing a large number of similar sparklines, you
may begin to feel that passing the arguments in each time is
getting a bit redundant. In such a case, you can subclass the
<em>Sparkline</em> or <em>BarSparkline</em> classes to
look the way you prefer. For example:
</p>
<pre><code>var MySparkline = function(id,data,mixins) {
this.background_color = "rgba(255,255,255,1);";
this.line_color = "rga(100,100,100,.7);";
this.top_padding = 3;
this.bottom_padding = 3;
this.left_padding = 6;
this.right_padding = 6;
this.init(id,data,mixins);
}
MySparkline.prototype = new Sparkline();
new MySparkline("canvas_a",[1,2,3,4]);</code></pre>
<p>
If you wanted to customize <em>BarSparkline</em> instead, you
would change the line
<code>MySparkline.prototype = new Sparkline();</code>
to
<code>MySparkline.prototype = new BarSparkline();</code>.
</p>
<hr>
<h2 id="tests"> Tests </h2>
<p>
This section contains some visual tests for unusual
situations (zero elements, one element, etc).
</p>
<canvas width="500" height="100" id="test1"></canvas>
<canvas width="500" height="100" id="test2"></canvas>
<hr>
<h2 id="download"> Download </h2>
<p>
Right click <a href="sparklines.min.js">here to download the minified
sparklines.min.js file</a>.
</p>
<p>
Its also very easy to build your own deploy copy to have the most
recent version. Simply check out the current project from Git and
from the main project directory type:
</p>
<pre><code>./scripts/deploy.sh</code></pre>
<p>
and a deploy copy will be created named <code>sparklines.min.js</code>
which contains all necessary code merged into one file.
</p>
<hr>
<h2 id="source"> Source </h2>
<ul>
<li> <a href="sparklines.js">sparklines.js</a> </li>
<li> <a href="http://ejohn.org/blog/processingjs/">Processing.js</a> </li>
</ul>
<p>
There is a public repository available at <a
href="http://github.com/lethain/sparklines.js/tree/master">github</a>
for those interested in the most recent releases or contributing.
</p>
<hr>
<h2 id="about"> About </h2>
<p>
This project is inspired by a number of sources, and almost all of
those sources have appeared in my life as the result of readings and
research direct my way by <a href="http://densityofspace.com/">J.D. Hollis</a>. Beyond that,
J.D. has also provided feedback about the project, along with
a critical eye.
</p>
<p>
There is a huge amount of thinking about informational design
going on at the moment, and this project might be described as
a small attempt to make a small piece of that information
easier to take advantage of.
</p>
<hr>
<h2 id="contact"> Contact </h2>
<p>
Feel free to send requests, comments and complaints about this project
to <code>lethain@gmail.com</code>.
</p>
<hr>
<h2 id="license"> License </h2>
<p> This project has been released under the <a rel="license" href="http://www.opensource.org/licenses/mit-license.php">MIT License</a> by <a href="http://lethain.com">Will Larson</a></p>
</body> </html>