A Basic Chart - Building a Geospacial App with SvelteKit, Deck.gl, and Mapbox - Part 4
Published: 2022-07-13 21:32:43

---
series: Building a Geospacial App with SvelteKit, Deck.gl, and Mapbox
---

We are going to add a D3.js bar chart that will interact with our geospacial data.

The [Building a Geospacial App](http://vis.academy/#/building-a-geospatial-app/4-a-basic-chart) tutorial uses a data visualization library called React-Vis. Apparently React and D3 do not work together very easily, so you will see some data visualization libraries that combine React and D3 to make it easier for developers to incorporate D3 into a React app. Since we are using Svelte we don't have that problem and we can use D3 (along with all of its power and customizability) directly.

Svelte and D3 work really well together. However, to optimize the relationship between Svelte and D3 it is important to understand some basic concepts about these two great pieces of software. Please read this (short) post titled [Making Visualizations Literally with Svelte & D3](https://www.connorrothschild.com/post/svelte-and-d3) and then come back here.

# Update the `processData()` function
In your `index.svelte` file, find the `processData()` function and update it to look like this:

```js
function processData() {
  let data = taxiData.reduce(
    (accu, curr) => {
      let pickupHour = new Date(curr.pickup_datetime).getUTCHours();
      let dropoffHour = new Date(curr.dropoff_datetime).getUTCHours();

      let pickupLongitude = Number(curr.pickup_longitude);
      let pickupLatitude = Number(curr.pickup_latitude);

      if (!isNaN(pickupLongitude) && !isNaN(pickupLatitude)) {
        accu.points.push({
          position: [pickupLongitude, pickupLatitude],
          hour: pickupHour,
          pickup: true
        });
      }

      let dropoffLongitude = Number(curr.dropoff_longitude);
      let dropoffLatitude = Number(curr.dropoff_latitude);

      if (!isNaN(dropoffLongitude) && !isNaN(dropoffLatitude)) {
        accu.points.push({
          position: [dropoffLongitude, dropoffLatitude],
          hour: dropoffHour,
          pickup: false
        });
      }

      let prevPickups = accu.pickupObj[pickupHour] || 0;
      let prevDropoffs = accu.dropoffObj[dropoffHour] || 0;

      accu.pickupObj[pickupHour] = prevPickups + 1;
      accu.dropoffObj[dropoffHour] = prevDropoffs + 1;

      return accu;
    },
    {
      points: [],
      pickupObj: {},
      dropoffObj: {}
    }
  );

  data.pickups = Object.entries(data.pickupObj).map(([hour, count]) => {
    return { hour: Number(hour), x: Number(hour) + 0.5, y: count };
  });
  data.dropoffs = Object.entries(data.dropoffObj).map(([hour, count]) => {
    return { hour: Number(hour), x: Number(hour) + 0.5, y: count };
  });
    
  taxiDataset = data;
}
```

Now find the `pointsArray` declaration and replace this:

```js
let pointsArray = [];
```

...with this:

```js
let taxiDataset = {
  points: [],
  pickups: [],
  pickupObj: {},
  dropoffs: [],
  dropoffObj: {}
};
```

Now find the `renderLayers` reactive property:

```js
$: renderLayers({ data: pointsArray, settings: settings });
```

...and update it to look like this:

```js
$: renderLayers({ data: taxiDataset.points, settings: settings });
```

It looks like there is a lot going on in the `processData()` function. It is just formatting the `taxiData` into an object that is shaped like the `taxiDataset` object that you used to replace the `pointsArray` variable. 

* The `points` property holds the scatterplot data, which will show how the distance and time of the trips are correlated.
* The `pickupObj` property holds the number of pickups by hour.
* The `pickups` property holds the x and y values of the pickup bars in the bar chart.
* The `dropoffObj` property holds the number of dropoffs by hour.
* The `dropoffs` property holds the x and y values of the dropoff bars in the bar chart.


# Create the bar chart container
Create a new file inside your `/src/components` directory and name it `BarChart.svelte`. Paste the following code inside:

```vue
<div class="bar-chart">
  <h2>Pickups by hours</h2>
</div>

<style>
  .bar-chart {
    position: absolute;
    left: 10px;
    bottom: 10px;
    z-index: 100;
    width: 500px;
    height: 210px;
    padding: 10px;
    background-color: white;
    border-radius: 3;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
    font-size: 12px;
    line-height: 1.833;
  }
</style>
```

Now in your `index.svelte` file, import that `BarChart` component:

```js
import BarChart from "$/components/BarChart.svelte";
```

...and include it inside the `<div>` tag in your HTML as the last element/component in the `<div>` tag, like this:

```html
<div class="deck-container">
  {#if hover.hoveredObject}
    <div class="tooltip" style:transform={`translate(${hover.x}px, ${hover.y}px)`}>
      <div>{hover.label}</div>
    </div>
  {/if}
  <MapStylePicker currentStyle={mapStyle} on:change={handleStyleChange}/>
  <LayerControls {settings} controls={CONTROLS} on:layerSettingsChange={updateLayerSettings} />
  <div id="map" bind:this={mapElement}></div>
  <canvas id="deck-canvas" bind:this={canvasElement}></canvas>
  <BarChart />
</div>
```

Make sure to save your files and refresh your browser, if necessary, to see the box for your bar chart.


# Create the bar chart
First, we are going to create a simple bar chart of pickups by hour.

To do this, we are going to use the `taxiDataset.pickups` variable we prepared above. This is an array of objects of the form `{hour: 0, x: 0.5, y: 246}`. Each `x` is going to be the x-coordinate of the corresponding bar and each `y` is going to be y-coordinate of the corresponding bar for the pickups we want to plot.

We are going to create the bar chart by coding SVG elements, which are similar to HTML elements, directly into the HTML portion of our `BarChart.svelte` component.

In your `BarChart.svelte` file, update the HTML as follows:

TODO: Finish the rest of this tutorial.

```html

```