{"id":3708,"date":"2020-05-06T07:19:05","date_gmt":"2020-05-06T07:19:05","guid":{"rendered":"https:\/\/www.iventura.ai\/?p=3708"},"modified":"2020-05-06T07:33:06","modified_gmt":"2020-05-06T07:33:06","slug":"basic-visualization-with-react-and-plotly-js","status":"publish","type":"post","link":"https:\/\/www.iventura.ai\/index.php\/2020\/05\/06\/basic-visualization-with-react-and-plotly-js\/","title":{"rendered":"Basic Visualization with React and Plotly.js"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"970\" height=\"450\" src=\"https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_6-j3RAvr7HPRAK7s1fQfzg.jpeg\" alt=\"\" class=\"wp-image-3710\" srcset=\"https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_6-j3RAvr7HPRAK7s1fQfzg.jpeg 970w, https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_6-j3RAvr7HPRAK7s1fQfzg-300x139.jpeg 300w, https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_6-j3RAvr7HPRAK7s1fQfzg-768x356.jpeg 768w\" sizes=\"auto, (max-width: 970px) 100vw, 970px\" \/><\/figure>\n\n\n\n<p>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<\/p>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>Let\u2019s 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.<\/p>\n\n\n\n<p>Pre-requisites:<br><strong>NodeJS and npm<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Create-react-app<\/li><\/ol>\n\n\n\n<pre class=\"wp-block-preformatted\">$ npx create-react-app data-visual<br>$ cd data-visual<\/pre>\n\n\n\n<p>2. Install required libraries<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ npm i plotly.js react-plotly.js react-bootstrap bootstrap d3 xlsx<\/pre>\n\n\n\n<p>3. Remove all files except index.js, index.css and App.js<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.\/index.jsimport React from \"react\";<br>import ReactDOM from \"react-dom\";<br>import \".\/index.css\";<br>import App from \".\/App\";import \"bootstrap\/dist\/css\/bootstrap.min.css\";ReactDOM.render(&lt;App\/&gt;,document.getElementById(\"root\"));<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>We will create various components that could be used multiple times in out application.<\/p><\/blockquote>\n\n\n\n<p>4. Create card component<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ .\/components\/Cards.jsimport React, { Component } from \"react\";export class Card extends Component {<br>  render() {<br>    return (<br>      &lt;div className={\"card\" + (this.props.plain ? \" card-plain\" : \"\")}&gt;<br>        &lt;div className={\"header\" + (this.props.hCenter ? \" text-center\" : \"\")}&gt;<br>          &lt;h4 className=\"title\"&gt;{this.props.title}&lt;\/h4&gt;<br>          &lt;p className=\"category\"&gt;{this.props.category}&lt;\/p&gt;<br>        &lt;\/div&gt;<br>        &lt;div<br>          className={<br>            \"content\" +<br>            (this.props.ctAllIcons ? \" all-icons\" : \"\") +<br>            (this.props.ctTableFullWidth ? \" table-full-width\" : \"\") +<br>            (this.props.ctTableResponsive ? \" table-responsive\" : \"\") +<br>            (this.props.ctTableUpgrade ? \" table-upgrade\" : \"\")<br>          }<br>        &gt;<br>          {this.props.content}&lt;div className=\"footer\"&gt;<br>            {this.props.legend}<br>            {this.props.stats != null ? &lt;hr \/&gt; : \"\"}<br>            &lt;div className=\"stats\"&gt;<br>              &lt;i className={this.props.statsIcon} \/&gt; {this.props.stats}<br>            &lt;\/div&gt;<br>          &lt;\/div&gt;<br>        &lt;\/div&gt;<br>      &lt;\/div&gt;<br>    );<br>  }<br>}export default Card;<\/pre>\n\n\n\n<p>5. Create select component<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/  .\/components\/Select.jsimport React from \"react\";const Select = (props) =&gt; {<br>  return;<br>  &lt;div style={props.style}&gt;<br>    &lt;label&gt;{props.label}:&lt;\/label&gt;<br>    &lt;select<br>      onChange={(e) =&gt; props.setVal(e.target.value)}<br>      value={props.val}<br>      className=\"form-control\"<br>    &gt;<br>      {props.cols &amp;&amp;<br>        props.cols.map((col, index) =&gt; &lt;option value={col}&gt;{col}&lt;\/option&gt;)}<br>    &lt;\/select&gt;<br>  &lt;\/div&gt;;<br>};export default Select;<\/pre>\n\n\n\n<p>6. Create graph component<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ .\/components\/Graphs.jsimport React, { useEffect, useState } from \"react\";<br>import Plot from \"react-plotly.js\";<br>import Select from \".\/Select\";<br>const cols = [\"lines\", \"markers\", \"bubbles\", \"lines+markers\"];<br>const bubbleMarker = {<br>  opacity: 0.4,<br>  size: 60<br>};const Graph = props =&gt; {<br>  const [mode, setMode] = useState(null);return (<br>    &lt;div&gt;<br>      &lt;div style={{ width: 500 }}&gt;<br>        {props.graphType === \"scatter\" ? (<br>          &lt;Select<br>            val={mode}<br>            setVal={setMode}<br>            cols={cols}<br>            label=\"mode\"<br>            style={{ width: 100 }}<br>          \/&gt;<br>        ) : null}<br>      &lt;\/div&gt;&lt;Plot<br>        data={<br>          props.graphType === \"pie\"<br>            ? [<br>                {<br>                  values: props.y,<br>                  labels: props.x,<br>                  type: \"pie\"<br>                }<br>              ]<br>            : [<br>                {<br>                  x: props.x,<br>                  y: props.y,<br>                  type: props.graphType || \"bar\",<br>                  mode: (mode === \"bubbles\" ? \"markers\" : mode) || \"lines\",<br>                  marker:<br>                    mode !== \"bubbles\"<br>                      ? {<br>                          color: props.x<br>                        }<br>                      : bubbleMarker<br>                }<br>                \/\/ { type: \"bar\", x: [1, 2, 3], y: [2, 5, 3], marker: { color: \"red\" } }<br>              ]<br>        }<br>        layout={{ width: 600, height: 450, title: props.label }}<br>      \/&gt;<br>    &lt;\/div&gt;<br>  );<br>};export default Graph;<\/pre>\n\n\n\n<p>7. Create datatable component<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/  .\/components\/DataTable.jsimport React from \"react\";<br>import { Table } from \"react-bootstrap\";function getKeys(data) {<br>  return Object.keys(data[0]);<br>}function getHeader(data) {<br>  var keys = getKeys(data);<br>  return keys.map((key, index) =&gt; {<br>    return &lt;th key={key}&gt;{key.toUpperCase()}&lt;\/th&gt;;<br>  });<br>}function getRowsData(data) {<br>  var items = data.slice(0, 5);<br>  var keys = getKeys(data);<br>  return items.map((row, index) =&gt; {<br>    return (<br>      &lt;tr key={index}&gt;<br>        &lt;RenderRow key={index} data={row} keys={keys} \/&gt;<br>      &lt;\/tr&gt;<br>    );<br>  });<br>}const RenderRow = props =&gt; {<br>  return props.keys.map((key, index) =&gt; {<br>    return &lt;td key={props.data[key]}&gt;{props.data[key]}&lt;\/td&gt;;<br>  });<br>};const DataTable = props =&gt; {<br>  console.log(props);<br>  \/\/   debugger;<br>  return (<br>    &lt;div&gt;<br>      &lt;Table striped hover responsive variant=\"dark\"&gt;<br>        &lt;thead&gt;<br>          &lt;tr&gt;{getHeader(props.data)}&lt;\/tr&gt;<br>        &lt;\/thead&gt;<br>        &lt;tbody&gt;{getRowsData(props.data)}&lt;\/tbody&gt;<br>      &lt;\/Table&gt;<br>    &lt;\/div&gt;<br>  );<br>};export default DataTable;<\/pre>\n\n\n\n<p>8. Update content on App.js<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ import React from 'react';<br>\/\/ import logo from '.\/logo.svg';<br>\/\/ import '.\/App.css';\/\/ function App() {<br>\/\/   return (<br>\/\/     &lt;div className=\"App\"&gt;<br>\/\/       &lt;header className=\"App-header\"&gt;<br>\/\/         &lt;img src={logo} className=\"App-logo\" alt=\"logo\" \/&gt;<br>\/\/         &lt;p&gt;<br>\/\/           Edit &lt;code&gt;src\/App.js&lt;\/code&gt; and save to reload.<br>\/\/         &lt;\/p&gt;<br>\/\/         &lt;a<br>\/\/           className=\"App-link\"<br>\/\/           href=\"<a href=\"https:\/\/reactjs.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/reactjs.org<\/a>\"<br>\/\/           target=\"_blank\"<br>\/\/           rel=\"noopener noreferrer\"<br>\/\/         &gt;<br>\/\/           Learn React<br>\/\/         &lt;\/a&gt;<br>\/\/       &lt;\/header&gt;<br>\/\/     &lt;\/div&gt;<br>\/\/   );<br>\/\/ }\/\/ export default App;import React, { useEffect, useState, useRef } from \"react\";<br>import { Card } from \".\/components\/Card\";<br>import { Container, Row, Col } from \"react-bootstrap\";<br>import Plot from \"react-plotly.js\";<br>import * as d3 from \"d3\";<br>import XLSX from \"xlsx\";<br>import DataTable from \".\/components\/DataTable\";<br>import Select from \".\/components\/Select\";<br>\/\/ import Graph from \"..\/components\/Graph\";<br>const row = (d) =&gt; {<br>  const keys = Object.keys(d);<br>  keys.map((key) =&gt; {<br>    if (!isNaN(d[key])) {<br>      d[key] = +d[key];<br>    }<br>    if (isNaN(d[key]) &amp;&amp; d[key].length &gt; 100) {<br>      d[key] = d[key].slice(0, 100) + \"...\";<br>    }<br>  });<br>  return d;<br>};<br>function unpack(rows, key) {<br>  return rows.map(function (row) {<br>    return row[key];<br>  });<br>}<br>const graph1 = [\"bar\", \"pie\", \"scatter\"];<br>const graph2 = [\"heatmap\", \"scatter3d\", \"contour\"];const App = () =&gt; {<br>  const [data, setData] = useState([]);<br>  const [cols, setCols] = useState([]);<br>  const [currX, setCurrX] = useState(\"\");<br>  const [currY, setCurrY] = useState(\"\");<br>  const [currZ, setCurrZ] = useState(\"\");<br>  const [fileName, setFileName] = useState(\"\");<br>  const [basicGraphType, setBasicGraphType] = useState(\"bar\");<br>  const [scientificGraphType, setScientificGraphType] = useState(\"heatmap\");const [fullWidth, setFullWidth] = useState(true);const plotRef = useRef(null);useEffect(() =&gt; {<br>    if (data.length !== 0) {<br>      setCols(Object.keys(data[\"0\"]));<br>    }<br>  }, [data]);useEffect(() =&gt; {<br>    cols &amp;&amp; setCurrX(cols[0]);<br>    cols &amp;&amp; setCurrY(cols[1]);<br>    cols &amp;&amp; setCurrZ(cols[2]);<br>  }, [cols]);async function handleChange(e) {<br>    const reader = new FileReader();<br>    let dataURL;<br>    reader.onload = function (e) {<br>      dataURL = e.target.result;<br>      if (file.name.split(\".\").pop() !== \"csv\") {<br>        const wb = XLSX.read(dataURL, { type: \"binary\" });<br>        const wsname = wb.SheetNames[0];<br>        const ws = wb.Sheets[wsname];<br>        \/* Convert array of arrays *\/<br>        dataURL = XLSX.utils.sheet_to_csv(ws, { header: 1 });<br>        \/* Update state *\/<br>      }<br>      const dataObj = d3.csvParse(dataURL, row);<br>      setData(dataObj);<br>    };<br>    const file = e.target.files[0];<br>    setFileName(file.name);<br>    if (file.name.split(\".\").pop() === \"csv\") {<br>      reader.readAsText(file);<br>    } else {<br>      reader.readAsBinaryString(file);<br>    }<br>  }return (<br>    &lt;div&gt;<br>      &lt;Container fluid style={{ padding: 20 }}&gt;<br>        &lt;Row&gt;<br>          &lt;Col md={4} sm={6}&gt;<br>            &lt;input<br>              type=\"file\"<br>              onChange={handleChange}<br>              accept=\".csv,.xls,.xlsx\"<br>              className=\"form-control-file\"<br>            \/&gt;<br>            &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;<br>            &lt;span style={{ color: \"red\" }}&gt;(csv, xls)&lt;\/span&gt;<br>            &lt;div&gt;<br>              &lt;Select val={currX} setVal={setCurrX} cols={cols} label=\"X\" \/&gt;<br>              &lt;Select val={currY} setVal={setCurrY} cols={cols} label=\"Y\" \/&gt;<br>              &lt;Select val={currZ} setVal={setCurrZ} cols={cols} label=\"Z\" \/&gt;<br>              &lt;br \/&gt;<br>            &lt;\/div&gt;<br>          &lt;\/Col&gt;<br>          &lt;Col md={8} sm={6}&gt;<br>            {data.length !== 0 &amp;&amp; cols ? (<br>              &lt;Card<br>                title={fileName}<br>                category=\"Top 5 rows of the file\"<br>                ctTableFullWidth<br>                ctTableResponsive<br>                content={<br>                  &lt;div md={8} style={{ overflow: \"auto\" }}&gt;<br>                    &lt;DataTable data={data} \/&gt;<br>                  &lt;\/div&gt;<br>                }<br>              \/&gt;<br>            ) : null}<br>          &lt;\/Col&gt;<br>        &lt;\/Row&gt;<br>        &lt;Row&gt;<br>          &lt;Col md={5} sm={6}&gt;<br>            &lt;Select<br>              val={basicGraphType}<br>              setVal={setBasicGraphType}<br>              cols={graph1}<br>              label=\"Graph\"<br>            \/&gt;<br>            &lt;br \/&gt;<br>            &lt;div<br>              style={{<br>                width: fullWidth ? \"100%\" : \"50%\",<br>              }}<br>            &gt;<br>              &lt;Plot<br>                ref={plotRef}<br>                useResizeHandler<br>                style={{ width: \"100%\", height: \"100%\" }}<br>                data={[<br>                  {<br>                    x: unpack(data, currX),<br>                    y: unpack(data, currY),<br>                    type: basicGraphType,<br>                    hoverongaps: false,<br>                  },<br>                ]}<br>                layout={{ title: \"Data Plot\", autosize: true }}<br>                config={{ responsive: true }}<br>              \/&gt;<br>            &lt;\/div&gt;<br>          &lt;\/Col&gt;&lt;Col md={5} sm={6}&gt;<br>            &lt;Select<br>              val={scientificGraphType}<br>              setVal={setScientificGraphType}<br>              cols={graph2}<br>              label=\"Graph2\"<br>            \/&gt;<br>            &lt;br \/&gt;<br>            &lt;div<br>              style={{<br>                width: fullWidth ? \"100%\" : \"50%\",<br>              }}<br>            &gt;<br>              &lt;Plot<br>                ref={plotRef}<br>                useResizeHandler<br>                style={{ width: \"100%\", height: \"100%\" }}<br>                data={[<br>                  {<br>                    z: unpack(data, currZ),<br>                    x: unpack(data, currX),<br>                    y: unpack(data, currY),<br>                    type: scientificGraphType,<br>                    hoverongaps: false,<br>                  },<br>                ]}<br>                layout={{ title: \"Scientific Plots\", autosize: true }}<br>                config={{ responsive: true }}<br>              \/&gt;<br>            &lt;\/div&gt;<br>          &lt;\/Col&gt;<br>        &lt;\/Row&gt;<br>      &lt;\/Container&gt;<br>    &lt;\/div&gt;<br>  );<br>};<br>export default App;<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>In the application most of the code uses inline css styling but one can always use .css file<\/p><\/blockquote>\n\n\n\n<p>9. Start App<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ npm start\n ScreenShot<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"535\" src=\"https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_Woal9CIlVqN3-1ZCzRfoJQ-1024x535.png\" alt=\"\" class=\"wp-image-3711\" srcset=\"https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_Woal9CIlVqN3-1ZCzRfoJQ-1024x535.png 1024w, https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_Woal9CIlVqN3-1ZCzRfoJQ-300x157.png 300w, https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_Woal9CIlVqN3-1ZCzRfoJQ-768x402.png 768w, https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_Woal9CIlVqN3-1ZCzRfoJQ.png 1400w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p> Before uploading data file <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"536\" src=\"https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_jPNEWIhQy_eyVIj1DqAkjQ-1024x536.png\" alt=\"\" class=\"wp-image-3712\" srcset=\"https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_jPNEWIhQy_eyVIj1DqAkjQ-1024x536.png 1024w, https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_jPNEWIhQy_eyVIj1DqAkjQ-300x157.png 300w, https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_jPNEWIhQy_eyVIj1DqAkjQ-768x402.png 768w, https:\/\/www.iventura.ai\/wp-content\/uploads\/2020\/05\/1_jPNEWIhQy_eyVIj1DqAkjQ.png 1400w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><strong>Caution<\/strong>: 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.<\/p><\/blockquote>\n\n\n\n<p>Thank You !!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"yst_prominent_words":[239,246,244,245,240,236,235,249,254,250,248,253,251,247,242,237,252,241,243,238],"class_list":["post-3708","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/posts\/3708","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/comments?post=3708"}],"version-history":[{"count":2,"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/posts\/3708\/revisions"}],"predecessor-version":[{"id":3722,"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/posts\/3708\/revisions\/3722"}],"wp:attachment":[{"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/media?parent=3708"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/categories?post=3708"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/tags?post=3708"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/www.iventura.ai\/index.php\/wp-json\/wp\/v2\/yst_prominent_words?post=3708"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}