Saturday, December 1, 2012

The New and Better Way to Specify Series and Axis Options

TL;DR: Put series inside the series option. If you want to put a series on the second y-axis, then inside that series specify axis : 'y2'. You can say that a series belongs on the first y-axis with axis : 'y', but that's also the default. This only applies inside the series option. Also, per-series options can also be specified in an axis, so it applies to every series on that axis.

In a recent post, I described the bizarre behavior required to make multiple axes work. Fortunately, because of the experience writing the post, I submitted a series of patches that rewrote the internals for handling options processing, and also improve the API.

Specifying a Series

Traditionally, per-series options were specified on the top-level of the options dictionary, like so:

{
  pointSize : 5,
  legend : 'always',
  T : {
    pointSize : 6
  }
}

This behavior is now discouraged. Instead you should put your per-series options in the top-level series option:

{
  pointSize : 5,
  legend : 'always',
  series : {
    T : {
      pointSize : 6
    }
  }
}

Now, if you want to deal with multiple axes, pay close attention, because things have changed.

It used to be that if you wanted to specify that a series was on the second y-axis, you did this:

T : {
  axis : { }
}

And then if you wanted to put another series on the second y-axis, you would reference the first series, like so:

S : {
  axis : 'T'
}

This behavior still works, until you put it inside the series option.

So let's say you had 

{
  pointSize : 5,
  legend : 'always',
  T : {
    axis : { }
  },
  S : {
    axis : 'T'
  }
}

and then you moved it into the series option:

{
  pointSize : 5,
  legend : 'always',
  series : {
    T : {
      axis : { }
    },
    S : {
      axis : 'T'
    }
  }
}
... the graph would fail to render, with the exception
"Using objects for axis specification is not supported inside the 'series' option."
That's because we did per-axis specifications right this time. All you have to do is directly specify the axis you want a series to appear on, like so:

{
  pointSize : 5,
  legend : 'always',
  series : {
    T : {
     axis : 'y2'
    },
    S : {
      axis : 'y2'
    }
  }
}


No more weird {}, and no more referencing other series.


Remember, behavior inside the series option is different from outside. The outside-series options have been effectively deprecated. However, all the old behavior has been preserved. so your old graphs will still work. It's different from the old way, but it's easier to use.

Specifying Per-series options on an axis

As I mentioned at the top, options parsing has been rewritten. This allowed for a nice small change, which is the rule in which options are found:
When searching for a per-series option, first see if it's specified in the series. If it's not there, see if there's an option for it on the axis. If it's not there look for a user-specified option, and then finally rely on a default value.
This implies the new rule for finding per-axis options:
When searching for a per-axis option, first see if it's specified in the axis. If it's not there, look for a user-specified option, and then finally, rely on a default value.
Make sense? Let's look at a demo:

{
  drawPoints : true,
  pointSize : 5,
  legend : 'always',
  series : {
    T : {
      axis : 'y2',
      pointSize : 10
    },
    S : {
      axis : 'y2'
    }
  },
  axes : {
    'y2' : {
      drawPointCallback: Dygraph.Circles.PENTAGON
    }
  }
});

In this case,  notice that series T and S are both on the y2 axis. The point size is overridden for T by being specified directly in T. However, both S and T have pentagons for points because of the drawPointCallback specification in axes.

2 comments:

  1. Dygraph is really a great form of visualization for time series. Cutting edge stuff. Thanks for making it happen.

    ReplyDelete
  2. Awesome !!! Thanks for this wonderful framework !

    ReplyDelete