🏠 back to Observable

Plot : formatting numerical values computed by a transform in text mark

Starting from an example from the Group transform notebook, I’m trying to add numeric values to a faceted stacked bar chart. This works great, but if I want to show proportions intead of count, I don’t know how I could format them to be displayed, say, as percentages. As the values are computed by a transform, I don’t know how to apply formatting to them.

Here is the plot code.


Plot.plot({
  y: {
    grid: true,
    percent: true
  },
  marks: [
    Plot.barY(penguins, Plot.groupX({y: "proportion"}, {x: "species", fill: "sex"})),
    Plot.textY(penguins, Plot.stackY(Plot.groupX({y: "proportion", text: "proportion"}, {x: "species", z: "sex"}))),
    Plot.ruleY([0])
  ]
})

Also available in this notebook : Untitled / juba / Observable

Thanks !

1 Like

Each channel (such as x, y, fill or, most importantly, text) can be specified by a function. Strings (such as "proportion") simply point to some commonly used function for convenience. It’s usually not too hard to roll your own, though.

Try this for the text channel:

text: (d) => d3.format("0.2%")(d.length / penguins.length)

Here’s the result:


Having said that, it’s just a matter of time before @Fil points out an easier, built in approach. :slight_smile:

2 Likes

So that means that when in a Group transform, the function is applied to the data from the current group. I didn’t know that, it can be really useful, thanks !

1 Like

You could use Plot.map :slight_smile:

format = d3.format(".1%")
Plot.textY(
      penguins,
      Plot.map({ text: (data) => data.map(format) },
        Plot.stackY(
          Plot.groupX(
            { y: "proportion", text: "proportion" },
            { x: "species", z: "sex" }
          )
        )
      )
    )
2 Likes

Perhaps, but I’m not sure that’s always the case. I think it can be tricky to figure out exactly what that argument is when using some sort of transform. To figure it out, I used the following intermediate step:

text: (d) => {console.log(d); return "temp"}

At that point, the labels were all temp but I could check the console to see the value of d. Then, it was pretty easy to write the function.

1 Like

Great, now I’ve got a solution and I better understand what map can be useful for. Composing transforms is very powerful, but I’m not completely used to this yet (and it is an approach which seems quite different from, say, ggplot2 in R).

Thanks !

1 Like