Search code examples
vegaaltairvega-lite

Vega-Lite single line or trail mark with multiple colours


I'm trying to plot something like a trail mark but where I can map the line colour instead of the line size. Is that possible? So far I haven't been able to achieve it.

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "description": "Google's stock price over time.",
  "data": {"url": "data/stocks.csv"},
  "transform": [
    {"filter": "datum.symbol==='GOOG'"},
    {"calculate": "datum.price>400", "as": "good"}
  ],
  "mark": "trail",
  "encoding": {
    "x": {"field": "date", "type": "temporal"},
    "y": {"field": "price", "type": "quantitative"},
    "size": {"field": "good", "type": "nominal"}
  }
}

This is when using size with a trail mark.

This is when using size with a trail mark

This if I map to color.

This if I map to color.


Solution

  • Lines cannot be multiple colors in Vega-Lite, but you can use a color encoding along with an impute transform to change the color of different sections of the line (vega editor):

    {
      "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
      "description": "Google's stock price over time.",
      "data": {"url": "data/stocks.csv"},
      "transform": [
        {"filter": "datum.symbol==='GOOG'"},
        {"calculate": "datum.price>400", "as": "good"}
      ],
      "mark": "line",
      "encoding": {
        "x": {"field": "date", "type": "temporal"},
        "y": {"field": "price", "type": "quantitative", "impute": {"value": null}},
        "color": {"field": "good", "type": "nominal"}
      }
    }
    

    enter image description here

    Unfortunately this leaves breaks in the line; you can get around this by creating a background layer like this (vega editor):

    {
      "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
      "description": "Google's stock price over time.",
      "data": {"url": "data/stocks.csv"},
      "transform": [
        {"filter": "datum.symbol==='GOOG'"},
        {"calculate": "datum.price>400", "as": "good"}
      ],
      "encoding": {
        "x": {"field": "date", "type": "temporal"},
        "y": {"field": "price", "type": "quantitative", "impute": {"value": null}}
      },
      "layer": [
        {"mark": "line"},
        {
          "mark": "line",
          "encoding": {"color": {"field": "good", "type": "nominal"}}
        }
      ]
    }
    

    enter image description here


    Edit: if you're using Altair, the equivalent would be something like this:

    import altair as alt
    from vega_datasets import data
    
    alt.layer(
        alt.Chart().mark_line(),
        alt.Chart().mark_line().encode(color='good:N'),
        data=data.stocks.url
    ).transform_filter(
        'datum.symbol==="GOOG"',
    ).transform_calculate(
        good="datum.price>400"
    ).encode(
        x='date:T',
        y=alt.Y('price:Q', impute={'value': None})
    )
    

    enter image description here