Mosaic Chart with Labels

View this example in the online editor

Vega-Lite JSON Specification

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {
    "url": "data/cars.json"
  },
  "transform": [
    {
      "aggregate": [
        {
          "op": "count",
          "as": "count_*"
        }
      ],
      "groupby": [
        "Origin",
        "Cylinders"
      ]
    },
    {
      "stack": "count_*",
      "groupby": [],
      "as": [
        "stack_count_Origin1",
        "stack_count_Origin2"
      ],
      "offset": "normalize",
      "sort": [
        {
          "field": "Origin",
          "order": "ascending"
        }
      ]
    },
    {
      "window": [
        {
          "op": "min",
          "field": "stack_count_Origin1",
          "as": "x"
        },
        {
          "op": "max",
          "field": "stack_count_Origin2",
          "as": "x2"
        },
        {
          "op": "dense_rank",
          "as": "rank_Cylinders"
        },
        {
          "op": "distinct",
          "field": "Cylinders",
          "as": "distinct_Cylinders"
        }
      ],
      "groupby": [
        "Origin"
      ],
      "frame": [
        null,
        null
      ],
      "sort": [
        {
          "field": "Cylinders",
          "order": "ascending"
        }
      ]
    },
    {
      "window": [
        {
          "op": "dense_rank",
          "as": "rank_Origin"
        }
      ],
      "frame": [
        null,
        null
      ],
      "sort": [
        {
          "field": "Origin",
          "order": "ascending"
        }
      ]
    },
    {
      "stack": "count_*",
      "groupby": [
        "Origin"
      ],
      "as": [
        "y",
        "y2"
      ],
      "offset": "normalize",
      "sort": [
        {
          "field": "Cylinders",
          "order": "ascending"
        }
      ]
    },
    {
      "calculate": "datum.y + (datum.rank_Cylinders - 1) * datum.distinct_Cylinders * 0.01 / 3",
      "as": "ny"
    },
    {
      "calculate": "datum.y2 + (datum.rank_Cylinders - 1) * datum.distinct_Cylinders * 0.01 / 3",
      "as": "ny2"
    },
    {
      "calculate": "datum.x + (datum.rank_Origin - 1) * 0.01",
      "as": "nx"
    },
    {
      "calculate": "datum.x2 + (datum.rank_Origin - 1) * 0.01",
      "as": "nx2"
    },
    {
      "calculate": "(datum.nx+datum.nx2)/2",
      "as": "xc"
    },
    {
      "calculate": "(datum.ny+datum.ny2)/2",
      "as": "yc"
    }
  ],
  "vconcat": [
    {
      "mark": {
        "type": "text",
        "baseline": "middle",
        "align": "center"
      },
      "encoding": {
        "x": {
          "aggregate": "min",
          "field": "xc",
          "title": "Origin",
          "axis": {
            "orient": "top"
          }
        },
        "color": {
          "field": "Origin",
          "legend": null
        },
        "text": {"field": "Origin"}
      }
    },
    {
      "layer": [
        {
          "mark": {
            "type": "rect"
          },
          "encoding": {
            "x": {
              "field": "nx",
              "type": "quantitative",
              "axis": null
            },
            "x2": {"field": "nx2"},
            "y": {
              "field": "ny",
              "type": "quantitative"
            },
            "y2": {"field": "ny2"},
            "color": {
              "field": "Origin",
              "type": "nominal",
              "legend": null
            },
            "opacity": {
              "field": "Cylinders",
              "type": "quantitative",
              "legend": null
            },
            "tooltip": [
              {
                "field": "Origin",
                "type": "nominal"
              },
              {
                "field": "Cylinders",
                "type": "quantitative"
              }
            ]
          }
        },
        {
          "mark": {
            "type": "text",
            "baseline": "middle"
          },
          "encoding": {
            "x": {
              "field": "xc",
              "type": "quantitative",
              "axis": null
            },
            "y": {
              "field": "yc",
              "type": "quantitative",
              "axis": {
                "title": "Cylinders"
              }
            },
            "text": {
              "field": "Cylinders",
              "type": "nominal"
            }
          }
        }
      ]
    }
  ],
  "resolve": {
    "scale": {
      "x": "shared"
    }
  },
  "config": {
    "view": {
      "stroke": ""
    },
    "concat": {"spacing": 10},
    "axis": {
      "domain": false,
      "ticks": false,
      "labels": false,
      "grid": false
    }
  }
}