Search code examples
plottime-seriesvega-litevega

Vega-lite timeseries chart that overlays current, last year and average in a cyclical way


I have a simple timeseries with a price over time: [{t:"2023-01-31", price: 100}, ...].

With vega-lite.js I can easily plot this as a line.

enter image description here

The script for that is here.

But, I'd like to show such data by month with 3 lines.

  • One line shows the data of last year.
  • One line showing last year
  • One with the average price of the last 5 years.

Something like this:

enter image description here

This allows a more compact and intuitive reading in some cases. The months wrap around, so the x-axis always has the same size. Comparing the current, with past situations is easier, because the lines are overlaid.

I have tried to

  • create additional columns with transform, to distinguish those three
  • use {"timeUnit": "month"}, {"aggregate": "mean"} options to reorganize my axis ... but without success.

What is the right way to go about this in an elegant Vega-way?


Solution

  • Here you go.

    enter image description here

    {
      "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
      "width": 600,
      "encoding": {
        "x": {
          "field": "month",
          "axis": {"labelExpr": "monthAbbrevFormat(datum.value)", "labelAngle": 0}
        },
        "y": {"field": "price", "type": "quantitative"},
        "tooltip": [
          {"field": "t", "type": "temporal", "title": "t"},
          {"field": "p", "type": "quantitative", "title": "price"}
        ],
        "color": {
          "field": "null",
          "title": "series",
          "scale": {
            "domain": ["2021", "2022", "Ave 2016-2021"],
            "range": ["red", "orange", "blueviolet"]
          },
          "type": "ordinal"
        }
      },
      "layer": [
        {
          "mark": {"type": "line", "stroke": "red"},
          "transform": [{"filter": "datum.year ==2021"}]
        },
        {
          "mark": {"type": "line", "stroke": "orange"},
          "transform": [{"filter": "datum.year ==2020"}]
        },
        {
          "mark": {"type": "line", "stroke": "blueviolet", "interpolate": "basis"},
          "transform": [
            {"filter": "datum.year <= 2021 && datum.year >= 2016"},
            {
              "aggregate": [{"op": "mean", "field": "price", "as": "price"}],
              "groupby": ["month"]
            }
          ]
        }
      ],
      "data": {
        "values": [
          {"t": "2021-06-01T00:00:00", "price": 500},
          {"t": "2012-12-01T00:00:00", "price": 130},
          {"t": "2012-02-01T00:00:00", "price": 153},
          {"t": "2020-05-01T00:00:00", "price": 400},
          {"t": "2015-08-01T00:00:00", "price": 170},
          {"t": "2015-01-01T00:00:00", "price": 140},
          {"t": "2014-11-01T00:00:00", "price": 130},
          {"t": "2009-08-01T00:00:00", "price": 110},
          {"t": "2012-03-01T00:00:00", "price": 130},
          {"t": "2019-11-01T00:00:00", "price": 400},
          {"t": "2017-09-01T00:00:00", "price": 180},
          {"t": "2009-10-01T00:00:00", "price": 220},
          {"t": "2014-07-01T00:00:00", "price": 146},
          {"t": "2015-03-01T00:00:00", "price": 160},
          {"t": "2012-06-01T00:00:00", "price": 160},
          {"t": "2018-05-01T00:00:00", "price": 220},
          {"t": "2016-11-01T00:00:00", "price": 195},
          {"t": "2019-10-01T00:00:00", "price": 400},
          {"t": "2011-02-01T00:00:00", "price": 130},
          {"t": "2021-03-01T00:00:00", "price": 500},
          {"t": "2019-02-01T00:00:00", "price": 317.5},
          {"t": "2012-09-01T00:00:00", "price": 140},
          {"t": "2018-08-01T00:00:00", "price": 250},
          {"t": "2015-11-01T00:00:00", "price": 186},
          {"t": "2010-05-01T00:00:00", "price": 120},
          {"t": "2010-02-01T00:00:00", "price": 130},
          {"t": "2010-09-01T00:00:00", "price": 150},
          {"t": "2017-10-01T00:00:00", "price": 180},
          {"t": "2018-01-01T00:00:00", "price": 200},
          {"t": "2020-02-01T00:00:00", "price": 400},
          {"t": "2020-07-01T00:00:00", "price": 375},
          {"t": "2018-06-01T00:00:00", "price": 232.5},
          {"t": "2019-04-01T00:00:00", "price": 322.5},
          {"t": "2014-02-01T00:00:00", "price": 130},
          {"t": "2016-01-01T00:00:00", "price": 143},
          {"t": "2019-07-01T00:00:00", "price": 400},
          {"t": "2014-12-01T00:00:00", "price": 135},
          {"t": "2009-05-01T00:00:00", "price": 110},
          {"t": "2020-03-01T00:00:00", "price": 330},
          {"t": "2019-09-01T00:00:00", "price": 400},
          {"t": "2013-02-01T00:00:00", "price": 135},
          {"t": "2009-12-01T00:00:00", "price": 150},
          {"t": "2017-07-01T00:00:00", "price": 195},
          {"t": "2020-10-01T00:00:00", "price": 400},
          {"t": "2016-10-01T00:00:00", "price": 205},
          {"t": "2015-07-01T00:00:00", "price": 180},
          {"t": "2018-03-01T00:00:00", "price": 200},
          {"t": "2012-05-01T00:00:00", "price": 165},
          {"t": "2013-10-01T00:00:00", "price": 135},
          {"t": "2012-10-01T00:00:00", "price": 130},
          {"t": "2016-07-01T00:00:00", "price": 150},
          {"t": "2011-08-01T00:00:00", "price": 200},
          {"t": "2019-03-01T00:00:00", "price": 320},
          {"t": "2017-08-01T00:00:00", "price": 180},
          {"t": "2013-06-01T00:00:00", "price": 135},
          {"t": "2015-05-01T00:00:00", "price": 153},
          {"t": "2020-09-01T00:00:00", "price": 460},
          {"t": "2014-06-01T00:00:00", "price": 140},
          {"t": "2011-06-01T00:00:00", "price": 145},
          {"t": "2018-12-01T00:00:00", "price": 300},
          {"t": "2021-02-01T00:00:00", "price": 450},
          {"t": "2017-03-01T00:00:00", "price": 210},
          {"t": "2015-04-01T00:00:00", "price": 190}
        ]
      },
      "transform": [
        {"calculate": "year(datum.t)", "as": "year"},
        {"calculate": "month(datum.t)", "as": "month"}
      ]
    }