# Faceting a Choropleth

**URL:** <https://talk.observablehq.com/t/faceting-a-choropleth/9387>\
**Category:** Help\
**Created:** [June 12, 2024, 1:53pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387 "2024-06-12T13:53:56Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Evan](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/evan/32/276_2.png) [@Evan](https://talk.observablehq.com/u/Evan)\
**Post date:** [June 12, 2024, 1:53pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/1 "2024-06-12T13:53:56Z")

</div>

Hi!

I’m a big fan of Plot but one thing I can’t figure out is how to facet a choropleth. For instance, take the Choropleth Plot example: [Plot: Choropleth / Observable | Observable](https://observablehq.com/@observablehq/plot-choropleth) and imagine that you have a yearly time series of unemployment data. Is there an obvious way to facet on year?

The only way I can figure out how to do it would be to create a geometry object for each county-year combination, which seems excessive because it would mean making many copies of the same geometries.

Currently, I work around this by just creating my own faceted layout using something like this approach: [Facet wrap / Toph Tucker | Observable](https://observablehq.com/@tophtucker/facet-wrap).

Thanks for any help!

---

<div class="post-metadata">

**Author:** ![Cobus](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cobus/32/9670_2.png) [@Cobus](https://talk.observablehq.com/u/Cobus)\
**Post date:** [June 12, 2024, 2:22pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/2 "2024-06-12T14:22:55Z")

</div>

Have you taken a look at the Plot geo [documentation](https://observablehq.com/plot/marks/geo) page? There is an example halfway down the page.

---

<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:** [June 12, 2024, 2:34pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/3 "2024-06-12T14:34:13Z")

</div>

You don’t really _duplicate_ the features, as JavaScript does a good job of using light references to the same object.

Here’s a light way to do a faceted choropleth:

> **[Faceted choropleth](https://observablehq.com/@fil/faceted-choropleth)**
>
> Unemployment rate by U.S. county, August 2016. Data: Bureau of Labor Statistics. We use the geo mark to paint each county with a color representing the unemployment rate, and render a white mesh of the states boundaries on top. A centroid transform...

(I made random time series, so…)

---

<div class="post-metadata">

**Author:** ![Evan](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/evan/32/276_2.png) [@Evan](https://talk.observablehq.com/u/Evan)\
**Post date:** [June 12, 2024, 3:44pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/4 "2024-06-12T15:44:12Z")

</div>

Excellent, @Fil. I had not realized you could specify a Geo mark that way. I’d suggest showing this way of constructing a choropleth (faceted or not) in the docs or as an example (or maybe I’ve just missed this). This seems like a more natural way of making a choropleth than embedding the data in the feature properties or constructing a Map as a fips based data lookup.

Good point too about the objects not really being copied.

@Cobus I saw that example, but it appears to assume that your geodata and your “other” data are already merged, which I think is an odd assumption for the docs given that the tutorials and templates assume you are starting from a “blank” set of geodata (like the U.S. Map template) to which you will bringing, say, a csv. Unless I’m missing something, the method suggested by that example would require a user to either pull in another library to merge their data to the feature properties or to construct a new geoJSON object by hand.

Also I would suggest that the example is confusing in that it references a `walmart` dataset that is different from the one in other examples. For example, I might expect to be able to copy and paste that example into this notebook and have it work: [Plot: Map small multiples / Observable | Observable](https://observablehq.com/@observablehq/plot-map-small-multiples) but I’m pretty sure it doesn’t.

---

<div class="post-metadata">

**Author:** ![Evan](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/evan/32/276_2.png) [@Evan](https://talk.observablehq.com/u/Evan)\
**Post date:** [June 12, 2024, 5:56pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/5 "2024-06-12T17:56:43Z")

</div>

FWIW - here is a version of that example that might have made more sense to me, and used the `geometry` option.

```auto
Plot.plot({
  margin: 0,
  padding: 0,
  projection: "albers",
  fy: {interval: "10 years"},
  marks: [
    Plot.geo(statemesh, {strokeOpacity: 0.2}),
    Plot.geo(nation),
    Plot.geo(walmarts, {
      geometry: d=> ({
        type: "Point",
        coordinates:[d.longitude, d.latitude]
      }),
      fy: "date", r: 1.5, fill: "blue"}),
    Plot.axisFy({frameAnchor: "top", dy: 30, tickFormat: (d) => `${d.getUTCFullYear()}’s`})
  ]
})

```

---

<div class="post-metadata">

**Author:** ![Cobus](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cobus/32/9670_2.png) [@Cobus](https://talk.observablehq.com/u/Cobus)\
**Post date:** [June 12, 2024, 6:41pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/6 "2024-06-12T18:41:08Z")

</div>

Thanks for sharing this. I do agree that it would be useful to be a bit more explicit about what the `walmarts` data looks like.

---

<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:** [June 12, 2024, 8:15pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/7 "2024-06-12T20:15:25Z")

</div>

For point data you can use Plot.dot directly — no need to construct a geometry for Plot.geo 🙂

Do you by any chance have an interesting dataset that could be used to demonstrate a faceted choropleth? We could use a good example.

---

<div class="post-metadata">

**Author:** ![jwoLondon](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jwolondon/32/259_2.png) [@jwoLondon](https://talk.observablehq.com/u/jwoLondon)\
**Post date:** [June 13, 2024, 3:36pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/8 "2024-06-13T15:36:54Z")

</div>

I like this approach as it results in simpler and easier to manage code than squeezing attributes into the geoJSON properties.

However, I’ve come across one problem: In the normal approach of supplying a geoJSON to `Plot.geo()`, one can encase its options object inside `Plot.centroid` to get tooltips or point-based symbols. But this doesn’t appear to work if one uses your suggested `geometry` element approach.

Is there way to use `Plot.centroid` (which is nice because it is so concise), or would you have to generate centroid coordinates explicitly with, say, d3.polygonCentroid()?

---

<div class="post-metadata">

**Author:** ![mbostock](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mbostock/32/9_2.png) [@mbostock](https://talk.observablehq.com/u/mbostock)\
**Post date:** [June 13, 2024, 9:10pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/9 "2024-06-13T21:10:27Z")

</div>

The centroid transform supports the geometry option. Can you share an example of it not working?

---

<div class="post-metadata">

**Author:** ![jwoLondon](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jwolondon/32/259_2.png) [@jwoLondon](https://talk.observablehq.com/u/jwoLondon)\
**Post date:** [June 14, 2024, 8:16am UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/10 "2024-06-14T08:16:31Z")

</div>

Reassuring to know it should be possible. Most likely a misunderstanding somewhere on my part.

Here is a (non) working example illustrating the problem.

> **[Using the geometry option with Plot.geo](https://observablehq.com/d/4569c4c1560824ff)**
>
> In repsonse to this Observable Forum query To illustrate, here is a dataset showing household access to cars in London over three census periods: And here is the geoJSON of the London boroughs with corresponding borough name stored as feature \`id\`s...

(You can skip directly to the problem at the bottom of the document, but I’ve tried to explain my workings in the content above it).

---

<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:** [June 14, 2024, 11:44am UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/11 "2024-06-14T11:44:22Z")

</div>

Thanks for the example, Jo. You can fix temporarily by re-adding it to the options.

```auto
Plot.plot({
  width: 900,
  height: 320,
  projection: londonProj,
  fx: { label: null },
  marks: [
    Plot.geo(carAccessTidy, {
      ...Plot.centroid({
        fx: "year",
        geometry: "geometry",
        fill: "carAccess",
        opacity: 0.7,
        tip: true
      }),
      geometry: "geometry" // ✨
    })
  ]
})

```

A more generic fix in [fix centroid/geocentroid with tips by Fil · Pull Request #2086 · observablehq/plot · GitHub](https://github.com/observablehq/plot/pull/2086)

---

<div class="post-metadata">

**Author:** ![jwoLondon](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jwolondon/32/259_2.png) [@jwoLondon](https://talk.observablehq.com/u/jwoLondon)\
**Post date:** [June 14, 2024, 11:59am UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/12 "2024-06-14T11:59:56Z")

</div>

Thanks Fil, both for the workaround and fix. Glad I wasn’t doing something stupid.

---

<div class="post-metadata">

**Author:** ![Evan](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/evan/32/276_2.png) [@Evan](https://talk.observablehq.com/u/Evan)\
**Post date:** [June 21, 2024, 3:33pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/13 "2024-06-21T15:33:51Z")

</div>

Hi Fil,

This isn’t the dataset that generated this question, but it is one I had on hand and that is publicly available: [Plot Faceted Choropleth / Evan Galloway | Observable](https://observablehq.com/@gallowayevan/plot-faceted-choropleth).

Thanks again for your always excellent help.

Best,  
Evan

---

<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:** [June 21, 2024, 4:04pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/14 "2024-06-21T16:04:40Z")

</div>

Thanks! There is a small difference between the two approaches that we have to be aware of, wrt non-available data. When you map “from the features” you can style N/A as grey with, say, specifying the **unknown** option of the color scale to be gray. When you map from the data, every feature must be present in the dataset (and in each facet), otherwise you get holes in the map. (The problem can be solved by different means: by laying out a gray background on the whole map, or by making a full join of some sort.)

---

<div class="post-metadata">

**Author:** ![Evan](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/evan/32/276_2.png) [@Evan](https://talk.observablehq.com/u/Evan)\
**Post date:** [June 21, 2024, 5:01pm UTC](https://talk.observablehq.com/t/faceting-a-choropleth/9387/15 "2024-06-21T17:01:12Z")

</div>

Thanks! Good point. I added your note to the notebook.
