Search code examples
jsonchartsvisualizationvega

How to change width of bar chart by slider in Vega


I have a Vega chart for which I need to change bar width of rectangle based on triangle slider.

The code :

{
  "$schema": "https://vega.github.io/schema/vega/v4.json",
  "width": 400,
  "height": 50,
  "padding": 5,
  "data": [
    {
      "name": "table",
      "values": [

        {"x": "Download data (.csv)", "c": "case1", "y": 20},
        {"x": "Download data (.csv)", "c": "case2", "y": 20},
        {"x": "Download data (.csv)", "c": "case3", "y": 20},
        {"x": "Download data (.csv)", "c": "case4", "y": 20},
        {"x": "Download data (.csv)", "c": "case5", "y":20}
      ]
    },
    {
      "name": "filtered-table",
      "source": "table",
      "transform": [{"type": "stack", "groupby": ["x"], "field": "y"}]
    }
  ],
   "signals": [
    {
      "name": "dragging",
      "value": false,
      "on": [
        {"events": "@handle:mousedown", "update": "true"},
        {"events": "window:mouseup", "update": "false"}
      ]
    },
    {
      "name": "handleYear",
      "value": 20,
      "on": [
        {
          "events": "[@handle:mousedown, window:mouseup] > window:mousemove!",
          "update": "invert('x', clamp(x(), 0, width))"
        }
      ]
    },
    {"name": "currentYear", "update": "clamp(handleYear, 0, 40)"}
    ],
  "scales": [
    {
      "name": "y",
      "type": "band",
      "range": "height",
      "domain": {"data": "filtered-table", "field": "x"}
    },
    {
      "name": "x",
      "type": "linear",
      "range": "width",
      "domain": {"data": "filtered-table", "field": "y1"}
    },
    {
      "name": "color",
      "type": "ordinal",
      "range": ["darkblue", "orange", "lightgrey", "red", "green"],
      "domain": {"data": "filtered-table", "field": "c"}
    }
  ],
  "axes": [{"orient": "left", "scale": "y", "ticks": false, "labelPadding": 5},
  {"orient": "bottom", "scale": "x", "ticks": false, "labelPadding": 5}],
  "marks": [
    {
      "type": "rect",
      "from": {"data": "filtered-table"},
      "encode": {
        "enter": {
          "y": {"scale": "y", "field": "x"},
          "height": {"scale": "y", "band": 1, "offset": -1},
          "x": {"scale": "x", "field": "y0"},
          "x2": {"scale": "x", "field": "y1"},
          "fill": {"scale": "color", "field": "c"}
        },
        "update": {"fillOpacity": {"value": 1}},
        "hover": {"fillOpacity": {"value": 0.5}}
      }
    },

    {
      "name": "handle",
      "type": "symbol",
      "encode": {
        "enter": {
          "y": {"scale": "x", "value":0, "offset": -7},
          "shape": {"value": "triangle-down"},
          "size": {"value": 400},
          "stroke": {"value": "#000"},
          "strokeWidth": {"value": 0.5}
        },
        "update": {
          "x": {"scale": "x", "signal": "currentYear"},
          "fill": {"signal": "dragging ? 'lemonchiffon' : '#fff'"}
        },
        "hover": {
          "fill": {"value": "lemonchiffon"},
          "cursor": {"value": "pointer"}
        }
      }
    },
    {
      "type": "text",
      "encode": {
        "enter": {
          "y": {"value": -20},
          "x": {"value": 25},
          "fontSize": {"value": 32},
          "fontWeight": {"value": "bold"},
          "fill": {"value": "steelblue"}
        },
        "update": {"text": {"signal": "currentYear"}}
      }
    }
  ]
}

The triangle slider is positioned on x-axis with value 20 and the slider range is (0-40), so the slider can not be moved outside this range . chart

The expected result I want is : when the triangle slider is moved for example to 30 value on x-axis, the blue rectangle should be updated from (0-30) and the orange rectangle should be updated to (31-40) .

The expected result : enter image description here


Solution

  • enter image description here

    {
      "$schema": "https://vega.github.io/schema/vega/v4.json",
      "width": 400,
      "height": 50,
      "padding": 5,
      "data": [
        {
          "name": "table",
          "values": [
    
            {"x": "Download data (.csv)", "c": "case1", "y": 20},
            {"x": "Download data (.csv)", "c": "case2", "y": 20},
            {"x": "Download data (.csv)", "c": "case3", "y": 20},
            {"x": "Download data (.csv)", "c": "case4", "y": 20},
            {"x": "Download data (.csv)", "c": "case5", "y":20}
          ]
        },
        {
          "name": "filtered-table",
          "source": "table",
          "transform": [
            {"type": "formula", "as": "y", "expr": "datum.c=='case1'?currentYear:datum.c=='case2'?40-currentYear:datum.y"},
            
            {"type": "stack", "groupby": ["x"], "field": "y"}
          ]
        }
      ],
       "signals": [
        {
          "name": "dragging",
          "value": false,
          "on": [
            {"events": "@handle:mousedown", "update": "true"},
            {"events": "window:mouseup", "update": "false"}
          ]
        },
        {
          "name": "handleYear",
          "value": 20, 
          "on": [
            {
              "events": "[@handle:mousedown, window:mouseup] > window:mousemove!",
              "update": "invert('x', clamp(x(), 0, width))"
            }
          ]
        },
        {"name": "currentYear", "update": "clamp(handleYear, 0, 40)"}
        ],
      "scales": [
        {
          "name": "y",
          "type": "band",
          "range": "height",
          "domain": {"data": "filtered-table", "field": "x"}
        },
        {
          "name": "x",
          "type": "linear",
          "range": "width",
          "domain": {"data": "filtered-table", "field": "y1"}
        },
        {
          "name": "color",
          "type": "ordinal",
          "range": ["darkblue", "orange", "lightgrey", "red", "green"],
          "domain": {"data": "filtered-table", "field": "c"}
        }
      ],
      "axes": [{"orient": "left", "scale": "y", "ticks": false, "labelPadding": 5},
      {"orient": "bottom", "scale": "x", "ticks": false, "labelPadding": 5}],
      "marks": [
        {
          "type": "rect",
          "from": {"data": "filtered-table"},
          "encode": {
            "update": {
              "y": {"scale": "y", "field": "x"},
              "height": {"scale": "y", "band": 1, "offset": -1},
              "x": {"scale": "x", "field": "y0"},
              "x2": {"scale": "x", "field": "y1"},
              "fill": {"scale": "color", "field": "c"}
          
          ,"fillOpacity": {"value": 1}},
            "hover": {"fillOpacity": {"value": 0.5}}
          }
        },
    
        {
          "name": "handle",
          "type": "symbol",
          "encode": {
            "enter": {
              "y": {"scale": "x", "value":0, "offset": -7},
              "shape": {"value": "triangle-down"},
              "size": {"value": 400},
              "stroke": {"value": "#000"},
              "strokeWidth": {"value": 0.5}
            },
            "update": {
              "x": {"scale": "x", "signal": "currentYear"},
              "fill": {"signal": "dragging ? 'lemonchiffon' : '#fff'"}
            },
            "hover": {
              "fill": {"value": "lemonchiffon"},
              "cursor": {"value": "pointer"}
            }
          }
        },
        {
          "type": "text",
          "encode": {
            "enter": {
              "y": {"value": -20},
              "x": {"value": 25},
              "fontSize": {"value": 32},
              "fontWeight": {"value": "bold"},
              "fill": {"value": "steelblue"}
            },
            "update": {"text": {"signal": "currentYear"}}
          }
        }
      ]
    }