Sam Shiles
Sam Shiles

Reputation: 11249

Vega-lite set color from data whilst retaining a legend

I'm trying to use values from the data in order to set the colors of the bars. I would also like this to be reflected in a legend.

So I've figured out how to use a specific color for a bar, based on a value in the data:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "description": "A bar chart that directly encodes color names in the data.",
  "data": {
    "values": [
      {
        "color": "rgb(0, 0, 0)",
        "b": 28,
        "type": "outside"
      },
      {
        "color": "rgb(255, 0, 0)",
        "b": 55,
        "type": "inside"
      },
      {
        "color": "rgb(0, 255, 0)",
        "b": 43,
        "type": "dew"
      }
    ]
  },  
  "mark": "bar",
  "encoding": {
    "x": {
      "field": "type",
      "type": "nominal"
    },
    "y": {
      "field": "b",
      "type": "quantitative"
    },
    "color": { "field": "color", "type": "nominal", "legend": {}, "scale": null}
  }
}

Correctly colored bars:

Correctly Colored Bars

The above only works due to the "scale": null which prevents the legend from showing. If I remove this, then the legend shows, but the custom colors are lost and I get the rbg values showing up in the legend:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "description": "A bar chart that directly encodes color names in the data.",
  "data": {
    "values": [
      {
        "color": "rgb(0, 0, 0)",
        "b": 28,
        "type": "outside"
      },
      {
        "color": "rgb(255, 0, 0)",
        "b": 55,
        "type": "inside"
      },
      {
        "color": "rgb(0, 255, 0)",
        "b": 43,
        "type": "dew"
      }
    ]
  },  
  "mark": "bar",
  "encoding": {
    "x": {
      "field": "type",
      "type": "nominal"
    },
    "y": {
      "field": "b",
      "type": "quantitative"
    },
    "color": { "field": "color", "type": "nominal", "legend": {}}
  }
}

Colors lost, wrong legend labels:

enter image description here

I can obviously get the correct legend labels with:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "description": "A bar chart that directly encodes color names in the data.",
  "data": {
    "values": [
      {
        "color": "rgb(0, 0, 0)",
        "b": 28,
        "type": "outside"
      },
      {
        "color": "rgb(255, 0, 0)",
        "b": 55,
        "type": "inside"
      },
      {
        "color": "rgb(0, 255, 0)",
        "b": 43,
        "type": "dew"
      }
    ]
  },  
  "mark": "bar",
  "encoding": {
    "x": {
      "field": "type",
      "type": "nominal"
    },
    "y": {
      "field": "b",
      "type": "quantitative"
    },
    "color": { "field": "type", "type": "nominal", "legend": {}}
  }
}

But still I don't get the colors I want:

enter image description here

Is it possible to have both custom colors and a legend?

Upvotes: 4

Views: 2572

Answers (1)

jakevdp
jakevdp

Reputation: 86330

The way to get custom colors to appear in a legend is to use a scale with a custom scheme. For example, you could create the chart you have in mind this way:

(view in vega editor)

{
  "data": {
    "values": [
      {"b": 28, "type": "outside"},
      {"b": 55, "type": "inside"},
      {"b": 43, "type": "dew"}
    ]
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "type", "type": "nominal"},
    "y": {"field": "b", "type": "quantitative"},
    "color": {
      "field": "type",
      "type": "nominal",
      "scale": {
        "domain": ["outside", "inside", "dew"],
        "range": ["rgb(0, 0, 0)", "rgb(255, 0, 0)", "rgb(0, 255, 0)"]
      }
    }
  }
}

enter image description here

I don't know of any way to draw this color scheme definition from the data, or to force a legend to be drawn when setting scale to null, but you could hack it by essentially drawing the legend yourself. It might look something like this:

(view in vega editor)

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "description": "A bar chart that directly encodes color names in the data.",
  "data": {
    "values": [
      {"color": "rgb(0, 0, 0)", "b": 28, "type": "outside"},
      {"color": "rgb(255, 0, 0)", "b": 55, "type": "inside"},
      {"color": "rgb(0, 255, 0)", "b": 43, "type": "dew"}
    ]
  },
  "hconcat": [
    {
      "mark": "bar",
      "encoding": {
        "x": {"field": "type", "type": "nominal"},
        "y": {"field": "b", "type": "quantitative"},
        "color": {
          "field": "color",
          "type": "nominal",
          "legend": {},
          "scale": null
        }
      }
    },
    {
      "title": "type",
      "mark": {"type": "point", "size": 80, "shape": "square", "filled": true},
      "encoding": {
        "y": {
          "field": "type",
          "type": "nominal",
          "axis": {"orient": "right", "title": null}
        },
        "color": {"field": "color", "type": "nominal", "scale": null}
      }
    }
  ]
}

enter image description here

Upvotes: 4

Related Questions