A graphical toolkit for visualization
Protovis
Overview
Examples
Documentation
Download
Index
« Previous / Next »

Horizon Graphs

View full screen.

Horizon graphs increase data density while preserving resolution. Here we show national unemployment rates as a percentage of the labor force from 2000 to 2010, courtesy of the U.S. Bureau of Labor Statistics. Negative values represent below-average employment and are either "mirrored" or "offset" to share the same space as positive values, which represent above-average employment.

While horizon graphs may require learning, they have been found to be more effective than standard line and area plots when chart sizes are small. For more, see "Sizing the Horizon: The Effects of Chart Size and Layering on the Graphical Perception of Time Series Visualizations" by Heer et al., CHI 2009.

Next: Candlestick Charts

Source

<html>
  <head>
    <title>Horizon Graph</title>
    <script type="text/javascript" src="../protovis-r3.2.js"></script>
    <script type="text/javascript" src="../jquery-1.4.2.min.js"></script>
    <script type="text/javascript" src="../jquery-ui-1.8rc3.custom.min.js"></script>
    <script type="text/javascript" src="unemployment.js"></script>
    <link type="text/css" rel="stylesheet" href="ex.css"/>
    <link type="text/css" href="../ui-lightness/jquery-ui-1.8rc3.custom.css" rel="stylesheet"/>
    <style type="text/css">

#fig {
  width: 500px;
  height: 115px;
}

#slider {
  width: 120px;
  display: inline-block;
  margin-left: 10px;
  margin-right: 10px;
}

#bands {
  display: inline-block;
  width: 10px;
  text-align: right;
}

.ui-slider {
  font-size: 10px;
  width: 300px;
  margin-top: 5px;
}

.ui-state-focus {
  outline: none;
}

    </style>
  </head>
  <body><div id="center"><div id="fig">
    <div style="width:500px;">
      <b>Bands:</b><span id="slider"></span><span id="bands">2</span>
      <span style="float:right;"><b>Negative:</b>
      <input type="radio" id="mirror" name="mode" value="mirror" checked/><label
      for="mirror">mirror</label>
      <input type="radio" id="offset" name="mode" value="offset"/><label
      for="offset">offset</label></span>
    </div>
    <script type="text/javascript+protovis">

var data = pv.nest(all)
    .key(function(d) d.series)
    .entries()
    .filter(function(d) d.key == 0)[0].values;

/* Offset so that positive is above-average and negative is below-average. */
var avg = pv.mean(data, function(d) d.rate);
data.map(function(d) d.rate -= avg);

var w = 500,
    h = 84,
    bands = 2,
    mode = "mirror",
    fx = function(d) d.date,
    fy = function(d) d.rate,
    m = Math.max(pv.max(data, fy), -pv.min(data, fy)),
    x = pv.Scale.linear(data, fx).range(0, w).by(fx),
    y = pv.Scale.linear(-m, m).range(-h, h).by(fy);

var vis = new pv.Panel()
    .top(10)
    .width(w)
    .height(h);

vis.add(pv.Layout.Horizon)
    .bands(function() bands)
    .mode(function() mode)
    .height(function() h / bands)
    .bottom(0)
  .band.add(pv.Area)
    .data(data)
    .left(x)
    .height(y);

vis.render();

$(slider).slider({
    min: 1, max: 5, value: 2, slide: function(e, ui) {
      $("#bands").html(bands = ui.value);
      vis.render();
    }
});

$([mirror, offset]).change(function() {
  mode = this.value;
  vis.render();
});

    </script>
  </div></div></body>
</html>

Data

Due to size, the data file is omitted from this example. See unemployment.js.
Copyright 2010 Stanford Visualization Group