Skip to content

Data

A slat is a function of one row of your data. That row arrives as d, so the slat reads d.name, d.value, and so on. You can give a Plot its data in three ways, and mix them.

Lists, shared values and functions

Every prop you give a Plot is data for its slats, apart from the settings it already knows (order, key, reorder and the rest):

  • Lists line up by position: the third name, the third number and the third picture belong together, and go to the third slat. The longest list sets how many slats there are.
  • A single value is shared by every slat.
  • A function of d runs once for each slat, and runs again when a value it reads changes, or when the Plot is given a new function.
Oslo
6 °C
Rome
16 °C
Cairo
27 °C
import { Chart, Plot, Bar, Label } from "@bezda/rhp";

export default function Weather() {
  return (
    <Chart scale={[0, 30]}>
      <Plot
        // a list: each slat gets its own entry
        city={["Oslo", "Rome", "Cairo"]}
        temp={[6, 16, 27]}
        // one value: shared by every slat
        unit="°C"
        // a function of `d`: worked out per slat
        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 slat, d.city, d.temp, d.unit and d.warm all read the same way. d also has d.index (the row’s place in the data, from 0) and d.position (the slat’s place on screen once sorted).

Row objects

If your data is already a list of objects, one object per row, pass it as rows. Each object becomes one row, and its fields are what the slat reads: d.city, d.temp and so on.

Oslo
6 °C
Rome
16 °C
Cairo
27 °C
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 use rows together with lists and functions. If a prop and a field have the same name, the slat reads the prop.

Adding and removing rows: keys

By default a slat is tied to a place in the list, not to a row: the first slat shows the first row, the second slat the second row. So if you remove the first city, every slat after it takes the data of the row below, and the whole chart shuffles.

Give the Plot a key, the field that identifies a row, and each slat follows its own city instead. Removing a city now removes that city’s slat, and the others stay where they are.

Click a bar to remove its city.
Oslo
6 °C
Rome
16 °C
Cairo
27 °C
Lima
19 °C
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 slats and blocks that use the changed values update.

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

<Plot fruit={fruits} sold={sold()}>{Fruit}</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 slat.

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 slat 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 slats again, without animation, so it’s never out of date. Only the data you give the Plot is watched. A function of d that reads some other signal, a hovered item for example, runs once and never again, so a chart that reacts to choices like that should not be static.

Helpers that turn raw numbers into what a chart needs

Some charts need their numbers prepared first, and rhp comes with small functions that do it. 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.