Itâs a general technique thatâs commonly used in data processing. I can give a toy example here. Lets say we have a list of people with their eye colors.
people = [
{name: "Alex", eye: "blue"},
{name: "Brianna", eye: "green"},
{name: "Charles", eye: "brown"},
{name: "Davis", eye: "green"},
];
And then lets say we want to have a bar chart showing how common each eye color is.
Plot.plot({
marks: [Plot.barY(people, Plot.groupX({ y: "count" }, { x: "eye" }))]
})
But this would leak private data of names. Instead, we could make a derived data set:
derived = Object.fromEntries(
d3.rollup(
people,
(ds) => ds.length,
(d) => d.eye
)
)
That would produce the value
[
{"color":"blue","count":1},
{"color":"green","count":2},
{"color":"brown","count":1}
]
You can then choose âDownload JSONâ on that cell to get that output.
You can then use that derived data set as an attachment in a brand new notebook.
Plot.plot({
marks: [
Plot.barY(await FileAttachment("derived
.json").json(), {
x: "color",
y: "count"
})
]
})
That new notebook will produce the same output, but wonât reveal the private data.
Of course, the process of producing the intermediate data is going to depend on your exact situation. It also wonât update as the original source data changes, since it is of course just a snapshot.