Skip to content

Charts inside slats

A slat can hold a Plot of its own. The inner Plot draws inside that slat, on the same scale as everything else, and its own slats behave like the slats of any other Plot. This one idea gives you stacked bars, grouped bars, heatmaps and more.

Stacked bars

Each day’s slat holds a Plot with overlap, which puts all of that Plot’s slats in the same space instead of stacking them, so its Bars line up end to end. stackUp works out where each piece starts and ends.

Mon
Tue
Wed
import { createMemo } from "solid-js";
import { Chart, Plot, Bar, Label, stackUp } from "@bezda/rhp";

// Where each day's hours go: one Bar per activity, stacked in one band.
const COLORS = ["#2a78d6", "#1baf7a", "#eb6834"];

export default function Hours() {
  return (
    <Chart scale={[0, 24]} ticks={[0, 6, 12, 18, 24]}>
      <Plot
        day={["Mon", "Tue", "Wed"]}
        hours={[
          [8, 8, 8],
          [7, 9, 8],
          [8, 6, 10],
        ]}
      >
        {(d) => {
          // { from: [0, 8, 16], to: [8, 16, 24] }
          const stack = createMemo(() => stackUp(d.hours));
          return (
            <div>
              <Label edge="start">{d.day}</Label>
              <Plot
                overlap
                from={stack().from}
                to={stack().to}
                color={COLORS}
              >
                {(part) => (
                  <Bar
                    from={part.from}
                    to={part.to}
                    color={part.color}
                  />
                )}
              </Plot>
            </div>
          );
        }}
      </Plot>
    </Chart>
  );
}

Grouped bars

Without overlap, the inner Plot divides the day’s thickness between its own slats, one thin slat per item: three bars per team.

North
East
South
import { Chart, Plot, Bar, Label, slat } from "@bezda/rhp";

// Medals per team: each team's slat holds a Plot of three bars.
const COLORS = ["#d4a72c", "#98a1ab", "#b8733b"];
const Team = slat({ thickness: 60 }, (d) => (
  <div>
    <Label edge="start">{d.team}</Label>
    <Plot count={d.medals} color={COLORS}>
      {(m) => (
        <div>
          <Bar to={m.count} color={m.color} />
        </div>
      )}
    </Plot>
  </div>
));

export default function Medals() {
  return (
    <Chart scale={[0, 20]}>
      <Plot
        team={["North", "East", "South"]}
        medals={[
          [12, 9, 14],
          [8, 15, 6],
          [17, 11, 9],
        ]}
      >
        {Team}
      </Plot>
    </Chart>
  );
}

Across the slat

orientation="across" turns the inner Plot the other way: its slats run along the scale instead of stacking. That’s how the heatmap puts one cell per hour in each day’s slat.

Tips

  • An inner Plot gets its data from d: pass it d.hours, d.medals and so on.
  • Work out derived data once per slat with createMemo, as the stacked example does with stackUp.
  • thick on an inner Plot makes it use part of the slat’s thickness: thick={0.5} is half.