Skip to content

Bar Chart Tutorial

Simple bar chart

In this tutorial, we will add a simple bar chart to our project. For simplicity, we assume a project setup similar to what you might get with CRA or Vite.

To build our bar chart, we will use the <SegmentPlot> component from @bezda/rhp-core. As far as props go, this component only requires a width and height prop. However, it does expect a <PlotContext.Provider> somewhere in the component tree above it which means that you also need the variables the provider requires. This specific context provider expects five observables (see PlotContext.Provider section of the State Management guide for more details).

Putting it together, we have something like this:

  import { useContext } from 'react';
  import { useObservable } from '@legendapp/state/react';
  import { PlotContext, SegmentPlot } from '@bezda/rhp-core';
  import type { Vars } from '@bezda/rhp-core';

  const App = () => {

    // Create plot state variables (observables) that the context provider requires.
    // The PlotContext.Provider will provide these variables to all child components.
    const plotData = useObservable([[10], [4], [6], [7]]);
    const vars = useObservable({
      "color": ["var(--sl-color-text)"],  
      "bar-label": ["A"],
    } as Vars);
    const dataMax = useObservable(10);

    // You can create/use global state variables if you desire
    const { theme, orientation } = useContext(PlotContext);

    // The SegmentPlot component requires only a width and height prop.
    return (
      <PlotContext.Provider value={{ plotData: plotData, dataMax: dataMax, orientation: orientation, theme: theme, vars: vars }}>
        <SegmentPlot
          width="560px"
          height="360px"
        />
      </PlotContext.Provider>
    )
  }

  export default App;

In the above, we create our plotData, vars, and dataMax observables as local (to the App component) observables using the useObservable hook from @legendapp/state/react and we get/create the remaining theme and orientation observables from global PlotContext. We give the local observables some initial data. Note that we are not providing a template to the <SegmentPlot> component and so it will use a built-in default template. The default template expects two variables from vars: color and bar-label. For color, we provide a css variable so that the bars and lines in the chart match the global theme. We set the labels next to each bar to “A” for now.

Adding a template

To add a template, we first create/get an array of type FullBarElementType[] and pass it to <SegmentPlot> using the segmentTemplate prop.

  import { useContext } from 'react';
  import { useObservable } from '@legendapp/state/react';
  import { PlotContext, SegmentPlot } from '@bezda/rhp-core';
  import type { Vars } from '@bezda/rhp-core';

  // Get template
  import { myTemplate } from './templates';

  const App = () => {

    // Create plot state variables (observables) that the context provider requires.
    // The PlotContext.Provider will provide these variables to all child components.
    const plotData = useObservable([[10], [4], [6], [7]]);
    const vars = useObservable({
      "color": ["var(--sl-color-text)"],  
      "bar-label": ["A"],
    } as Vars);
    const dataMax = useObservable(10);

    // You can create/use global state variables if you desire
    const { theme, orientation } = useContext(PlotContext);

    // The SegmentPlot component requires only a width and height prop.
    return (
      <PlotContext.Provider value={{ plotData: plotData, dataMax: dataMax, orientation: orientation, theme: theme, vars: vars }}>
        <SegmentPlot
          width="560px"
          height="360px"
          segmentTemplate={myTemplate}
        />
      </PlotContext.Provider>
    )
  }

  export default App;

Customizing appearance

While one could build a full template from scratch, it is often easier and quicker to start with a template that is close to what you want and then make small changes to it. In this tutorial, we will do just that. We will start with a template used for some of the bar chart examples and demos in the Guide and Get Started sections of this documentation.

First, we should remove the texts that says “block” from the decorations and bars along with most of the related hover effects and transitions. We can also remove the rounded borders from the decorations and adjust spacing.

Of course, css and markup allow many ways to achieve the same visual result. In the template above, we center the label text and the bar value text vertically and horizontally using flexbox. To center the decoration text while keeping the previous dimensions of the decorations we wrap each piece of text in an extra div. We also add opacity: 0; transition: opacity 0.4s ease-in-out;.full-bar:hover & {opacity: 1;} to the decoration that shows the bar’s data value so that it is invisible by default and becomes visible when the bar is hovered over.

Now we want the bar labels to show different text for each bar. We can do that by changing "bar-label": ["A"] to "bar-label": ["A", "B", "C", "D"] in the vars data object:

Bars of different colors

With a few simple changes, we can have each of the bars be a different color. First, we change the value of the color variable in the vars object. We can choose any color we want in any format that css supports. We can also use css variables which can be handy if you want to match your project’s theme. In this tutorial, we will change it from ["var(--sl-color-text)"] to ["red", "blue", "green", "yellow", "purple"].

Its not very conventional to have the entire core-component take on the new color. We can change the color of the <Decoration> that contains the label and line segment that forms part of the zero-axis line. To do this, we first make a change to the template. We change the markup in the last decoration object to use a different variable (lets call it label-color) and then we add the label-color variable to the vars object.

To summarize, we changed "color": ["var(--sl-color-text)"] to "color": ["red", "blue", "green", "yellow"] to change the colors used by each core-component. Then we changed {{color}} to {{label-color}} in the last markup property (at the end/bottom of the template) and then finally, we added "label-color": ["var(--sl-color-text)"] to the vars data object.