userrr
userrr

Reputation: 279

Add Arbitrary Legend to Vega-Lite Deneb

This is currently my code . I'm displaying two area charts showcasing the evolution of metrics in 2022 and 2023 over the months:

{
  "data": {"name": "dataset"},
  "transform": [
    {
      "calculate": "format(datum['Leaves Count 2022']/1000,'0.1f')+'k'",
      "as": "l1"
    },
    {
      "calculate": "format(datum['Leaves Count 2023']/1000,'0.1f')+'k'",
      "as": "l2"
    },
    {
      "joinaggregate": [
        {
          "op": "max",
          "field": "Leaves Count 2022",
          "as": "l1max"
        },
        {
          "op": "max",
          "field": "Leaves Count 2023",
          "as": "l2max"
        },
        {
          "op": "min",
          "field": "Leaves Count 2022",
          "as": "l1min"
        },
        {
          "op": "min",
          "field": "Leaves Count 2023",
          "as": "l2min"
        }
      ]
    }
  ],
  "layer": [
    {
      "mark": {
        "type": "area",
        "line": {"color": "#063970"},
        "color": {
          "x1": 1,
          "y1": 1,
          "gradient": "linear",
          "stops": [
            {
              "offset": 0,
              "color": "white"
            },
            {
              "offset": 1,
              "color": "#063970"
            }
          ]
        }
      }
    },
    {
      "mark": {
        "type": "area",
        "line": {"color": "#2596be"},
        "color": {
          "x1": 1,
          "y1": 1,
          "gradient": "linear",
          "stops": [
            {
              "offset": 0,
              "color": "white"
            },
            {
              "offset": 1,
              "color": "#2596be"
            }
          ]
        }
      },
      "encoding": {
        "y": {
          "field": "Leaves Count 2022",
          "type": "quantitative"
        }
      }
    },
    {
      "mark": {
        "type": "circle",
        "size": 50,
        "fill": {
          "expr": "datum['Leaves Count 2023'] == datum.l2max ? 'red' : datum['Leaves Count 2023'] == datum.l2min ? 'green' : '#063970'"
        },
        "stroke": "white",
        "strokeWidth": 1
      },
      "encoding": {
        "x": {
          "field": "MONTH",
          "type": "ordinal",
          "sort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
        },
        "y": {
          "field": "Leaves Count 2023",
          "type": "quantitative"
        }
      }
    },
    {
      "mark": {
        "type": "circle",
        "size": 50,
        "fill": {
          "expr": "datum['Leaves Count 2022'] == datum.l1max ? 'red' : datum['Leaves Count 2022'] == datum.l1min ? 'green' : '#2596be'"
        },
        "stroke": "white",
        "strokeWidth": 1
      },
      "encoding": {
        "x": {
          "field": "MONTH",
          "type": "ordinal",
          "sort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
        },
        "y": {
          "field": "Leaves Count 2022",
          "type": "quantitative"
        }
      }
    },
    {
      "mark": {
        "type": "text",
        "yOffset": -10,
        "size": 10,
        "color": {
          "expr": "datum['Leaves Count 2023'] == datum.l2max ? 'red' : datum['Leaves Count 2023'] == datum.l2min ? 'green' : '#000000'"
        },
        "fontWeight": {
          "expr": "datum['Leaves Count 2023'] == datum.l2max || datum['Leaves Count 2023'] == datum.l2min ? 'bold' : 'normal'"
        }
      },
      "encoding": {
        "text": {"field": "l2"},
        "opacity": {
          "condition": {
            "test": {
              "field": "MONTH",
              "equal": "off"
            },
            "value": 0.1
          },
          "value": 1
        },
        "y": {
          "field": "Leaves Count 2023",
          "type": "quantitative",
          "axis": null
        }
      }
    },
    {
      "mark": {
        "type": "text",
        "yOffset": -10,
        "size": 10,
        "color": {
          "expr": "datum['Leaves Count 2022'] == datum.l1max ? 'red' : datum['Leaves Count 2022'] == datum.l1min ? 'green' : '#000000'"
        },
        "fontWeight": {
          "expr": "datum['Leaves Count 2022'] == datum.l1max || datum['Leaves Count 2022'] == datum.l1min ? 'bold' : 'normal'"
        }
      },
      "encoding": {
        "text": {"field": "l1"},
        "opacity": {
          "condition": {
            "test": {
              "field": "MONTH",
              "equal": "off"
            },
            "value": 0.1
          },
          "value": 1
        },
        "y": {
          "field": "Leaves Count 2022",
          "type": "quantitative",
          "axis": null
        }
      }
    },
    {
      "mark": {
        "type": "rule",
        "stroke": "red",
        "strokeDash": [3, 3]
      },
      "encoding": {
        "x": {
          "field": "MONTH",
          "type": "ordinal",
          "sort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
        },
        "y": {
          "field": "Leaves Count 2023",
          "type": "quantitative"
        }
      },
      "transform": [
        {"filter": "datum['Leaves Count 2023'] == datum.l2max"}
      ]
    },
    {
      "mark": {
        "type": "rule",
        "stroke": "red",
        "strokeDash": [3, 3]
      },
      "encoding": {
        "x": {
          "field": "MONTH",
          "type": "ordinal",
          "sort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
        },
        "y": {
          "field": "Leaves Count 2022",
          "type": "quantitative"
        }
      },
      "transform": [
        {"filter": "datum['Leaves Count 2022'] == datum.l1max"}
      ]
    }
  ],
  "encoding": {
    "x": {
      "field": "MONTH",
      "type": "ordinal",
      "axis": {"labelPadding": 0},
      "sort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
      "title": "MONTH"
    },
    "y": {
      "field": "Leaves Count 2023",
      "type": "quantitative",
      "axis": null
    }
  }
}

I want to add a legend at the right of my visual with two small circles colored in the same color as my the colors I used for leaves count 2022 and leaves count 2023 , something like this

enter image description here How can my code be edited to fulfill this task?

Upvotes: 1

Views: 144

Answers (1)

davidebacci
davidebacci

Reputation: 30174

Legends are supposed to be created automatically from your spec. Your spec is a bit to big to parse and impossible to test without sample data. However, you can create arbitrary legends as follows.

enter image description here

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "A bar chart with negative values. We can hide the axis domain line, and instead use a conditional grid color to draw a zero baseline.",
  "data": {
    "values": [
      {"a": "A", "b": -28},
      {"a": "B", "b": 55},
      {"a": "C", "b": -33},
      {"a": "D", "b": 91},
      {"a": "E", "b": 81},
      {"a": "F", "b": 53},
      {"a": "G", "b": -19},
      {"a": "H", "b": 87},
      {"a": "I", "b": 52}
    ]
  },
  "encoding": {
    "y": {
      "field": "a",
      "type": "nominal",
      "axis": {
        "domain": false,
        "ticks": false,
        "labelAngle": 0,
        "labelPadding": 4
      }
    },
    "x": {
      "field": "b",
      "type": "quantitative",
      "scale": {"padding": 20},
      "axis": {
        "gridColor": {
          "condition": {"test": "datum.value === 0", "value": "black"},
          "value": "#ddd"
        }
      }
    }
  },
  "layer": [
    {"mark": "bar"},
    {
      "mark": {
        "type": "text",
        "align": {"expr": "datum.b < 0 ? 'right' : 'left'"},
        "dx": {"expr": "datum.b < 0 ? -2 : 2"}
      },
      "encoding": {"text": {"field": "b", "type": "quantitative"}}
    },
    {
      "mark": "point",
      "encoding": {
        "strokeWidth":{"value": 0},
        "fill": {
          "field": "x",
          "title":"Total Sales by Channel",
          "scale": {
            "domain": ["Export", "Wholesale"],
            "range": ["red", "blue"]
          }, "legend":{"symbolStrokeWidth":0}
        }
      }
    }
  ]
}

The important part is this and all the values (including field x) are made up:

{
      "mark": "point",
      "encoding": {
        "strokeWidth":{"value": 0},
        "fill": {
          "field": "x",
          "title":"Total Sales by Channel",
          "scale": {
            "domain": ["Export", "Wholesale"],
            "range": ["red", "blue"]
          }, "legend":{"symbolStrokeWidth":0}
        }
      }
    }

Upvotes: 1

Related Questions