Skip to content

Charts inside rows

A row can hold a Plot of its own. That inner Plot draws inside the row, on the same scale, and its rows follow the same rules as any other. This one idea gives you stacked bars, grouped bars, heatmaps and more.

Stacked bars

Each day’s row holds a Plot with overlap: its rows share the day’s band instead of stacking, so its Bars line up end to end. stackUp works out where each piece starts and ends.

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

// Where each day's hours go. A day's bar is a Plot of its own: 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 splits the row’s band, one thin row per item: three bars per team.

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

// Medals per team: a team's row holds a Plot of three bars, one per
// medal.
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 row

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

Tips

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