Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

top-level legend option, and better types #2249

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mbostock
Copy link
Member

@mbostock mbostock commented Nov 23, 2024

This introduces a new top-level legend option which is inherited by scales that support legends (color, symbol, and opacity). This makes it slightly more concise to enable legends, and takes us a step closer to enabling them automatically if desired. For example:

Screenshot 2024-11-23 at 9 31 27 AM
Plot.plot({
  grid: true,
  inset: 12,
  legend: true,
  marks: [Plot.dot(decathlon, {x: "Long Jump", y: "100 Meters", symbol: "Country", stroke: "Country"})]
})

Note above that Plot is smart enough to realize that the symbol legend subsumes the color legend, and hence the color legend does not need to be displayed separately. Plot now suppresses the color legend automatically when the symbol legend also encodes color. You can force separate legends by using the stroke symbol legend option:

Screenshot 2024-11-23 at 9 35 04 AM
Plot.plot({
  grid: true,
  inset: 12,
  legend: true,
  symbol: {stroke: "currentColor"},
  marks: [Plot.dot(decathlon, {x: "Long Jump", y: "100 Meters", symbol: "Country", stroke: "Country"})]
})

I considered the alternative below, which we could have display a colorless symbol legend and no color legend, but it would require more finagling to allow the symbol legend to read the color legend options; let me know if you prefer it:

Plot.plot({
  grid: true,
  inset: 12,
  legend: true,
  color: {legend: false},
  marks: [Plot.dot(decathlon, {x: "Long Jump", y: "100 Meters", symbol: "Country", stroke: "Country"})]
})

I also wasn’t sure if we wanted a way to force the display of separate symbol and color legends, as this currently displays only a joint legend (which I think makes sense, since it’s equivalent to inheriting the top-level option):

Plot.plot({
  grid: true,
  inset: 12,
  color: {legend: true},
  symbol: {legend: true},
  marks: [Plot.dot(decathlon, {x: "Long Jump", y: "100 Meters", symbol: "Country", stroke: "Country"})]
})

Lastly, this fixes a types bug where legend options were not allowed on scale options. For example, setting the stroke symbol legend option previously errored with Object literal may only specify known properties, and 'stroke' does not exist in type 'ScaleOptions'. This also introduces more specific types for legend options for additional safety.

@mbostock mbostock requested a review from Fil November 23, 2024 17:38
@Fil
Copy link
Contributor

Fil commented Nov 23, 2024

I love it. I don't see the need to have an option to force the separate legends when it's a double encoding. (Given that a user who really wants two legends can always create them with plot.legend.)

One caveat is that when we introduce radius legends (hopefully one day 😊 ), this will change the output (for the better…)?

@mbostock
Copy link
Member Author

Right, if you set the top-level legend option, you’re opting-in to potential future legends. I think that’s okay.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants