Skip to content

Sankey Tree

ts
const layerSpacing = 64;
const internalSpacing = 2;

const classColor = {
  First: gf.color6[0],
  Second: gf.color6[1],
  Third: gf.color6[2],
  Crew: gf.color6[3],
};

gf.Frame([
  gf.StackX({ spacing: layerSpacing, alignment: "middle" }, [
    gf.StackY(
      { spacing: 0, alignment: "middle" },
      gf.For(_.groupBy(titanic, "class"), (items, cls) =>
        gf
          .rect({
            w: 40,
            h: _(items).sumBy("count") / 10,
            fill: gf.neutral,
          })
          .name(`${cls}-src`)
      )
    ),
    gf.StackY(
      { spacing: internalSpacing, alignment: "middle" },
      gf.For(_.groupBy(titanic, "class"), (items, cls) =>
        gf.StackX({ spacing: layerSpacing, alignment: "middle" }, [
          gf
            .StackY(
              { spacing: 0, alignment: "middle" },
              gf.For(_.groupBy(items, "sex"), (items, sex) =>
                gf
                  .rect({
                    w: 40,
                    h: _(items).sumBy("count") / 10,
                    fill: classColor[cls],
                  })
                  .name(`${cls}-${sex}-src`)
              )
            )
            .name(`${cls}-tgt`),
          gf.StackY(
            {
              h: _(items).sumBy("count") / 10,
              spacing: internalSpacing * 2,
              alignment: "middle",
            },
            gf.For(_.groupBy(items, "sex"), (items, sex) =>
              gf.StackX({ spacing: layerSpacing, alignment: "middle" }, [
                gf
                  .StackY(
                    {
                      spacing: 0,
                      alignment: "middle",
                    },
                    gf.For(
                      _.groupBy(items, "survived"),
                      (survivedItems, survived) =>
                        gf
                          .rect({
                            w: 40,
                            h: _(survivedItems).sumBy("count") / 10,
                            fill:
                              sex === "Female" ? gf.color6[4] : gf.color6[5],
                          })
                          .name(`${cls}-${sex}-${survived}-src`)
                    )
                  )
                  .name(`${cls}-${sex}-tgt`),
                gf.StackY(
                  {
                    w: 40,
                    spacing: internalSpacing * 4,
                    alignment: "middle",
                  },
                  gf.For(
                    _.groupBy(items, "survived"),
                    (survivedItems, survived) => {
                      return gf
                        .rect({
                          h: _(survivedItems).sumBy("count") / 10,
                          fill:
                            sex === "Female"
                              ? survived === "No"
                                ? gf.gray
                                : gf.color6[4]
                              : survived === "No"
                                ? gf.gray
                                : gf.color6[5],
                        })
                        .name(`${cls}-${sex}-${survived}-tgt`);
                    }
                  )
                ),
              ])
            )
          ),
        ])
      )
    ),
  ]),
  gf.For(_.groupBy(titanic, "class"), (items, cls) => [
    gf.ConnectX(
      {
        fill: classColor[cls],
        interpolation: "bezier",
        opacity: 0.7,
      },
      [gf.ref(`${cls}-src`), gf.ref(`${cls}-tgt`)]
    ),
    gf.For(_.groupBy(items, "sex"), (sexItems, sex) => [
      gf.ConnectX(
        {
          fill: sex === "Female" ? gf.color6[4] : gf.color6[5],
          interpolation: "bezier",
          opacity: 0.7,
        },
        [gf.ref(`${cls}-${sex}-src`), gf.ref(`${cls}-${sex}-tgt`)]
      ),
      gf.For(_.groupBy(sexItems, "survived"), (survivedItems, survived) =>
        gf.ConnectX(
          {
            fill:
              sex === "Female"
                ? survived === "No"
                  ? gf.gray
                  : gf.color6[4]
                : survived === "No"
                  ? gf.gray
                  : gf.color6[5],
            interpolation: "bezier",
            opacity: 0.7,
          },
          [
            gf.ref(`${cls}-${sex}-${survived}-src`),
            gf.ref(`${cls}-${sex}-${survived}-tgt`),
          ]
        )
      ),
    ]),
  ]),
]).render(root, { w: 500, h: 400 });