Implement A Bubble Chart Using Vega In ReactJS

Introduction

This article demonstrates how to create and use bubble chart using vega in reactjs. This article starts with the introduction of the react-vega package. After that, it demonstrates how vega json file works for creating any chart using its json formatted data.

What is Vega?

Vega is a visualization grammar, a declarative language for creating, saving, and sharing interactive visualization designs.With Vega, you can describe the visual appearance and interactive behavior of a visualization in a JSON format, and generate web-based views using Canvas or SVG.

Reference from: Learn more about Vega here

To achieve this feature we will use a npm package npm i react-vega using this you can modify the JSON file and create it according to your requirement.

Prerequisites

  • Basic knowledge of ReactJS
  • Visual Studio Code
  • Node and NPM installed

Step 1. Install NPM dependencies Create a React.js Project

Let's create a new React project by using the following command.

npx create-react-app react-bubblechart

Step 2. Install NPM dependencies

npm i react-vega

Step 3. Creating a Component

Now go to the src folder and create a new folder for bubble chart and inside it create a component, 'bubble-chart.js'. Add the following code to this component.

import React from "react";
import { Vega } from "react-vega";
import bubblechart from "./bubblechart.json";
import "./_bubblechart.css";


export const PackedBubbleChart = () => {
  const option = {
    $schema: "https://vega.github.io/schema/vega/v5.json",
    autosize: "pad",
    width: 700,
    height: 200,
    signals: [
      { name: "cx", update: "width / 2.5" },
      { name: "cy", update: "height / 2.5" },
      {
        name: "gravityX",
        value: 0.4,
      },
      {
        name: "gravityY",
        value: 0.4,
      },
      {
        name: "selected",
        value: "",
        on: [{ events: "mouseover", update: "datum" }],
      },
      {
        name: "legend",
        update: 'vlSelectionResolve("bubbleChart_store", "union", true, true)',
      },
      {
        name: "legend_tuple_fields",
        value: [{ type: "E", field: "category" }],
      },
      {
        name: "legend_category_legend",
        value: null,
        on: [
          {
            events: [
              {
                source: "view",
                type: "mouseover",
                markname: "category_legend_symbols",
              },
              {
                source: "view",
                type: "mouseover",
                markname: "category_legend_labels",
              },
              {
                source: "view",
                type: "mouseover",
                markname: "category_legend_entries",
              },
            ],
            update: "datum.value || item().items[0].items[0].datum.value",
            force: true,
          },
          {
            events: [{ source: "view", type: "mouseover" }],
            update: "!event.item || !datum ? null : legend_category_legend",
            force: true,
          },
        ],
      },
      {
        name: "legend_tuple",
        update:
          "legend_category_legend !== null ? {fields: legend_tuple_fields, values: [legend_category_legend]} : null",
      },
      {
        name: "legend_toggle",
        value: false,
        on: [
          {
            events: { merge: [{ source: "view", type: "click" }] },
            update: "event.shiftKey",
          },
        ],
      },
      {
        name: "legend_modify",
        on: [
          {
            events: { signal: "legend_tuple" },
            update:
              'modify("bubbleChart_store", legend_toggle ? null : legend_tuple, legend_toggle ? null : true, legend_toggle ? legend_tuple : null)',
          },
        ],
      },
    ],
    data: [
      { name: "bubbleChart_store" },
      {
        name: "table",
        values: bubblechart,
      },
    ],
    scales: [
      {
        name: "size",
        domain: { data: "table", field: "value" },
        range: [150, 400],
      },
      {
        name: "color",
        type: "ordinal",
        domain: [
          "Information Technology",
          "Industrials",
          "Health Care",
          "Consumer Discretionary",
          "Communication Services",
          "Financials",
          "Real Estate",
          "Materials",
          "Consumer Staples",
          "Utilities",
          "Energy",
        ],
        range: [
          "#724bc3",
          "#b14891",
          "#c981b2",
          "#ff736a",
          "#ff9831",
          "#189d3e",
          "#34c768",
          "#8ce8ad",
          "#35a4e8",
          "#87d3f2",
          "#27acaa",
        ],
      },
    ],
    marks: [
      {
        type: "group",
        name: "concat_0_group",
        signals: [
          {
            name: "mouse__move",
            on: [
              {
                events: [
                  {
                    source: "scope",
                    type: "mouseover",
                  },
                ],
                update:
                  'datum && item().mark.marktype !== \'group\' ? {unit: "concat_0", fields: recentTransaction_name, values: [(item().isVoronoi ? datum.datum : datum)["category"]]} : null',
                force: true,
              },
              {
                events: [{ source: "view", type: "mouseout" }],
                update: "null",
              },
            ],
          },
          {
            name: "recentTransaction_name",
            value: [{ type: "E", field: "category" }],
          },
          {
            name: "updated_cityName",
            on: [
              {
                events: { signal: "mouse__move" },
                update: 'modify("bubbleChart_store", mouse__move, true)',
              },
            ],
          },
        ],
        marks: [
          {
            name: "nodes",
            type: "symbol",
            from: { data: "table" },
            encode: {
              enter: {
                fill: { scale: "color", field: "category" },
                xfocus: { signal: "cx" },
                yfocus: { signal: "cy" },
              },
              update: {
                size: { signal: "pow(2 * datum.value, 1)", scale: "size" },
                stroke: { value: "#3a3a4a" },
                strokeWidth: { value: 1 },
                tooltip: {
                  signal: "datum.category+' '+datum.name +' '+ datum.value",
                },
                opacity: [
                  {
                    test:
                      '(!length(data("bubbleChart_store")) || vlSelectionTest("bubbleChart_store", datum)) ',
                    value: 1,
                  },
                  { value: 0.2 },
                ],
              },
            },
            transform: [
              {
                type: "force",
                iterations: 100,
                static: false,
                forces: [
                  {
                    force: "collide",
                    iterations: 2,
                    radius: { expr: "sqrt(datum.size) / 2" },
                  },
                  { force: "center", x: { signal: "cx" }, y: { signal: "cy" } },
                  { force: "x", x: "xfocus", strength: { signal: "gravityX" } },
                  { force: "y", y: "yfocus", strength: { signal: "gravityY" } },
                ],
              },
            ],
          },
          {
            type: "text",
            from: { data: "nodes" },
            encode: {
              enter: {
                align: { value: "center" },
                baseline: { value: "middle" },
              },
            },
          },
        ],
      },
    ],
    legends: [
      {
        labelColor: "#c4c4cd ",
        fill: "color",
        direction: "horizontal",
        encode: {
          labels: {
            name: "category_legend_labels",
            interactive: true,
            "update":{
              "fontSize":{"signal": 14}
          }
          },
          symbols: {
            name: "category_legend_symbols",
            interactive: true,
            "update": {
              "strokeWidth": {"value": 12},
              "size": {"value": 200}
          }
          },
          entries: {
            name: "category_legend_entries",
            interactive: true,
            update: { fill: { value: "transparent" } },
          },
        },
      },
    ],
    "config": {
      "legend": { "columns":{"signal": "3"},"orient": "bottom",
       "layout": {"bottom": {"anchor": "middle"}}, "symbolType": "circle",
        "labelColor": "white"}
  },
  };
  
  return (
    <>
        <Vega spec={option} actions={false} />
    </>
  );
};

export default PackedBubbleChart;

Step 3. Create a new component for sortable list

create a new json file, 'bubblechart.json'. Add the following code to this file.

[
    {
      "category": "Information Technology",
      "name": "Cloud Computing",
      "value": 277
    },
    {
      "category": "Information Technology",
      "name": "Immersive Technology",
      "value": 1
    },
  
    {
      "category": "Industrials",
      "name": "Renewable Energy",
      "value": 31
    },
    {
      "category": "Industrials",
      "name": "Cloud Computing",
      "value": 30
    },
    {
      "category": "Health Care",
      "name": "Artificial Intelligence",
      "value": 26
    },
    {
      "category": "Health Care",
      "name": "Cloud Computing",
      "value": 26
    },
    {
      "category": "Consumer Discretionary",
      "name": "Mobile Applications",
      "value": 25
    },
    {
      "category": "Consumer Discretionary",
      "name": "Cloud Computing",
      "value": 21
    },
    {
      "category": "Consumer Discretionary",
      "name": "Artificial Intelligence",
      "value": 15
    },
    {
      "category": "Consumer Discretionary",
      "name": "Immersive Technology",
      "value": 1
    },
    {
      "category": "Consumer Discretionary",
      "name": "Robotics",
      "value": 1
    },
    {
      "category": "Communication Services",
      "name": "Cloud Computing",
      "value": 43
    },
    {
      "category": "Communication Services",
      "name": "Mobile Applications",
      "value": 30
    },
    {
      "category": "Communication Services",
      "name": "Big Data/ Analytics",
      "value": 25
    },
    {
      "category": "Financials",
      "name": "Mobile Applications",
      "value": 17
    },
    {
      "category": "Financials",
      "name": "Blockchain",
      "value": 12
    },
    {
      "category": "Real Estate",
      "name": "Cloud Computing",
      "value": 4
    },
    {
      "category": "Real Estate",
      "name": "Mobile Applications",
      "value": 2
    },
    {
      "category": "Real Estate",
      "name": "Blockchain",
      "value": 1
    },
    {
      "category": "Materials",
      "name": "Electric Vehicle",
      "value": 3
    },
    {
      "category": "Materials",
      "name": "Renewable Energy",
      "value": 3
    },
    {
      "category": "Consumer Staples",
      "name": "Cannabis",
      "value": 6
    },
    {
      "category": "Consumer Staples",
      "name": "Mobile Applications",
      "value": 3
    },
    {
      "category": "Consumer Staples",
      "name": "Artificial Meat",
      "value": 2
    },
    {
      "category": "Utilities",
      "name": "Smart Homes / Smart Cities",
      "value": 1
    },
    
    {
      "category": "Energy",
      "name": "Internet of Things",
      "value": 1
    },
    {
      "category": "Energy",
      "name": "Wireless Communication Technology",
      "value": 1
    }
  ]

Step 4. Add the below code in App.js file

import './App.css';
import PackedBubbleChart from './bubble-chart/bubblechart';

function App() {
  return (
    <PackedBubbleChart/>
  );
}

export default App;

Step 5. Output

Now, run the project by using the 'npm start' command, and check the result.

bubble chart using Vega in Reactjs

bubble chart using Vega in Reactjs

Summary

In this article, we learned how to create a bubble chart using Vega library in ReactJS application.