Skip to content

Data

Each row gets the data of the thing it shows, as d: d.name, d.value, and so on. You can give a Plot that data in three ways, and mix them.

Lists, shared values and functions

Every prop you give a Plot (other than its settings, such as order) is a piece of data:

  • Lists line up by position: the third name, the third number and the third picture belong together, and go to the third row. The longest list sets how many rows there are.
  • A single value is shared by every row.
  • A function of d is worked out for each row, and again only when what it reads changes.
import { Chart, Plot, Bar, Label } from "@bezda/rhp";

export default function Weather() {
  return (
    <Chart scale={[0, 30]}>
      <Plot
        // a list: each row gets its own entry
        city={["Oslo", "Rome", "Cairo"]}
        temp={[6, 16, 27]}
        // one value: shared by every row
        unit="°C"
        // a function of the row: worked out per row
        warm={(d) => d.temp > 15}
      >
        {(d) => (
          <div>
            <Label edge="start">{d.city}</Label>
            <Bar to={d.temp} color={d.warm ? "negative" : "series-1"} />
            <Label at={d.temp}>
              {d.temp} {d.unit}
            </Label>
          </div>
        )}
      </Plot>
    </Chart>
  );
}

Inside the row, d.city, d.temp, d.unit and d.warm all read the same way. Each row also has d.index (its place in the data, from 0) and d.position (its place on screen once sorted).

Row objects

If your data already keeps each thing’s values together, as a list of objects, pass it as rows. Each object becomes one row, and its fields become d.city, d.temp and so on.

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

const cities = [
  { city: "Oslo", temp: 6 },
  { city: "Rome", temp: 16 },
  { city: "Cairo", temp: 27 },
];

export default function Weather() {
  return (
    <Chart scale={[0, 30]}>
      <Plot rows={cities}>
        {(d) => (
          <div>
            <Label edge="start">{d.city}</Label>
            <Bar to={d.temp} />
            <Label at={d.temp}>{d.temp} °C</Label>
          </div>
        )}
      </Plot>
    </Chart>
  );
}

You can combine rows with lists and functions: a prop wins over a field with the same name.

Adding and removing rows: keys

By default, a row is its number: the first row, the second row. If you remove the first city, every row after it takes the data of the one below, and they all move.

Give the Plot a key, a field that names each row, and a row follows its city instead. Removing a city then removes its row, and the others stay where they are.

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

const all = [
  { city: "Oslo", temp: 6 },
  { city: "Rome", temp: 16 },
  { city: "Cairo", temp: 27 },
  { city: "Lima", temp: 19 },
];

export default function Weather() {
  const [cities, setCities] = createSignal(all);
  const remove = (name) =>
    setCities(cities().filter((c) => c.city !== name));
  return (
    <>
      <div class="demo-controls">
        <span>Click a bar to remove its city.</span>
        <button onClick={() => setCities(all)}>Bring them back</button>
      </div>
      <Chart scale={[0, 30]}>
        <Plot rows={cities()} key="city">
          {(d) => (
            <div>
              <Label edge="start">{d.city}</Label>
              <Bar
                to={d.temp}
                onClick={() => remove(d.city)}
                style={{ cursor: "pointer" }}
              />
              <Label at={d.temp}>{d.temp} °C</Label>
            </div>
          )}
        </Plot>
      </Chart>
    </>
  );
}

key is a field name (key="city") or a function (key={(d) => d.id}).

Data that changes

Pass data that changes as a signal or a store, the way you would in any Solid app. The Plot reads it, and when it changes, only the rows and blocks that use the changed values update.

const [sold, setSold] = createSignal([12, 18, 7]);

<Plot fruit={fruits} sold={sold()}>{Row}</Plot>

setSold([12, 25, 7]); // one bar grows; nothing else is touched

For big lists that change one item at a time, a store is even lighter: setting one item re-runs just that row.

Data that never changes

If a chart’s data is fixed (a report, a printed page, a chart in an article), add static to the Chart:

<Chart static scale={[0, 100]}>…</Chart>

Each row is then drawn once and keeps nothing to watch for changes, so a big chart uses a fraction of the memory: about a sixth for 1,000 bars. Hover styles, themes, resizing and the scale all still work. If the data does change anyway, the chart draws all its rows again, without animation, so it’s never out of date. Only the data you give the Plot is watched, though: a value worked out per row that reads some other signal (a hovered item, say) is read once. Charts that react to choices like that should stay live.

Helpers for common shapes of data

rhp comes with small functions that turn raw numbers into what a chart needs. For example, stackUp turns [8, 8, 8] into where each piece of a stacked bar starts and ends. They’re all in the helpers reference.