Categories: Uncategorized

Basic Visualization with React and Plotly.js

Visualization of data makes it more understandable. In the world of Big Data, it is impossible to check every set of data and bring a logical, decision making output from it. Visualization is an increasingly key tool to make sense of the trillions of rows of data generated every day

Data Visualization tools such as Plotly is a high-level, declarative charting library. It has over 40 chart types, including 3D charts, statistical graphs, and SVG maps. Moreover it is free and open source.

Let’s us now see how to create a basic visualization application using React and Plotly. In this article we will be using React Hooks and function as a component for better understanding.

Pre-requisites:
NodeJS and npm

  1. Create-react-app
$ npx create-react-app data-visual
$ cd data-visual

2. Install required libraries

$ npm i plotly.js react-plotly.js react-bootstrap bootstrap d3 xlsx

3. Remove all files except index.js, index.css and App.js

./index.jsimport React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";import "bootstrap/dist/css/bootstrap.min.css";ReactDOM.render(<App/>,document.getElementById("root"));

We will create various components that could be used multiple times in out application.

4. Create card component

// ./components/Cards.jsimport React, { Component } from "react";export class Card extends Component {
render() {
return (
<div className={"card" + (this.props.plain ? " card-plain" : "")}>
<div className={"header" + (this.props.hCenter ? " text-center" : "")}>
<h4 className="title">{this.props.title}</h4>
<p className="category">{this.props.category}</p>
</div>
<div
className={
"content" +
(this.props.ctAllIcons ? " all-icons" : "") +
(this.props.ctTableFullWidth ? " table-full-width" : "") +
(this.props.ctTableResponsive ? " table-responsive" : "") +
(this.props.ctTableUpgrade ? " table-upgrade" : "")
}
>
{this.props.content}<div className="footer">
{this.props.legend}
{this.props.stats != null ? <hr /> : ""}
<div className="stats">
<i className={this.props.statsIcon} /> {this.props.stats}
</div>
</div>
</div>
</div>
);
}
}export default Card;

5. Create select component

//  ./components/Select.jsimport React from "react";const Select = (props) => {
return;
<div style={props.style}>
<label>{props.label}:</label>
<select
onChange={(e) => props.setVal(e.target.value)}
value={props.val}
className="form-control"
>
{props.cols &&
props.cols.map((col, index) => <option value={col}>{col}</option>)}
</select>
</div>;
};export default Select;

6. Create graph component

// ./components/Graphs.jsimport React, { useEffect, useState } from "react";
import Plot from "react-plotly.js";
import Select from "./Select";
const cols = ["lines", "markers", "bubbles", "lines+markers"];
const bubbleMarker = {
opacity: 0.4,
size: 60
};const Graph = props => {
const [mode, setMode] = useState(null);return (
<div>
<div style={{ width: 500 }}>
{props.graphType === "scatter" ? (
<Select
val={mode}
setVal={setMode}
cols={cols}
label="mode"
style={{ width: 100 }}
/>
) : null}
</div><Plot
data={
props.graphType === "pie"
? [
{
values: props.y,
labels: props.x,
type: "pie"
}
]
: [
{
x: props.x,
y: props.y,
type: props.graphType || "bar",
mode: (mode === "bubbles" ? "markers" : mode) || "lines",
marker:
mode !== "bubbles"
? {
color: props.x
}
: bubbleMarker
}
// { type: "bar", x: [1, 2, 3], y: [2, 5, 3], marker: { color: "red" } }
]
}
layout={{ width: 600, height: 450, title: props.label }}
/>
</div>
);
};export default Graph;

7. Create datatable component

//  ./components/DataTable.jsimport React from "react";
import { Table } from "react-bootstrap";function getKeys(data) {
return Object.keys(data[0]);
}function getHeader(data) {
var keys = getKeys(data);
return keys.map((key, index) => {
return <th key={key}>{key.toUpperCase()}</th>;
});
}function getRowsData(data) {
var items = data.slice(0, 5);
var keys = getKeys(data);
return items.map((row, index) => {
return (
<tr key={index}>
<RenderRow key={index} data={row} keys={keys} />
</tr>
);
});
}const RenderRow = props => {
return props.keys.map((key, index) => {
return <td key={props.data[key]}>{props.data[key]}</td>;
});
};const DataTable = props => {
console.log(props);
// debugger;
return (
<div>
<Table striped hover responsive variant="dark">
<thead>
<tr>{getHeader(props.data)}</tr>
</thead>
<tbody>{getRowsData(props.data)}</tbody>
</Table>
</div>
);
};export default DataTable;

8. Update content on App.js

// import React from 'react';
// import logo from './logo.svg';
// import './App.css';// function App() {
// return (
// <div className="App">
// <header className="App-header">
// <img src={logo} className="App-logo" alt="logo" />
// <p>
// Edit <code>src/App.js</code> and save to reload.
// </p>
// <a
// className="App-link"
// href="https://reactjs.org"
// target="_blank"
// rel="noopener noreferrer"
// >
// Learn React
// </a>
// </header>
// </div>
// );
// }// export default App;import React, { useEffect, useState, useRef } from "react";
import { Card } from "./components/Card";
import { Container, Row, Col } from "react-bootstrap";
import Plot from "react-plotly.js";
import * as d3 from "d3";
import XLSX from "xlsx";
import DataTable from "./components/DataTable";
import Select from "./components/Select";
// import Graph from "../components/Graph";
const row = (d) => {
const keys = Object.keys(d);
keys.map((key) => {
if (!isNaN(d[key])) {
d[key] = +d[key];
}
if (isNaN(d[key]) && d[key].length > 100) {
d[key] = d[key].slice(0, 100) + "...";
}
});
return d;
};
function unpack(rows, key) {
return rows.map(function (row) {
return row[key];
});
}
const graph1 = ["bar", "pie", "scatter"];
const graph2 = ["heatmap", "scatter3d", "contour"];const App = () => {
const [data, setData] = useState([]);
const [cols, setCols] = useState([]);
const [currX, setCurrX] = useState("");
const [currY, setCurrY] = useState("");
const [currZ, setCurrZ] = useState("");
const [fileName, setFileName] = useState("");
const [basicGraphType, setBasicGraphType] = useState("bar");
const [scientificGraphType, setScientificGraphType] = useState("heatmap");const [fullWidth, setFullWidth] = useState(true);const plotRef = useRef(null);useEffect(() => {
if (data.length !== 0) {
setCols(Object.keys(data["0"]));
}
}, [data]);useEffect(() => {
cols && setCurrX(cols[0]);
cols && setCurrY(cols[1]);
cols && setCurrZ(cols[2]);
}, [cols]);async function handleChange(e) {
const reader = new FileReader();
let dataURL;
reader.onload = function (e) {
dataURL = e.target.result;
if (file.name.split(".").pop() !== "csv") {
const wb = XLSX.read(dataURL, { type: "binary" });
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
/* Convert array of arrays */
dataURL = XLSX.utils.sheet_to_csv(ws, { header: 1 });
/* Update state */
}
const dataObj = d3.csvParse(dataURL, row);
setData(dataObj);
};
const file = e.target.files[0];
setFileName(file.name);
if (file.name.split(".").pop() === "csv") {
reader.readAsText(file);
} else {
reader.readAsBinaryString(file);
}
}return (
<div>
<Container fluid style={{ padding: 20 }}>
<Row>
<Col md={4} sm={6}>
<input
type="file"
onChange={handleChange}
accept=".csv,.xls,.xlsx"
className="form-control-file"
/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span style={{ color: "red" }}>(csv, xls)</span>
<div>
<Select val={currX} setVal={setCurrX} cols={cols} label="X" />
<Select val={currY} setVal={setCurrY} cols={cols} label="Y" />
<Select val={currZ} setVal={setCurrZ} cols={cols} label="Z" />
<br />
</div>
</Col>
<Col md={8} sm={6}>
{data.length !== 0 && cols ? (
<Card
title={fileName}
category="Top 5 rows of the file"
ctTableFullWidth
ctTableResponsive
content={
<div md={8} style={{ overflow: "auto" }}>
<DataTable data={data} />
</div>
}
/>
) : null}
</Col>
</Row>
<Row>
<Col md={5} sm={6}>
<Select
val={basicGraphType}
setVal={setBasicGraphType}
cols={graph1}
label="Graph"
/>
<br />
<div
style={{
width: fullWidth ? "100%" : "50%",
}}
>
<Plot
ref={plotRef}
useResizeHandler
style={{ width: "100%", height: "100%" }}
data={[
{
x: unpack(data, currX),
y: unpack(data, currY),
type: basicGraphType,
hoverongaps: false,
},
]}
layout={{ title: "Data Plot", autosize: true }}
config={{ responsive: true }}
/>
</div>
</Col><Col md={5} sm={6}>
<Select
val={scientificGraphType}
setVal={setScientificGraphType}
cols={graph2}
label="Graph2"
/>
<br />
<div
style={{
width: fullWidth ? "100%" : "50%",
}}
>
<Plot
ref={plotRef}
useResizeHandler
style={{ width: "100%", height: "100%" }}
data={[
{
z: unpack(data, currZ),
x: unpack(data, currX),
y: unpack(data, currY),
type: scientificGraphType,
hoverongaps: false,
},
]}
layout={{ title: "Scientific Plots", autosize: true }}
config={{ responsive: true }}
/>
</div>
</Col>
</Row>
</Container>
</div>
);
};
export default App;

In the application most of the code uses inline css styling but one can always use .css file

9. Start App

$ npm start
 ScreenShot

Before uploading data file

Caution: Do not try to upload a file more than 5MB. React variable would not be able to handle such data and your application will crash.

Thank You !!

@nandish

Share
Published by
@nandish

Recent Posts