Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin: Colored ribbon #537

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
128 changes: 128 additions & 0 deletions src/extras/ribbon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* @license
* Copyright 2015 Petr Shevtsov ([email protected])
* MIT-licensed (http://opensource.org/licenses/MIT)
*
* Ribbon is a horizontal band of colors that runs through the chart. It can be useful
* to visualize categorical variables (http://en.wikipedia.org/wiki/Categorical_variable)
* that change over time (along the x-axis). For example multiple states of economy
* like "bust", "recession", "recovery", "boom" can be encoded as [0, 1, 2, 3]
* respectively (or normalized as [0, 0.33, 0.66, 1]) and assigned colors
* ["red","orange","green","purple"].
*
* Plugin options:
*
* `data`: Array of numeric values in the range from 0 to 1. Ribbon data array
* must be of same length as number of rows of Dygraph raw data table.
* Each of the values (0-1) scales to a position in the palette array scale
* (see palette argument below). For example, if palette is defined as
* ["transparent", "#ef2929", "#8ae234"], then 0 is the leftmost position ("#ef2929")
* on the palette scale, 1 is the rightmost position ("#8ae234") and 0.5 is the middle
* position ("#ef2929").
*
* `parser`: Function (function (data, dygraph)) returning the array of numeric values.
* Function arguments: raw data, dygraph instance. Provide it if the ribbon data,
* i.e. encodings are part of the dygraph raw data table rather than supplied separately
* through ribbon data argument.
*
* `options`: Object with the following properties:
*
* - `palette`: array of hexadecimal color codes.
* Default: ["transparent", "#ef2929", "#8ae234"].
* Pick colors from e.g. http://www.w3schools.com/tags/ref_colorpicker.asp
*
* - `top`: vertical position of the top edge of the ribbon relative to chart height.
* Value in the range from 0 (bottom edge of the chart) to 1 (top edge of the chart).
* E.g. 0.5 places the top edge of the ribbon at the 50% height of the chart.
*
* - `bottom`: vertical position of the bottom edge of the ribbon relative to chart
* height. See top.
*/

/*global Dygraph:false */

Dygraph.Plugins.Ribbon = (function() {
"use strict";

var ribbon = function(options) {
options = options || {};

this.ribbonData_ = options.data || null;
this.ribbonDataParser_ = options.parser || null;
this.ribbonOptions_ = options.options || {};

var defaultOptions = {
palette: [
"transparent",
"#ef2929",
"#8ae234"
],
top: 1,
bottom: 0
};

function update(self, o) {
if (typeof(o) != 'undefined' && o !== null) {
for (var k in o) {
if (o.hasOwnProperty(k)) {
self[k] = o[k];
}
}
}
return self;
}

this.ribbonOptions_ = update(defaultOptions, this.ribbonOptions_);
this.ribbonOptions_.top = Math.min(this.ribbonOptions_.top, 1);
this.ribbonOptions_.top = Math.max(this.ribbonOptions_.top, 0);
this.ribbonOptions_.bottom = Math.min(this.ribbonOptions_.bottom, 1);
this.ribbonOptions_.bottom = Math.max(this.ribbonOptions_.bottom, 0);

this.ribbonOptions_.top = Math.max(this.ribbonOptions_.top, this.ribbonOptions_.bottom);
this.ribbonOptions_.bottom = Math.min(this.ribbonOptions_.top, this.ribbonOptions_.bottom);
};

ribbon.prototype.toString = function() {
return "Ribbon Plugin";
};

ribbon.prototype.activate = function(g) {
if (this.ribbonData_ !== null || this.ribbonDataParser_ !== null) {
return {
willDrawChart: this.willDrawChart
};
}
};

ribbon.prototype.decodeColor = function(val) {
var max = Math.max.apply(null, this.ribbonData_);
val = val / max;
var idx = Math.ceil((this.ribbonOptions_.palette.length - 1) * val);

return this.ribbonOptions_.palette[idx];
};

ribbon.prototype.willDrawChart = function(e) {
var g = e.dygraph;
var layout = g.layout_;
var points = layout.points[0];
var area = layout.getPlotArea();
if (this.ribbonData_ === null) {
this.ribbonData_ = this.ribbonDataParser_(g.rawData_, g);
}
for (var i = 0; i < points.length; i++) {
var point = points[i];
var nextpoint = points[i + 1];

var left = g.toDomCoords(point.xval, 0)[0];
var right = (nextpoint === undefined) ? g.canvas_.width : g.toDomCoords(nextpoint.xval, 0)[0];
var color = this.decodeColor(this.ribbonData_[point.idx]);
var y = area.h * (1 - this.ribbonOptions_.top) + area.y;
var h = (area.h - area.h * this.ribbonOptions_.bottom) - y;
g.hidden_ctx_.fillStyle = color;
g.hidden_ctx_.fillRect(left, y, right - left, h);
}
};

return ribbon;
})();
143 changes: 143 additions & 0 deletions tests/ribbon.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<!DOCTYPE html>
<html>
<head>
<title>Colored Ribbon demo</title>
<script type="text/javascript" src="../dist/dygraph.js"></script>
<script type="text/javascript" src="../src/extras/ribbon.js"></script>
</head>
<body>
<h1>Colored Ribbon demo</h1>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pshevtsov , following can be included in the <div> of the ribbon.html to document the use, in addition to the source code of the examples:

Description:

Ribbon is a horizontal band of colors that runs through the chart. It can useful to visualize categorical variables (http://en.wikipedia.org/wiki/Categorical_variable) that change over time (along the x-axis). For example multiple states of economy like "bust","recession", "recovery", "boom" can be encoded as [0, 1, 2, 3] respectively (or normalized as [0, 0.33, 0.66, 1]) and assigned colors ["red","orange","green","purple"].

Arguments:

data:
Array of numeric values in the range from 0 to 1. Ribbon data array must be of same length as number of rows of Dygraph raw data table. Each of the values (0-1) scales to a position in the palette array scale (see palette argument below). For example, if palette is defined as ["transparent", "#ef2929", "#8ae234"], then 0 is the leftmost position ("#ef2929") on the palette scale, 1 is the rightmost position ("#8ae234") and 0.5 is the middle position ("#ef2929")

parser:
Function (function (data, dygraph)) returning the array of numeric values. Function arguments: raw data, dygraph instance. Provide it if the ribbon data, i.e. encodings are part of the dygraph raw data table rather than supplied separately through ribbon data argument. See example 2.

options:
Object with the following properties:

  • palette:
    array of hexadecimal color codes. Default: ["transparent", "#ef2929", "#8ae234"]. Pick colors from e.g. http://www.w3schools.com/tags/ref_colorpicker.asp
  • top:
    vertical position of the top edge of the ribbon relative to chart height. Value in the range from 0 (bottom edge of the chart) to 1 (top edge of the chart). E.g. 0.5 places the top edge of the ribbon at the 50% height of the chart.
  • bottom:
    vertical position of the bottom edge of the ribbon relative to chart height. See top.

<h2>Colored Ribbon with default options</h2>
<div id="div_g1" style="width:600px; height:300px;"></div>

<h2>Colored Ribbon with Encoded colors in data column</h2>
<div id="div_g2" style="width:600px; height:300px;"></div>

<h2>Colored Ribbon with customized height</h2>
<div id="div_g3" style="width:600px; height:300px;"></div>

<h2>Colored Ribbon with customized position</h2>
<div id="div_g4" style="width:600px; height:300px;"></div>

<h2>Colored Ribbon with customized colors</h2>
<div id="div_g5" style="width:600px; height:300px;"></div>

<script type="text/javascript">
function data() {
return "Date,High,Low\n" +
"20070101,62,39\n" +
"20070102,62,44\n" +
"20070103,62,42\n" +
"20070104,57,45\n" +
"20070105,54,44\n" +
"20070106,55,36\n" +
"20070107,62,45\n" +
"20070108,66,48\n" +
"20070109,63,39\n" +
"20070110,57,37\n";
}

var ribbon = new Dygraph.Plugins.Ribbon({
data: [0, 0.5, 0.5, 1, 1, 1, 0, 0, 0, 0.5]
});

var g1 = new Dygraph(
document.getElementById("div_g1"),
data,
{
plugins: [ribbon]
}
);

function data_color() {
return "Date,High,Low,Color\n" +
"20070101,62,39,0\n" +
"20070102,62,44,0.5\n" +
"20070103,62,42,0.5\n" +
"20070104,57,45,1\n" +
"20070105,54,44,1\n" +
"20070106,55,36,1\n" +
"20070107,62,45,0\n" +
"20070108,66,48,0\n" +
"20070109,63,39,0\n" +
"20070110,57,37,0.5\n";
}

ribbon = new Dygraph.Plugins.Ribbon({
parser: function(data) {
var colorIdx = 3;
var colors = [];
for (var i = 0; i < data.length; i++) {
var row = data[i];
if (row[colorIdx]) {
colors.push(row[colorIdx]);
} else {
colors.push(0);
}
}
return colors;
}
});

var g2 = new Dygraph(
document.getElementById("div_g2"),
data_color,
{
visibility: [true, true, false], // Hide colors column
plugins: [ribbon]
}
);

ribbon = new Dygraph.Plugins.Ribbon({
data: [0, 0.5, 0.5, 1, 1, 1, 0, 0, 0, 0.5],
options: {
top: 0.75
}
});

var g3 = new Dygraph(
document.getElementById("div_g3"),
data,
{
plugins: [ribbon]
}
);

ribbon = new Dygraph.Plugins.Ribbon({
data: [0, 0.5, 0.5, 1, 1, 1, 0, 0, 0, 0.5],
options: {
top: 0.75,
bottom: 0.25
}
});

var g4 = new Dygraph(
document.getElementById("div_g4"),
data,
{
plugins: [ribbon]
}
);

ribbon = new Dygraph.Plugins.Ribbon({
data: [0, 0.5, 0.5, 1, 1, 1, 0, 0, 0, 0.5],
options: {
palette: [
"#ad7fa8",
"#75507b",
"#5c3566"
]
}
});

var g5 = new Dygraph(
document.getElementById("div_g5"),
data,
{
plugins: [ribbon]
}
);
</script>
</body>
</html>