why would plot not pick unique colors from array or set

In this notebook, neither the domain+range or the fill/color are working when I want to pick 29 unique colors (which I have in my array colorset and colors2) for 29 states.

What am I doing wrong?


Plot’s default scheme for categorical colors, Observable10, is limited to ten colors, and if you go past that number you’ll quickly approach a limit where the colors are no longer discernable to the human eye (especially when affected by color deficiencies).

You may either want to consider setting your domain to the top n countries that you want to display (and color the rest via the unknown option), or generate your own color range from one of the existing sequential scales.

Thanks so much, I understand the logic now.
But I have been able to pick and match colors using domain+range for 25 items in this notebook <https://observablehq.com/@rbhttchr/25-heroes-of-hindi-cinema-1931-2020>, in the horizontal bar graph. Why am I not being able to do it in my Map of India plot? Is there a specific reason why it would not work here?

Oh, I see! If you take a closer look at your colors2 cell you’ll notice that the color definitions are missing the # that indicates a hexadecimal color code. One way to fix it is to map your colors, e.g.

      fill: colors2.map(d => `#${d}`),

(or ideally directly in your colors2 cell)

1 Like

Oh wow, thanks so much! I somehow knew I was doing something incredibly stupid. Thanks a ton!


The domain+range is still not working, though.

height: 800,
width: 800,
margin: 50,
color: { domain: staten2, range: colors },

marks: [
Plot.geo(states, {
stroke: “#e2e2e2”,

  title: (d) => `${d.properties.name}`

Plot.dot(cities, {
  x: "longitude",
  y: "latitude",
  r: 5,
  title: (d) => `${d.city}`
Plot.text(cities, { title: "city" }),

Plot.text(cities, {
  x: "longitude",
  y: "latitude",
  text: "city",
  dy: -15,
  textAnchor: "bottom",
  stroke: "white",
  fill: "black"


You need to add

      fill: d => d.properties.name,

so that Plot knows which value it should use to determine the color.

how to include the range, then?
with just <fill: d => d.properties.name,>, I am back at built-in color options.

fill needs to be one of the values that you specified in domain.

If you use

  color: { domain: statename, range: colorset },

then you also need to use

  marks: [
    Plot.geo(states, {
      stroke: "#e2e2e2",
      fill: "id",

You can always verify which colors and value are used by setting legend: true for your color scale definition.

1 Like

Fantastic, thanks so much!

If I want to use ternary operator (a few states of one particular color), should I do on the level of fill: “id”?

Only if it makes sense semantically. Otherwise I’d consider mapping them to categories and then defining the domain and range for those.

1 Like

Hi Mootari, thanks so much for your help. I am trying to get a grip on the map visualizations, and have a couple of questions.
In the Map of the World, is it possible to grab legends using the domains (visitedcountries, unknown)?
And is it possible to create domain+range for just visitedcountries and/or just unknown?
For example, the unknown will be all black, and the visited countries will be colored according to schemeBloe or whatever.
Or, the visitedcountries will be all black and the unknown will be colored with different colors accoding to Observable10 or whatever?
Thanks in advance!

That is what I meant by “mapping them to categories”. You should make the “visited” / “yet to visit” state a property of your data.

Here’s an example:

  height: 550,
  width: width,
  margin: 5,
  projection: d3.geoPatterson,
  axis: false,
  color: {
    legend: true,
    domain: [true, false],
    range: ["orange", "black"],
    tickFormat: d => d ? "visited" : "yet to visit"

  marks: [
    Plot.geo(countries, {
      stroke: "white",
      fill: d => visitedcountries.includes(d.properties.NAMEen),
    Plot.tip(countries.features, Plot.pointer(Plot.centroid({title: (d) => d.properties.NAMEen}))),   

I’ve also included centroid based labels (adapted from this example) which work for the most part but can end up in odd places for some countries (France, USA).