# Sorting facets in Plot

**URL:** <https://talk.observablehq.com/t/sorting-facets-in-plot/5581>\
**Category:** Help\
**Created:** [September 16, 2021, 3:53pm UTC](https://talk.observablehq.com/t/sorting-facets-in-plot/5581 "2021-09-16T15:53:58Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![floatingpurr](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/floatingpurr/32/5572_2.png) [@floatingpurr](https://talk.observablehq.com/u/floatingpurr)\
**Post date:** [September 16, 2021, 3:53pm UTC](https://talk.observablehq.com/t/sorting-facets-in-plot/5581/1 "2021-09-16T15:53:58Z")

</div>

In this experiment, I’m trying use Plot to chart cumulative percentages of fully vaccinated people in different areas of Italy.

> **[Milestones of Covid vaccination in Italy](https://observablehq.com/d/5bd94815a8d368b7)**
>
> Data Raw Processing Helpers Appendix

I’m wondering if there is a way to sort facets:

1. by **highest milestone** (i.e., dots in chart)  
_then, in case of equal milestones_
2. by **milestone date**  
_then, if dates are equal too_
3. by **area name**.

E.g., Given the following data:

```auto
[
{area: "ABR", date: 2021-04-26, milestone: 0.1},
{area: "ABR", date: 2021-05-21, milestone: 0.2},
{area: "ABR", date: 2021-07-19, milestone: 0.5},
{area: "ABR", date: 2021-08-26, milestone: 0.7},
{area: "BAS", date: 2021-04-21, milestone: 0.1},
{area: "BAS", date: 2021-05-22, milestone: 0.2},
{area: "BAS", date: 2021-07-24, milestone: 0.5},
{area: "BAS", date: 2021-09-04, milestone: 0.7},
{area: "CAL", date: 2021-04-30, milestone: 0.1},
{area: "CAL", date: 2021-05-27, milestone: 0.2},
{area: "CAL", date: 2021-07-23, milestone: 0.5},
]

```

The facet sorting should be: **ABR, BAS, CAL**

---

<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 16, 2021, 7:01pm UTC](https://talk.observablehq.com/t/sorting-facets-in-plot/5581/2 "2021-09-16T19:01:06Z")

</div>

Since Plot 0.2 you can add

```auto
Plot.dot(data, {
  x: "date",
  sort: {fy: "x", reduce: "max"},
  …
})

```

which will do the point #1 (you can even remove `reduce: "max"` since it’s the default reduce). For more complex sorting you could do:

```auto
Plot.dot(data, {
  x: "date",
  sort: {fy: "data", reduce: f},
  …
})

```

where _f_ is a function of the data. See [allow sort to reduce data by mbostock · Pull Request #517 · observablehq/plot · GitHub](https://github.com/observablehq/plot/pull/517) for details. I don’t think we’re supporting a more complex sorting from inside the mark—for this you’d have to compute the order you want outside (with [d3.groupSort](https://observablehq.com/@d3/d3-groupsort), possibly).

---

<div class="post-metadata">

**Author:** ![floatingpurr](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/floatingpurr/32/5572_2.png) [@floatingpurr](https://talk.observablehq.com/u/floatingpurr)\
**Post date:** [September 17, 2021, 11:22am UTC](https://talk.observablehq.com/t/sorting-facets-in-plot/5581/3 "2021-09-17T11:22:25Z")

</div>

Thank you @Fil for your feedback. Trying with:

```auto
    Plot.dot(data, {
      sort: { fy: "x", reduce: 'max' },
      x: "date",
      title: "milestone",
      fill: (d) => color(d.milestone)
    })

```

I get this:

 ![foo](https://canada1.discourse-cdn.com/flex030/uploads/observablehq/original/2X/d/d33564991740183f51f0910cace24f96a51c5f94.png)

So close, except for the first three facets that should be placed at bottom of the chart. Looking inside the code, it looks like this happens because the reducer sorts facets according to the max date in each series, regardless of the milestone value for such a date.

Even using `reduce: f`, I can only access to dates and not to their milestone values.

When you said:

> I don’t think we’re supporting a more complex sorting from inside the mark—for this you’d have to compute the order you want outside (with [d3.groupSort](https://observablehq.com/@d3/d3-groupsort), possibly).

did you mean sorting data in advance and then passing them to Plot?

---

<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 17, 2021, 12:10pm UTC](https://talk.observablehq.com/t/sorting-facets-in-plot/5581/4 "2021-09-17T12:10:33Z")

</div>

In your case you can do the following:

```auto
      sort: {
        fy: "data",
        reduce: (group) => [
          1 - d3.max(group, (d) => d.milestone), // milestone as a POSITIVE number
          d3.max(group, (d) => +d.date), // date as a number
          group[0].area
        ].join('/') // joined as a comparable string!
      }

```

The ideal (most semantic) version would be:

```auto
      sort: {
        fy: "data",
        reduce: (group) => [
          -d3.max(group, (d) => d.milestone), // numeric, reversed
          d3.max(group, (d) => d.date), // date
          group[0]["area"]
        ]
      }

```

without the “join” that creates a comparable string from the array — so in case of equality on the first element of the array (which would stay numeric), the second element would be used to separate, etc. But we can’t do this since Plot uses d3.ascending, which doesn’t do array comparisons.

Equivalently, you could write, in the definition of the _fy_ scale:

```auto
domain: d3.groupSort(
  data,
  (group) =>
    [
      1 - d3.max(group, (d) => d.milestone),
      d3.max(group, (d) => +d.date),
      group[0]["area"]
    ].join("/"),
  (d) => d.area
)

```

---

<div class="post-metadata">

**Author:** ![floatingpurr](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/floatingpurr/32/5572_2.png) [@floatingpurr](https://talk.observablehq.com/u/floatingpurr)\
**Post date:** [September 17, 2021, 12:54pm UTC](https://talk.observablehq.com/t/sorting-facets-in-plot/5581/5 "2021-09-17T12:54:46Z")

</div>

Thank you @Fil, very neat!

Just a remark for those who’ll read this thread:

> Even using `reduce: f`, I can only access to dates and not to their milestone values.

I was mistaken, it depends on the channel you are passing.
