# React data visualizations | No dependencies, just some CSS

How to make simple data plotting with pure CSS. The point I had here was not to
mathematically verify anything, but just to map out the curve and visually
inspect it for any anomalies.

In a previous post about
[getting a random item from an array](/get-random-value-from-array) I used a
helper that churns out random integers. And I got to thinking, how random it
actually is? Is there a way for me to visualize it?

## The graph

There is a way to visualize it, and it’s this random:

[Interactive example](/visualize-data-with-css)

It’s 1000 flexbox divs, not using any graph libs. The divs have a height of:
`occurrence count` \* `10` pixels.

## The random number generators

The
[MDN article on the random method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random)
has an example piece of code to get random integers in a range:

```js
const getRandomIntInclusive = (min, max) => {
  min = Math.ceil(min)
  max = Math.floor(max)

  return Math.floor(Math.random() * (max - min + 1) + min)
}
```

And it says:

> It might be tempting to use `Math.round()` to accomplish that, but doing so
> would cause your random numbers to follow a non-uniform distribution, which
> may not be acceptable for your needs.

So I made a random number generator that uses the `Math.round()`, you can choose
it from the dropdown on the above interactive graph. The distribution of the
values is not shockingly different (at least on this magnitude), the visual
difference isn’t striking.

```js
const getRandomIntRound = (min, max) => {
  min = Math.round(min)
  max = Math.round(max)

  return Math.round(Math.random() * (max - min + 1) + min)
}
```

## Build the random data

The random number functions used here are listed above. But if you don’t need
the min value, it can be made a bit simpler looking:

```js
const getRandomInt = max => Math.floor(Math.random() * max)
```

**I’m making 10 000 random numbers with a range from 0 to 1000**, that should be
enough. Create an array and fill it with randomness:

```js
const randomNumbers = Array.from({ length: 10000 }, () => getRandomInt(1000))
```

Then let’s find out how many times any given random number appears in the array.
The occurrences can be dug out with a simple reduce:

```js
const getOccurrences = array =>
  array.reduce((acc, randomNumber) => {
    acc[randomNumber] = ++acc[randomNumber] || 1
    return acc
  }, {})
```

That returns an object like the one below (truncated), where each key is the
random number, and the value is how many times it occurs in the array:

```js
{
  "0": 8,
  "1": 13,
  "2": 12,
  "3": 9,
  "4": 7,
  "5": 9,
  "6": 9,
  "7": 11,
  "8": 13,
  "9": 11,
  "10": 14,
  "11": 11,
  "12": 10,
  "13": 7,
  "14": 9,
  "15": 3,
  "16": 12,
  "17": 9,
  ...
}
```

From it, you can already see that the distribution looks pretty random.

### Make the sorting UI

Then we need a helper function to sort the data, let’s use `getOccurrences()`
helper here, and remember the generate the random data inside the function, or
the refresh won’t actually get fresh data:

```js
const getRandomData = (isSorted, randomMethod) => {
  // Generate these inside this function so the refresh works.
  const randomNumbers = Array.from({ length: 10000 }, () =>
    randomMethod === 'round'
      ? getRandomIntRound(0, 1000)
      : getRandomIntInclusive(0, 1000)
  )
  const occurrences = getOccurrences(randomNumbers)

  const arr = Object.keys(occurrences).map(x => occurrences[x])

  return isSorted
    ? arr.sort((a, b) => {
        if (a < b) return -1
        if (a > b) return 1
        return 0
      })
    : arr
}
```

## Render the graph

I’m using styled-components here, but you-do-you.

The refreshing is kind of interesting: React re-renders a component if you
update its state, but in this case there’s not really a change to be made, so
I’m updating a state that uses itself. Also, the random data needs to be
generated inside the `getRandomData` helper.

The other click listeners is for the sort and the select:

```js {29,30,47,48}
const Bar = styled.div(props => ({
  alignItems: 'flex-end',
  backgroundColor: 'Gray',
  height: props.elementHeight * 10 + 'px',
  width: '0.1%',
}))

const Wrap = styled.div({
  border: '1px solid var(--gray)',
  marginBottom: '20px',
  padding: '10px',
})

const Container = styled.div({
  alignItems: 'flex-end',
  display: 'flex',
  height: '240px',
  marginBottom: '10px',
  width: '100%',
})

const Button = styled.button({
  marginRight: '10px',
})

const Chart = ({ shouldSort }) => {
  const [isSorted, setIsSorted] = React.useState(shouldSort)
  const [remountCount, setRemountCount] = React.useState(0)
  const [randomMethod, setRandomMethod] = React.useState('normal')
  const refresh = () => setRemountCount(remountCount + 1)

  const handleSort = () => {
    setIsSorted(prev => !prev)
  }

  const handleChange = event => {
    setRandomMethod(event.target.value)
  }

  return (
    <Wrap>
      <Container>
        {getRandomData(isSorted, randomMethod).map((key, index) => (
          <Bar key={index} elementHeight={key} />
        ))}
      </Container>
      <Button onClick={refresh}>Refresh</Button>
      <Button onClick={handleSort}>{isSorted ? 'Unsort' : 'Sort'}</Button>
      <select onChange={handleChange}>
        <option value='ceil-floor'>With ceil/floor</option>
        <option value='round'>With round</option>
      </select>
    </Wrap>
  )
}
```

That's it pretty much.

## Conclusions

Could totally render the graph onto a canvas, would be faster and better.

The results here weren’t that interesting, the `Math.round()` randomness doesn’t
look that different (or maybe I’m just mangling the data in a wrong way..). This
was a bit pointless, but kind of fun.
