How To Implement Pie Chart Using Vega In React

Introduction

This article demonstrates how to create and use a pie chart using vega in reactjs. This article starts with an introduction to 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 - 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-piechart

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 pie-chart and inside it create a component, 'pie-chart.js'. Add the following code to this component.

import React from 'react';
import { Vega } from 'react-vega';
import "./_piechart.css";
import piechart from "./piechart.json";

  export const PieChart = () => {
    const spec={
      "$schema": "https://vega.github.io/schema/vega/v5.json",
      "width": 500,
      "height": 220,
      "signals": [
        {"name": "startAngle", "value": 0},
        {"name": "endAngle", "value": 6.29},
        {"name": "padAngle", "value": 0},
        {"name": "sort", "value": true},
        {"name": "strokeWidth", "value": 1},
        {
          "name": "selected",
          "value": "",
          "on": [{"events": "mouseover", "update": "datum"}]
        },
        {
          "name": "legend",
          "update": "vlSelectionResolve(\"industry_store\", \"union\", true, true)",
        },
        {
          "name": "legend_tuple_fields",
          "value": [{"type": "E", "field": "name"}]
        },
        {
          "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",
                "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(\"industry_store\", legend_toggle ? null : legend_tuple, legend_toggle ? null : true, legend_toggle ? legend_tuple : null)",
            },
          ],
        },
      ],
      "data": piechart,
      "legends": [
        {
          "labelColor": "#c4c4cd ",
          "fill": "color",
          "title": "",
          "encode": {
            "labels": {
              "name": "category_legend_labels",
              "interactive": true,
              "update":{
                  "fontSize":{"signal": "12"}
              }
            },
            "symbols": {
              "name": "category_legend_symbols",
              "interactive": true,
              "update": {
                  "strokeWidth": {"value": 12},
                  "size": {"value": 100}
              }
            },
            "entries": {
              "name": "category_legend_entries",
              "interactive": true,
              "update": { "fill": { "value": "transparent" } },
            }
          }
        }
      ],
      "scales": [
        {
          "name": "color",
          "type": "ordinal",
    "domain": [
          "London",
          "Portland",
          "Palo Alto",
          "Kansas City",
          "Santa Clara",
          "Coventry",
          "Bootle",
          "Boston",
          "Irvine",
          "Worcester",
          "Others",
        ],
        "range": [
          "#98df8a",
          "#27acaa",
          "#ff810a",
          "#34c668",
          "#178be4",
          "#714ac3",
          "#27acaa",
          "#8ce8ad",
          "#ffbb78",
          "#c4c4cd",
          "#d62728",
        ],
          
        }
      ],
      "marks": [
        {
          "type": "group",
          "name": "concat_0_group",
          "marks": [
            {
              "name": "cities_marks",
              "type": "arc",
              "style": ["arc"],
              "interactive": true,
              "from": {"data": "table"},
              "enter": {"fill": {"scale": "color", "field": "name"}},
              "encode": {
                "update": {
                  "fill": {"scale": "color", "field": "name"},
                  "x": {"signal": "width / 2"},
                  "y": {"signal": "height / 2"},
                        "tooltip": {
                  "signal": "datum.name+' '+datum.y + '('+(format(datum.y/100,'0.0p'))+')'"
                },
                  "opacity": [
                    {
                      "test": "(!length(data('industry_store')) || vlSelectionTest('industry_store', datum))",
                      "value": 1
                    },
                    {"value": 0.2}
                  ],
                  
                  "description": {
                    "signal": "\"Cities Yeild: \" + (format(datum[\"y\"], \"\")) + \"; name: \" + (isValid(datum[\"name\"]) ? datum[\"name\"] : \"\"+datum[\"name\"])"
                  },
                  "startAngle": {"field": "startAngle"},
                  "endAngle": {"field": "endAngle"},
                  // "padAngle": {
                  //   "signal": "if(selected && selected.name == datum.name, 0.015, 0.015)"
                  // },
                  "innerRadius": {"signal": "80"},
                  "outerRadius": {
                    "signal": "if((!length(data('industry_store')) || vlSelectionTest('industry_store', datum)), if(width >= height, height, width) / 2 * 1.2 * 0.8, if(width >= height, height, width) / 2 * 0.9)"
                  },
                  "stroke": {"signal": "scale('color', datum.name)"},
                  //"strokeWidth": {"signal": "strokeWidth"},
             
                }
              }
            },
            {
              "type": "text",
              "encode": {
                "enter": {"fill": {"value": "#525252"}, "text": {"value": ""}},
                "update": {
                  "x": {"signal": "width / 2"},
                  "y": {"signal": "height / 2"},
                  "align": {"value": "center"},
                  "baseline": {"value": "middle"},
                  "fontSize": {
                    "signal": "20"
                  },
                  "text": {"value": "89"},
                  "fill": {"value": "white"},
                  "font-family": {"value": "EYInterstate"}
                }
              }
            }
          ],
               "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)['name']]} : null",
                "force": true,
              },
              {
                "events": [{ "source": "view", "type": "mouseout" }],
                "update": "null",
              },
            ],
          },
          {
            "name": "recentTransaction_name",
            "value": [{ "type": "E", "field": "name" }],
          },
          {
            "name": "updated_cityName",
            "on": [
              {
                "events": { "signal": "mouse__move" },
                "update": "modify('industry_store', mouse__move, true)",
              },
            ],
          },
        ],
        }
      ],
      "encoding": {
        "tooltip": [
          {"field": "name", "type": "nominal"},
          {"field": "y", "type": "quantitative"}
        ]
      },
      "config": {
          "legend": { "columns":{"signal": "2"},"orient": "bottom", "layout": {"bottom": {"anchor": "middle"}}, "symbolType": "circle", "labelColor": "white"}
      },
  }

    return (
      <>
        <Vega spec={spec} className={undefined} actions={false} />
      </>
    )
  }

export default PieChart;

Step 3. Create a new component for a sortable list

Create a new JSON file, 'piechart.json'. Add the following code to this file.

[
	{ "name": "industry_store" },
	{
	  "name": "table",
	  "values": [{ "name": "London", "y": 22, "drilldown": "drilldown0" }, { "name": "Portland", "y": 7, "drilldown": "drilldown0" }, { "name": "Palo Alto", "y": 4, "drilldown": "drilldown0" }, { "name": "Kansas City", "y": 4, "drilldown": "drilldown0" }, { "name": "Santa Clara", "y": 3, "drilldown": "drilldown0" }, { "name": "Coventry", "y": 3, "drilldown": "drilldown0" }, { "name": "Bootle", "y": 3, "drilldown": "drilldown0" }, { "name": "Boston", "y": 3, "drilldown": "drilldown0" }, { "name": "Irvine", "y": 2, "drilldown": "drilldown0" }, { "name": "Worcester", "y": 2, "drilldown": "drilldown0" }, { "name": "Others", "color": "#C4C4CD", "y": 31, "drilldown": "Others0" }],
	  "transform": [
		{
		  "type": "pie",
		  "field": "y",
		  "startAngle": { "signal": "startAngle" },
		  "endAngle": { "signal": "endAngle" },
		  "sort": { "signal": "sort" }
		},
		{
		  "type": "formula",
		  "expr": "format(datum.value/100,'0.0p')",
		  "as": "percentvalue"
		  }
	  ]
	},
	{
	  "name": "fieldSum",
	  "source": "table",
	  "transform": [
		{
		  "type": "aggregate",
		  "fields": ["y"],
		  "ops": ["sum"],
		  "as": ["sum"]
		}
	  ]
	}
  ]

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

import './App.css';
import PieChart from './pie-chart/piechart';

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

export default App;

Step 5. Output

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

implement Pie chart using Vega in React

Summary

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