# Color and Legend Help in Plot

**URL:** <https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000>\
**Category:** Help\
**Created:** [September 5, 2022, 5:43pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000 "2022-09-05T17:43:21Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![frscott](https://avatars.discourse-cdn.com/v4/letter/f/90db22/32.png) [@frscott](https://talk.observablehq.com/u/frscott)\
**Post date:** [September 5, 2022, 5:43pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/1 "2022-09-05T17:43:21Z")

</div>

Hello,

I have a bunch of line graphs that you can sort by drug name. I want 8th grade to be green, 10th grade to be blue, and 12th grade to be red.

Initially I just did this

```auto
    color: {
      domain: ["8th Grade", "10th Grade", "12th Grade"],
      range: ["green", "blue", "red"],
      legend: true
    },

```

But for some graphs where I only have 12th grade data the legend would show 8th and 10th grade as well. I just wanted to show 12th grade in the legend. Is there an easy way to do this?

So I tried using the filtered data as the domain and I left the range the same.

```auto
    color: {
      domain: radio.grade,
      range: ["green", "blue", "red"],
      legend: true
    },

```

The problem here is that it makes 12th grade green instead of red. How would I go about keeping my same color scheme even when the domain changes from three grades to just one grade?

Here is the [example notebook with both implementations](https://observablehq.com/d/90ae80328f0707ec#drug=%22Beer%22).

---

<div class="post-metadata">

**Author:** ![Fil](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/fil/32/207_2.png) [@Fil](https://talk.observablehq.com/u/Fil)\
**Post date:** [September 5, 2022, 5:57pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/2 "2022-09-05T17:57:44Z")

</div>

I’ve sent you [a suggestion](https://observablehq.com/compare/90ae80328f0707ec...d1aed7435d3b655c).

---

<div class="post-metadata">

**Author:** ![frscott](https://avatars.discourse-cdn.com/v4/letter/f/90db22/32.png) [@frscott](https://talk.observablehq.com/u/frscott)\
**Post date:** [September 5, 2022, 6:01pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/3 "2022-09-05T18:01:07Z")

</div>

Thank you!

---

<div class="post-metadata">

**Author:** ![Fil](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/fil/32/207_2.png) [@Fil](https://talk.observablehq.com/u/Fil)\
**Post date:** [September 5, 2022, 6:07pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/4 "2022-09-05T18:07:41Z")

</div>

I’ve updated the suggestion with (I think) a more readable/editable format.

---

<div class="post-metadata">

**Author:** ![jikaczmarski](https://avatars.discourse-cdn.com/v4/letter/j/74df32/32.png) [@jikaczmarski](https://talk.observablehq.com/u/jikaczmarski)\
**Post date:** [March 31, 2024, 4:15am UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/5 "2024-03-31T04:15:54Z")

</div>

@Fil I am not able to see your suggestion. Would you be able to retrace what you did? This is the exact problem I’m having.

---

<div class="post-metadata">

**Author:** ![Fil](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/fil/32/207_2.png) [@Fil](https://talk.observablehq.com/u/Fil)\
**Post date:** [March 31, 2024, 8:26am UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/6 "2024-03-31T08:26:58Z")

</div>

Two years later, and @frscott has deleted their notebook, I’m sorry I don’t remember what I suggested.

A possibility is to create the mapping like so:

```auto
colors = new Map([["8th Grade", "green"], ["10th Grade", "blue"], ["12th Grade", "red"]]);

```

and then use:

```auto
    color: {
      domain,
      range: Array.from(domain, (c) => colors.get(c)),
      legend: true
    },

```

---

<div class="post-metadata">

**Author:** ![jikaczmarski](https://avatars.discourse-cdn.com/v4/letter/j/74df32/32.png) [@jikaczmarski](https://talk.observablehq.com/u/jikaczmarski)\
**Post date:** [March 31, 2024, 3:29pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/7 "2024-03-31T15:29:49Z")

</div>

Thanks for getting back to me on this. Your snippet has been a good help. Could you expand on the domain a little bit more in the `color:` section? I have a single data file that I filter in differently depending on the figure we’re trying to show. How would I declare the domain?

I’ve written a minimum example of the type of problem I’m dealing with:

```auto
// Define the color scheme
colors = new Map([
    ["8th Grade", "green"], 
    ["10th Grade", "blue"], 
    ["12th Grade", "red"]
]);

// Plot a filtered version of the data
Plot.plot({
    marks: [
        Plot.barY(
            data,
            Plot.groupX(
                {
                    y: "sum"
                },
                {
                    filter: d => d.grade != "10th Grade",
                    x: "x",
                    y: "y",
                    fill: "grade"
                }
            )
        ),
        Plot.ruleY([0])
    ],

    // Legend
    color: {
        domain,
        range: Array.from(domain, (c) => colors.get(c)),
        legend: true
    }
})

```

Which would return `domain is not defined`

---

<div class="post-metadata">

**Author:** ![Fil](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/fil/32/207_2.png) [@Fil](https://talk.observablehq.com/u/Fil)\
**Post date:** [March 31, 2024, 7:47pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/8 "2024-03-31T19:47:10Z")

</div>

Sure, you need to define the domain to the exact values you want to support in this chart (e.g. domain = [“8th grade”, “12th grade”]).

---

<div class="post-metadata">

**Author:** ![jikaczmarski](https://avatars.discourse-cdn.com/v4/letter/j/74df32/32.png) [@jikaczmarski](https://talk.observablehq.com/u/jikaczmarski)\
**Post date:** [March 31, 2024, 8:07pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/9 "2024-03-31T20:07:00Z")

</div>

That makes sense. Is there a programmatic way to export the domain from the fill only after it’s been filtered?

I want to avoid hard coding domains because this process will be repeated frequently.

---

<div class="post-metadata">

**Author:** ![Fil](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/fil/32/207_2.png) [@Fil](https://talk.observablehq.com/u/Fil)\
**Post date:** [March 31, 2024, 9:01pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/10 "2024-03-31T21:01:58Z")

</div>

you can create a chart with the default color scale, then read that scale’s domain:

> Plot.dot(data, {fill: “grade”}).plot().scale(“color”).domain

Note that the **filter** option does not change the color’s domain; you will have to filter the data instead: Plot.dot(data.filter(…)), {fill: “grade”}) etc.

---

<div class="post-metadata">

**Author:** ![jikaczmarski](https://avatars.discourse-cdn.com/v4/letter/j/74df32/32.png) [@jikaczmarski](https://talk.observablehq.com/u/jikaczmarski)\
**Post date:** [March 31, 2024, 9:14pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/11 "2024-03-31T21:14:02Z")

</div>

I see, so it seems that my issue centers around filtering as an option instead of using a full on data filter. I think this is plenty to go off for now. Thanks for taking the time to contribute.

---

<div class="post-metadata">

**Author:** ![Fil](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/fil/32/207_2.png) [@Fil](https://talk.observablehq.com/u/Fil)\
**Post date:** [March 31, 2024, 9:39pm UTC](https://talk.observablehq.com/t/color-and-legend-help-in-plot/7000/12 "2024-03-31T21:39:58Z")

</div>

Note that if you filter on the value (as in the pseudo example above), there’s no reason to create a fake chart and throw it away, since you could filter on the domain directly; my first suggestion would be more performant in that case:

```auto
    color: {
        domain: domain.filter(d => d !== "8th grade"),
        range: Array.from(domain.filter(d => d !== "8th grade"), (c) => colors.get(c)),
        legend: true
    }

```
