Adjust the alignment of VEGA bar charts

I would like to adjust the alignment of my charts so that it can look like the following image:

enter image description here

To be up to 220 characters, I ask another question: how to add a tendency on each bar chart just under each chart title ? It could be like : “XX%” with a triangle UP or Down with a conditional color for number & triangle ?

Thanks in advance

Here is my vega code :

{
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "description": "4 graphiques identiques en grille",
  "background": "white",
  "padding": 5,
  "data": [
    {
      "name": "source_0",
      "values": [
        {"a": "1", "b": 28},
        {"a": "2", "b": 55},
        {"a": "3", "b": 43},
        {"a": "4", "b": 91},
        {"a": "5", "b": 81},
        {"a": "6", "b": 53},
        {"a": "7", "b": 19},
        {"a": "8", "b": 87},
        {"a": "9", "b": 52}
      ],
      "format": {}
    },
    {
      "name": "source_1",
      "values": [
        {"a": "1", "b": -3},
        {"a": "2", "b": -10},
        {"a": "3", "b": 43},
        {"a": "4", "b": 91},
        {"a": "5", "b": 81},
        {"a": "6", "b": 53},
        {"a": "7", "b": 19},
        {"a": "8", "b": -50},
        {"a": "9", "b": 52}
      ]
    },
    {
      "name": "source_2",
      "values": [
        {"a": "1", "b": -20},
        {"a": "2", "b": -5},
        {"a": "3", "b": -2},
        {"a": "4", "b": -20},
        {"a": "5", "b": -15},
        {"a": "6", "b": -30},
        {"a": "7", "b": -40},
        {"a": "8", "b": -35},
        {"a": "9", "b": -12}
      ]
    },
    {
      "name": "data_0",
      "source": "source_0",
      "transform": [
        {
          "type": "stack",
          "groupby": ["a"],
          "field": "b",
          "sort": {"field": [], "order": []},
          "as": ["b_start", "b_end"],
          "offset": "zero"
        },
        {
          "type": "filter",
          "expr": "isValid(datum[\"b\"]) && isFinite(+datum[\"b\"])"
        }
      ]
    },
    {
      "name": "data_1",
      "source": "source_1",
      "transform": [
        {
          "type": "stack",
          "groupby": ["a"],
          "field": "b",
          "sort": {"field": [], "order": []},
          "as": ["b_start", "b_end"],
          "offset": "zero"
        },
        {
          "type": "filter",
          "expr": "isValid(datum[\"b\"]) && isFinite(+datum[\"b\"])"
        }
      ]
    },
    {
      "name": "data_2",
      "source": "source_2",
      "transform": [
        {
          "type": "stack",
          "groupby": ["a"],
          "field": "b",
          "sort": {"field": [], "order": []},
          "as": ["b_start", "b_end"],
          "offset": "zero"
        },
        {
          "type": "filter",
          "expr": "isValid(datum[\"b\"]) && isFinite(+datum[\"b\"])"
        }
      ]
    }
  ],
  "signals": [
    {"name": "childHeight", "value": 150},
    {"name": "concat_0_concat_0_x_step", "value": 20},
    {
      "name": "concat_0_concat_0_width",
      "update": "bandspace(domain('concat_0_concat_0_x').length, 0.1, 0.05) * concat_0_concat_0_x_step"
    },
    {"name": "concat_0_concat_1_x_step", "value": 20},
    {
      "name": "concat_0_concat_1_width",
      "update": "bandspace(domain('concat_0_concat_1_x').length, 0.1, 0.05) * concat_0_concat_1_x_step"
    },
    {"name": "concat_1_concat_0_x_step", "value": 20},
    {
      "name": "concat_1_concat_0_width",
      "update": "bandspace(domain('concat_1_concat_0_x').length, 0.1, 0.05) * concat_1_concat_0_x_step"
    },
    {"name": "concat_1_concat_1_x_step", "value": 20},
    {
      "name": "concat_1_concat_1_width",
      "update": "bandspace(domain('concat_1_concat_1_x').length, 0.1, 0.05) * concat_1_concat_1_x_step"
    }
  ],
  "layout": {"padding": 20, "columns": 1, "bounds": "full", "align": "each"},
  "marks": [
    {
      "type": "group",
      "name": "concat_0_group",
      "layout": {"padding": 20, "bounds": "full", "align": "each"},
      "marks": [
        {
          "type": "group",
          "name": "concat_0_concat_0_group",
          "title": {"text": "Graphe 1.1", "frame": "group"},
          "style": "null",
          "encode": {
            "update": {
              "width": {"signal": "concat_0_concat_0_width"},
              "height": {"signal": "childHeight"}
            }
          },
          "marks": [
            {
              "name": "concat_0_concat_0_marks",
              "type": "rect",
              "style": ["bar"],
              "from": {"data": "data_0"},
              "encode": {
                "update": {
                  "fill": [
                    {"test": "datum.b < 0", "value": "red"},
                    {"value": "green"}
                  ],
                  "ariaRoleDescription": {"value": "bar"},
                  "description": {
                    "signal": "\"a: \" + (isValid(datum[\"a\"]) ? datum[\"a\"] : \"\"+datum[\"a\"]) + \"; b: \" + (format(datum[\"b\"], \"\"))"
                  },
                  "x": {"scale": "concat_0_concat_0_x", "field": "a"},
                  "width": {
                    "signal": "max(0.25, bandwidth('concat_0_concat_0_x'))"
                  },
                  "y": {"scale": "concat_0_concat_0_y", "field": "b_end"},
                  "y2": {"scale": "concat_0_concat_0_y", "field": "b_start"}
                }
              }
            }
          ],
          "axes": [
            {
              "scale": "concat_0_concat_0_x",
              "orient": "bottom",
              "grid": false,
              "domain": false,
              "labelAngle": 0,
              "ticks": false,
              "labelBaseline": "top",
              "zindex": 0
            },
            {
              "scale": "concat_0_concat_0_y",
              "orient": "left",
              "grid": false,
              "domain": false,
              "labelAngle": 0,
              "labels": false,
              "ticks": false,
              "labelAlign": "right",
              "labelOverlap": true,
              "tickCount": {"signal": "ceil(childHeight/40)"},
              "zindex": 0
            }
          ]
        },
        {
          "type": "group",
          "name": "concat_0_concat_1_group",
          "title": {"text": "Graphe 1.2", "frame": "group"},
          "style": "null",
          "encode": {
            "update": {
              "width": {"signal": "concat_0_concat_1_width"},
              "height": {"signal": "childHeight"}
            }
          },
          "marks": [
            {
              "name": "concat_0_concat_1_marks",
              "type": "rect",
              "style": ["bar"],
              "from": {"data": "data_0"},
              "encode": {
                "update": {
                  "fill": [
                    {"test": "datum.b < 0", "value": "red"},
                    {"value": "green"}
                  ],
                  "ariaRoleDescription": {"value": "bar"},
                  "description": {
                    "signal": "\"a: \" + (isValid(datum[\"a\"]) ? datum[\"a\"] : \"\"+datum[\"a\"]) + \"; b: \" + (format(datum[\"b\"], \"\"))"
                  },
                  "x": {"scale": "concat_0_concat_1_x", "field": "a"},
                  "width": {
                    "signal": "max(0.25, bandwidth('concat_0_concat_1_x'))"
                  },
                  "y": {"scale": "concat_0_concat_1_y", "field": "b_end"},
                  "y2": {"scale": "concat_0_concat_1_y", "field": "b_start"}
                }
              }
            }
          ],
          "axes": [
            {
              "scale": "concat_0_concat_1_x",
              "orient": "bottom",
              "grid": false,
              "domain": false,
              "labelAngle": 0,
              "ticks": false,
              "labelBaseline": "top",
              "zindex": 0
            },
            {
              "scale": "concat_0_concat_1_y",
              "orient": "left",
              "grid": false,
              "domain": false,
              "labelAngle": 0,
              "labels": false,
              "ticks": false,
              "labelAlign": "right",
              "labelOverlap": true,
              "tickCount": {"signal": "ceil(childHeight/40)"},
              "zindex": 0
            }
          ]
        }
      ]
    },
    {
      "type": "group",
      "name": "concat_1_group",
      "layout": {"padding": 20, "bounds": "full", "align": "each"},
      "marks": [
        {
          "type": "group",
          "name": "concat_1_concat_0_group",
          "title": {"text": "Graphe 2.1", "frame": "group"},
          "style": "null",
          "encode": {
            "update": {
              "width": {"signal": "concat_1_concat_0_width"},
              "height": {"signal": "childHeight"}
            }
          },
          "marks": [
            {
              "name": "concat_1_concat_0_marks",
              "type": "rect",
              "style": ["bar"],
              "from": {"data": "data_1"},
              "encode": {
                "update": {
                  "fill": [
                    {"test": "datum.b < 0", "value": "red"},
                    {"value": "green"}
                  ],
                  "ariaRoleDescription": {"value": "bar"},
                  "description": {
                    "signal": "\"a: \" + (isValid(datum[\"a\"]) ? datum[\"a\"] : \"\"+datum[\"a\"]) + \"; b: \" + (format(datum[\"b\"], \"\"))"
                  },
                  "x": {"scale": "concat_1_concat_0_x", "field": "a"},
                  "width": {
                    "signal": "max(0.25, bandwidth('concat_1_concat_0_x'))"
                  },
                  "y": {"scale": "concat_1_concat_0_y", "field": "b_end"},
                  "y2": {"scale": "concat_1_concat_0_y", "field": "b_start"}
                }
              }
            }
          ],
          "axes": [
            {
              "scale": "concat_1_concat_0_x",
              "orient": "bottom",
              "grid": false,
              "domain": false,
              "labelAngle": 0,
              "ticks": false,
              "labelBaseline": "top",
              "zindex": 0
            },
            {
              "scale": "concat_1_concat_0_y",
              "orient": "left",
              "grid": false,
              "domain": false,
              "labelAngle": 0,
              "labels": false,
              "ticks": false,
              "labelAlign": "right",
              "labelOverlap": true,
              "tickCount": {"signal": "ceil(childHeight/40)"},
              "zindex": 0
            }
          ]
        },
        {
          "type": "group",
          "name": "concat_1_concat_1_group",
          "title": {"text": "Graphe 2.2", "frame": "group"},
          "style": "null",
          "encode": {
            "update": {
              "width": {"signal": "concat_1_concat_1_width"},
              "height": {"signal": "childHeight"}
            }
          },
          "marks": [
            {
              "name": "concat_1_concat_1_marks",
              "type": "rect",
              "style": ["bar"],
              "from": {"data": "data_2"},
              "encode": {
                "update": {
                  "fill": [
                    {"test": "datum.b < 0", "value": "red"},
                    {"value": "green"}
                  ],
                  "ariaRoleDescription": {"value": "bar"},
                  "description": {
                    "signal": "\"a: \" + (isValid(datum[\"a\"]) ? datum[\"a\"] : \"\"+datum[\"a\"]) + \"; b: \" + (format(datum[\"b\"], \"\"))"
                  },
                  "x": {"scale": "concat_1_concat_1_x", "field": "a"},
                  "width": {
                    "signal": "max(0.25, bandwidth('concat_1_concat_1_x'))"
                  },
                  "y": {"scale": "concat_1_concat_1_y", "field": "b_end"},
                  "y2": {"scale": "concat_1_concat_1_y", "field": "b_start"}
                }
              }
            }
          ],
          "axes": [
            {
              "scale": "concat_1_concat_1_x",
              "orient": "bottom",
              "grid": false,
              "domain": false,
              "labelAngle": 0,
              "ticks": false,
              "labelBaseline": "top",
              "zindex": 0
            },
            {
              "scale": "concat_1_concat_1_y",
              "orient": "left",
              "grid": false,
              "domain": false,
              "labelAngle": 0,
              "labels": false,
              "ticks": false,
              "labelAlign": "right",
              "labelOverlap": true,
              "tickCount": {"signal": "ceil(childHeight/40)"},
              "zindex": 0
            }
          ]
        }
      ]
    }
  ],
  "scales": [
    {
      "name": "concat_0_concat_0_x",
      "type": "band",
      "domain": {"data": "data_0", "field": "a", "sort": true},
      "range": {"step": {"signal": "concat_0_concat_0_x_step"}},
      "paddingInner": 0.1,
      "paddingOuter": 0.05
    },
    {
      "name": "concat_0_concat_0_y",
      "type": "linear",
      "domain": {"data": "data_0", "fields": ["b_start", "b_end"]},
      "range": [{"signal": "childHeight"}, 0],
      "nice": true,
      "zero": true
    },
    {
      "name": "concat_0_concat_1_x",
      "type": "band",
      "domain": {"data": "data_0", "field": "a", "sort": true},
      "range": {"step": {"signal": "concat_0_concat_1_x_step"}},
      "paddingInner": 0.1,
      "paddingOuter": 0.05
    },
    {
      "name": "concat_0_concat_1_y",
      "type": "linear",
      "domain": {"data": "data_0", "fields": ["b_start", "b_end"]},
      "range": [{"signal": "childHeight"}, 0],
      "nice": true,
      "zero": true
    },
    {
      "name": "concat_1_concat_0_x",
      "type": "band",
      "domain": {"data": "data_1", "field": "a", "sort": true},
      "range": {"step": {"signal": "concat_1_concat_0_x_step"}},
      "paddingInner": 0.1,
      "paddingOuter": 0.05
    },
    {
      "name": "concat_1_concat_0_y",
      "type": "linear",
      "domain": {"data": "data_1", "fields": ["b_start", "b_end"]},
      "range": [{"signal": "childHeight"}, 0],
      "nice": true,
      "zero": true
    },
    {
      "name": "concat_1_concat_1_x",
      "type": "band",
      "domain": {"data": "data_2", "field": "a", "sort": true},
      "range": {"step": {"signal": "concat_1_concat_1_x_step"}},
      "paddingInner": 0.1,
      "paddingOuter": 0.05
    },
    {
      "name": "concat_1_concat_1_y",
      "type": "linear",
      "domain": {"data": "data_2", "fields": ["b_start", "b_end"]},
      "range": [{"signal": "childHeight"}, 0],
      "nice": true,
      "zero": true
    }
  ]
}

  • Can you clarify the requirement as I don’t quite understand?

    – 

  • Hi Davide, i would like to align the max bars of each chart to the black line (whatever the datas) included the bottom line of the chart 2.2 (TOP 2.1 & 2.2 are not aligned) : Is that much clearer ?

    – 

  • I think I understand but it is not straight forward and would make the scale of each chart different so you could no longer compare across charts. 1.1 and 1.2 currently have the same data but if they did not and you wanted the max to finish at the same point, they would be using different scales which means they could not be compared to one another. Perhaps a percentage based scale would do it but even then, the chart would be misleading.

    – 

  • OK then, i drop this question. Do you need me to delete this post ?

    – 

  • I’ll just add my comment as the answer and you can mark as complete in case it helps anyone else.

    – 

It is not straight forward and would make the scale of each chart different so you could no longer compare across charts. 1.1 and 1.2 currently have the same data but if they did not and you wanted the max to finish at the same point, they would be using different scales which means they could not be compared to one another. Perhaps a percentage based scale would do it but even then, the chart would be misleading.

Leave a Comment