Flower Chart
A distribution rendered as a meadow, where each binned count grows a layered flower of colored petals atop a green stem.
ts
import { Constraint, Coord, chart, color, layer, petal, rect, scatter, stack } from "gofish-graphics";
import { catchLocations, seafood } from "./dataset";
const FLOWER_RADIUS = 40;
const stemData = seafood.map((d) => ({
...d,
x: catchLocations[d.lake as keyof typeof catchLocations].x,
}));
const container = document.getElementById("app");
// One flower head: a polar fan of petals, one per species, each as wide
// as that species' count. It has no data of its own, so as a nested mark
// it inherits each lake's rows.
const flower = chart({ coord: Coord.polar(), axes: false })
.flow(stack({ by: "species", dir: "x", h: FLOWER_RADIUS }))
// TODO(#1111): lighten the petals, as the low-level version did.
.mark(petal({ w: "count", fill: "species" }));
// One plant per lake, planted at the lake's x location: a thin green stem
// as tall as the lake's total catch, with the flower centered on its top.
chart(stemData, { axes: false, w: 400, h: 400 })
.flow(scatter({ by: "lake", x: "x" }))
.mark(
layer([
rect({ w: 4, h: "count", fill: color.green[5] }).name("stem"),
flower.name("flower"),
]).relate(({ stem, flower }) => [
Constraint.align({ x: "middle", y: ["end", "middle"] }, [
stem,
flower,
]),
])
)
.render(container);dataset.ts
ts
export type Lakes =
| "Lake A"
| "Lake B"
| "Lake C"
| "Lake D"
| "Lake E"
| "Lake F";
export type CatchData = {
lake: Lakes;
species: "Bass" | "Trout" | "Catfish" | "Perch" | "Salmon";
count: number;
};
export const catchLocations: Record<Lakes, { x: number; y: number }> = {
"Lake A": { x: 5.26, y: 22.64 },
"Lake B": { x: 30.87, y: 120.75 },
"Lake C": { x: 50.01, y: 60.94 },
"Lake D": { x: 115.13, y: 94.16 },
"Lake E": { x: 133.05, y: 50.44 },
"Lake F": { x: 85.99, y: 172.78 },
};
export const catchLocationsArray = Object.entries(catchLocations).map(
([lake, { x, y }]) => ({
lake,
x,
y,
})
);
export const seafood: CatchData[] = [
{
lake: "Lake A",
species: "Bass",
count: 23,
},
{
lake: "Lake A",
species: "Trout",
count: 31,
},
{
lake: "Lake A",
species: "Catfish",
count: 29,
},
{
lake: "Lake A",
species: "Perch",
count: 12,
},
{
lake: "Lake A",
species: "Salmon",
count: 8,
},
// … 25 more rows
];
export const catchData = seafood;
export const catchDataWithLocations = seafood.map((catchItem) => {
const location = catchLocationsArray.find(
(loc) => loc.lake === catchItem.lake
);
return {
...catchItem,
x: location?.x,
y: location?.y,
};
});
export type CatchDataWithLocation = (typeof catchDataWithLocations)[0];