A ternary chart example created by [Adrián Bazzana](https://www.linkedin.com/in/adrian-bazzana/).

View this example in the online editor

Vega-Lite JSON Specification

{
  "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
  "width": 625,
  "height": 541.25,
  "padding": 50,
  "title": {
    "text": [
      "Population Distribution by Socioeconomic Level in Cities [Data shown is fictional]"
    ],
    "fontSize": 15,
    "subtitleFontSize": 14,
    "subtitleFontStyle": "italic",
    "anchor": "start",
    "color": "#000000",
    "subtitleColor": "#76d9e4",
    "offset": 50
  },
  "config": {
    "view": {"stroke": "transparent"},
    "axis": {"disable": true, "grid": false, "tickBand": "extent"}
  },
  "layer": [
    {
      "data": {
        "values": [
          {"x": 0.25, "y": 0.433},
          {"x": 0.75, "y": 0.433},
          {"x": 0.5, "y": 0}
        ]
      },
      "mark": {"type": "line", "fill": "#c8edf1a2", "interpolate": "linear-closed","stroke": "#c8edf1a2", "strokeWidth": 0.2},
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"}
      }
    },
    {
      "data": {
        "values": [
          {"x": 0, "y": 0},
          {"x": 0.25, "y": 0.433},
          {"x": 0.5, "y": 0}
        ]
      },
      "mark": {"type": "line", "fill": "#f7b7b7", "interpolate": "linear-closed", "stroke": "#f7b7b7", "strokeWidth": 0.2},
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"}
      }
    },
    {
      "data": {
        "values": [
          {"x": 0, "y": 0},
          {"x": 0.1, "y": 0.1732},
          {"x": 0.2, "y": 0}
        ]
      },
      "mark": {"type": "line", "fill": "#ff7a7a", "interpolate": "linear-closed", "stroke": "#ff7a7a", "strokeWidth": 0.2},
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"}
      }
    },
    {
      "data": {
        "values": [
          {"x": 1, "y": 0},
          {"x": 0.75, "y": 0.433},
          {"x": 0.5, "y": 0}
        ]
      },
      "mark": {"type": "line", "fill": "#d1ffdb", "interpolate": "linear-closed", "stroke": "#d1ffdb", "strokeWidth": 0.2},
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"}
      }
    },
    {
      "data": {
        "values": [
          {"x": 1, "y": 0},
          {"x": 0.9, "y": 0.1732},
          {"x": 0.8, "y": 0}
        ]
      },
      "mark": {"type": "line", "fill": "#7cff98", "interpolate": "linear-closed", "stroke": "#7cff98", "strokeWidth": 0.2},
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"}
      }
    },
    {
      "data": {
        "values": [
          {"x": 0.5, "y": 0.866},
          {"x": 0.25, "y": 0.433},
          {"x": 0.75, "y": 0.433}
        ]
      },
      "mark": {"type": "line", "fill": "#ffd26f", "interpolate": "linear-closed", "stroke": "#ffd26f", "strokeWidth": 0.2},
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"}
      }
    },
    {
      "data": {
        "values": [
          {"x": 0.5, "y": 0.866},
          {"x": 0.4, "y": 0.6928},
          {"x": 0.6, "y": 0.6928}
        ]
      },
      "mark": {"type": "line", "fill": "#fff0cf", "interpolate": "linear-closed", "stroke": "#fff0cf", "strokeWidth": 0.2},
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"}
      }
    },
    {
      "data": {
        "values": [
          {"x": -0.05, "y": -0.05, "label": "High 100%"},
          {"x": 1.05, "y": -0.05, "label": "Low 100%"},
          {"x": 0.5, "y": 0.888, "label": "Medium 100%"}
        ]
      },
      "mark": {"type": "text", "dy": -10, "fontSize": 13, "color": "#000000"},
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"},
        "text": {"field": "label", "type": "nominal"}
      }
    },
    {
      "data": {
        "values": [
          {"x": 0.1, "y": 0, "x2": 0.05, "y2": 0.0866},
          {"x": 0.2, "y": 0, "x2": 0.1, "y2": 0.1732},
          {"x": 0.3, "y": 0, "x2": 0.15, "y2": 0.2598},
          {"x": 0.4, "y": 0, "x2": 0.2, "y2": 0.3464},
          {"x": 0.5, "y": 0, "x2": 0.25, "y2": 0.433},
          {"x": 0.6, "y": 0, "x2": 0.3, "y2": 0.5196},
          {"x": 0.7, "y": 0, "x2": 0.35, "y2": 0.6062},
          {"x": 0.8, "y": 0, "x2": 0.4, "y2": 0.6928},
          {"x": 0.9, "y": 0, "x2": 0.45, "y2": 0.7794},
          {"x": 0.9, "y": 0, "x2": 0.95, "y2": 0.0866},
          {"x": 0.8, "y": 0, "x2": 0.9, "y2": 0.1732},
          {"x": 0.7, "y": 0, "x2": 0.85, "y2": 0.2598},
          {"x": 0.6, "y": 0, "x2": 0.8, "y2": 0.3464},
          {"x": 0.5, "y": 0, "x2": 0.75, "y2": 0.433},
          {"x": 0.4, "y": 0, "x2": 0.7, "y2": 0.5196},
          {"x": 0.3, "y": 0, "x2": 0.65, "y2": 0.6062},
          {"x": 0.2, "y": 0, "x2": 0.6, "y2": 0.6928},
          {"x": 0.1, "y": 0, "x2": 0.55, "y2": 0.7794},
          {"x": 0.05, "y": 0.0866, "x2": 0.95, "y2": 0.0866},
          {"x": 0.1, "y": 0.1732, "x2": 0.9, "y2": 0.1732},
          {"x": 0.15, "y": 0.2598, "x2": 0.85, "y2": 0.2598},
          {"x": 0.2, "y": 0.3464, "x2": 0.8, "y2": 0.3464},
          {"x": 0.25, "y": 0.433, "x2": 0.75, "y2": 0.433},
          {"x": 0.3, "y": 0.5196, "x2": 0.7, "y2": 0.5196},
          {"x": 0.35, "y": 0.6062, "x2": 0.65, "y2": 0.6062},
          {"x": 0.4, "y": 0.6928, "x2": 0.6, "y2": 0.6928},
          {"x": 0.45, "y": 0.7794, "x2": 0.55, "y2": 0.7794}
        ]
      },
      "mark": {"type": "rule", "stroke": "#696969", "strokeDash": [2, 2]},
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"},
        "x2": {"field": "x2"},
        "y2": {"field": "y2"}
      }
    },
    {
      "data": {
        "values": [
          {"City": "Tokyo", "High": 5, "Medium": 50, "Low": 30},
          {"City": "New York", "High": 35, "Medium": 60, "Low": 20},
          {"City": "Mumbai", "High": 115, "Medium": 40, "Low": 70},
          {"City": "London", "High": 30, "Medium": 45, "Low": 252},
          {"City": "São Paulo", "High": 120, "Medium": 35, "Low": 2},
          {"City": "Paris", "High": 28, "Medium": 48, "Low": 32},
          {"City": "Mexico City", "High": 32, "Medium": 458, "Low": 55},
          {"City": "Cairo", "High": 12, "Medium": 30, "Low": 55},
          {"City": "Sydney", "High": 40, "Medium": 50, "Low": 15},
          {"City": "Johannesburg", "High": 18, "Medium": 28, "Low": 35}
        ]
      },
      "transform": [
        {
          "calculate": "datum['High'] + datum['Medium'] + datum['Low']",
          "as": "TotalLevel"
        },
        {"calculate": "datum['High']/datum.TotalLevel", "as": "high_percent"},
        {
          "calculate": "datum['Medium']/datum.TotalLevel",
          "as": "medium_percent"
        },
        {"calculate": "datum['Low']/datum.TotalLevel", "as": "low_percent"},
        {
          "calculate": "0.5 * (2 * datum.low_percent + datum.medium_percent)",
          "as": "x"
        },
        {"calculate": "0.866 * datum.medium_percent", "as": "y"},
        {
          "calculate": "toString(isValid(datum['High']) ? datum['High'] : 0) + ' (' + toString(round((isValid(datum.high_percent) ? datum.high_percent : 0) * 100, 1)) + '%)'",
          "as": "tooltip_high"
        },
        {
          "calculate": "toString(isValid(datum['Medium']) ? datum['Medium'] : 0) + ' (' + toString(round((isValid(datum.medium_percent) ? datum.medium_percent : 0) * 100, 1)) + '%)'",
          "as": "tooltip_medium"
        },
        {
          "calculate": "toString(isValid(datum['Low']) ? datum['Low'] : 0) + ' (' + toString(round((isValid(datum.low_percent) ? datum.low_percent : 0) * 100, 1)) + '%)'",
          "as": "tooltip_low"
        },
        {"filter": "datum['City'] !== null"},
        {"calculate": "length(datum['City'])", "as": "leng"},
        {
          "calculate": "(datum.x*100 - length(datum['City']))/100",
          "as": "Xleng"
        },
        {
          "calculate": "(datum.x*100 + length(datum['City']))/100",
          "as": "Xleng2"
        },
        {
          "calculate": "datum['high_percent'] > 0.8 ? '#FF0F0F' : datum['medium_percent'] > 0.8 ? '#FFC333' : datum['low_percent'] > 0.8 ? '#32F95D' : datum['high_percent'] > 0.5 && datum['medium_percent'] > datum['low_percent'] ? '#ff3c18' : datum['high_percent'] > 0.5 && datum['medium_percent'] < datum['low_percent'] ? '#cb4922' : datum['medium_percent'] > 0.5 && datum['high_percent'] > datum['low_percent'] ? '#ff962a' : datum['medium_percent'] > 0.5 && datum['high_percent'] < datum['low_percent'] ? '#cbd03d' : datum['low_percent'] > 0.5 && datum['medium_percent'] < datum['high_percent'] ? '#65be49' : datum['low_percent'] > 0.5 && datum['medium_percent'] > datum['high_percent'] ? '#65eb52' : '#43c1ce'",
          "as": "color"
        },
        {"calculate": "datum.medium_percent > 0.9 ? 15 : -15", "as": "dy_val"}
      ],
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"},
        "tooltip": [
          {"field": "City", "type": "nominal", "title": "City:"},
          {"field": "tooltip_high", "type": "nominal", "title": "🔴 High:"},
          {"field": "tooltip_medium", "type": "nominal", "title": "🟡 Medium:"},
          {"field": "tooltip_low", "type": "nominal", "title": "🟢 Low:"}
        ]
      },
      "layer": [
        {
          "mark": {
            "type": "point",
            "opacity": 1,
            "stroke": "#000000",
            "strokeWidth": 1.5,
            "strokeOpacity": 1
          },
          "encoding": {
            "x": {"field": "x", "type": "quantitative"},
            "y": {"field": "y", "type": "quantitative"},
            "fill": {"field": "color", "type": "nominal", "scale": null},
            "size": {
              "field": "TotalLevel",
              "type": "quantitative",
              "legend": null,
              "scale": {"range": [50, 500]}
            }
          }
        },
        {
          "mark": {
            "type": "text",
            "font": "Verdana",
            "dy": {"expr": "datum.dy_val"},
            "fontSize": 13,
            "color": "#000000",
            "fontWeight": 100
          },
          "encoding": {
            "x": {"field": "x", "type": "quantitative"},
            "y": {"field": "y", "type": "quantitative"},
            "text": {"field": "City", "type": "nominal"}
          }
        }
      ]
    }
  ]
}