Search code examples
vega-lite

Conditional axis in vega-lite


I want to represent two rows in the axis of a graph. The two rows represent month and year respectively.enter image description here

For the above plot , we use a conditional statement to display year only if the current month is jan, but this logic works well in this plot. But this fails if the plot is rendering only say, Feb, Apr, Jun etc, then the year will not be displayed at all. I wanted a generic solution to display year only on the first valid occurance be it Jan or Feb etc.

The above can be found in vegalite editor


Solution

  • I had no luck with Temporal labelExpr using H (hour), M (minutes) etc In this example I set the date to either 1 or 2 and use that logic in the labelExpr.

    Let me know if this could be a possible solution for you. I have added lots of dynamic features to show that in action too.

    Also added a trick I like to use so tooltip works everywhere. I set the chart to Area instead of line..

    {
      "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
      "description": "Line chart with conditional axis ticks, labels, and grid.",
      "data": {"url": "data/stocks.csv"},
      "transform": [
        {"filter": "datum.symbol==='GOOG'"},
        {"filter": {"field": "date", "timeUnit": "year", "range": [2006, 2007]}},
        {
          "filter": {
            "field": "date",
            "timeUnit": "yearmonthdate",
            "gte": "2006-03-01"
          }
        },
        {"calculate": "timeFormat(datum.date, '%y%m')", "as": "YM"},
        {"calculate": "timeFormat(datum.date, '%m')", "as": "M"},
        {
          "joinaggregate": [{"op": "min", "field": "date", "as": "firstDate"}],
          "groupby": ["symbol"]
        },
        {
          "calculate": "datetime(timeFormat(datum.firstDate, '%y%m') == datum.YM || datum.M == '01' ? timeFormat(datum.date, '%Y-%m-' + '01') : timeFormat(datum.date, '%Y-%m-' + '02'))",
          "as": "formattedDate"
        }
      ],
      "width": 700,
      "mark": {
        "type": "area",
        "color": "transparent",
        "line": {"color": "#0564C8"}
      },
      "encoding": {
        "tooltip": {
          "field": "formattedDate",
          "type": "temporal",
          "timeUnit": "utcyearmonth"
        },
        "x": {
          "field": "formattedDate",
          "type": "ordinal",
          "timeUnit": "utcyearmonthdate",
          "bandPosition": 0,
          "axis": {
            "title": "",
            "tickCount": 12,
            "format": "%Y-%m-%d",
            "labelAlign": "left",
            "labelExpr": "[timeFormat(datum.value, '%b'), timeFormat(datum.value, '%d') == '01' ? timeFormat(datum.value, '%Y') : '']",
            "labelOffset": 4,
            "grid": true,
            "labelPadding": {
              "expr": "timeFormat(datum.value, '%d') == '01' ? -26:-11"
            },
            "tickSize": {"expr": "timeFormat(datum.value, '%d') == '01' ? 30:15"},
            "gridDash": {
              "expr": "timeFormat(datum.value, '%d') == '01' ? []:[2,2]"
            },
            "tickDash": {
              "expr": "timeFormat(datum.value, '%d') == '01' ? []:[2,2]"
            },
            "tickColor": {
              "expr": "timeFormat(datum.value, '%d') == '01' ? '#0564C8':'silver'"
            },
            "gridColor": {
              "expr": "timeFormat(datum.value, '%d') == '01' ? '#0564C8':'silver'"
            }
          }
        },
        "y": {"field": "price", "type": "quantitative", "axis": {"grid": false}}
      },
      "config": {"axis": {"domainColor": "#ddd", "tickColor": "#ddd"}}
    }
    

    enter image description here