First, I’ll contextualize what will be used in this article.
Plot.ly is a library commonly used to draw graphs and other web interfaces. It started with Python but now has many other implementations in different programming languages, like JavaScript and R. It also has special implementations to support some popular frameworks, like React and Angular.
For this article, I am using React, a powerful library to make web applications. Simple code and easy components creation make React scalable and robust.
One day a friend ask me for help integrating Plot.ly with React. She is writing some application that consumes an API and she is creating a tool to see this data. At first, I thought the problem was getting used to the way you write code using modern JavaScript, such as using new naming and development patterns, like for example, installing libraries using NPM. So I pointed her to the initial steps and apparently she made some static graphs. But she needed to draw graphs using dynamic data and she didn’t find a solution that worked for her.
So I go into history. I originally looked in the Plot.ly + React documentation, it’s really good, but for initial and simple problems, such as complex interactions or dynamic loading of data, it’s pretty bad or nonexistent.
Let’s code
First, we need to install Node.js, NPM and React. From the command line, we type
npm i -g create-react-app
and wait until it finishes.
Now we can create our React app with
create-react-app myplotlysite
Move into the app folder
cd myplotlysite
and install Plot.ly in your project using NPM
npm i -SE react-plotly.js plotly.js
Let’s start our project
npm start
and see the results on the browser that opens (the default URL is localhost:3000
).
Now we create a class for a graph and define the Plotly component
<Plot
graphDiv="graph"
/>
Defining state to control some lines
state = {
line1: {
x: [-3, -2, -1],
y: [1, 2, 3],
name: 'Line 1'
},
line2: {
x: [1, 2, 3],
y: [-3, -2, -1],
name: 'Line 2'
}
}
Putting the state on graph data:
<Plot
data={[
this.state.line1,
this.state.line2,
]}
graphDiv="graph"
/>
This is what it looks like:
Let create a function to add data on the graph, and link it to a button. The function will add values to the data array and change values of layout.datarevision
and revision
.
It will look something like this:
increaseGraphic = () => {
const { line1, line2, layout } = this.state;
line1.x.push(this.rand());
line1.y.push(this.rand());
line2.x.push(this.rand());
line2.y.push(this.rand());
this.setState({ revision: this.state.revision + 1 });
layout.datarevision = this.state.revision + 1;
}
Now our class looks like this:
import React from 'react';
import Plot from 'react-plotly.js';export default class PlotLyGraphic extends React.Component {
state = {
line1: {
x: [-3, -2, -1],
y: [1, 2, 3],
name: 'Line 1'
},
line2: {
x: [1, 2, 3],
y: [-3, -2, -1],
name: 'Line 2'
},
layout: {
datarevision: 0,
},
revision: 0,
}
rand = () => parseInt(Math.random() * 10, 10);
increaseGraphic = () => {
const { line1, line2, layout } = this.state;
line1.x.push(this.rand());
line1.y.push(this.rand());
line2.x.push(this.rand());
line2.y.push(this.rand());
this.setState({ revision: this.state.revision + 1 });
layout.datarevision = this.state.revision + 1;
}
render() {
return (
<div>
<Plot
data={[
this.state.line1,
this.state.line2,
]}
layout={this.state.layout}
revision={this.state.revision}
graphDiv="graph"
/>
</div>
);
}
}
Extra
With simple changes, we can prepare the component to look for data on a web service or consume from time to time from an API. Understanding the React Component Lifecycle is important for this. For example, we can use the componentDidMount
call and the function setInterval
to call increaseGraph
(or your API call) periodically.
componentDidMount() {
setInterval(this.increaseGraph, 1000);
}
The final component is:
import React from 'react';
import Plot from 'react-plotly.js';
export default class PlotEx extends React.Component {
state = {
line1: {
x: [-3, -2, -1],
y: [1, 2, 3],
name: 'Line 1'
},
line2: {
x: [1, 2, 3],
y: [-3, -2, -1],
name: 'Line 2'
},
layout: {
datarevision: 0,
},
revision: 0,
}
componentDidMount() {
setInterval(this.increaseGraphic, 1000);
}
rand = () => parseInt(Math.random() * 10 + this.state.revision, 10);
increaseGraphic = () => {
const { line1, line2, layout } = this.state;
line1.x.push(this.rand());
line1.y.push(this.rand());
if (line1.x.length >= 10) {
line1.x.shift();
line1.y.shift();
}
line2.x.push(this.rand());
line2.y.push(this.rand());
if (line2.x.length >= 10) {
line2.x.shift();
line2.y.shift();
}
this.setState({ revision: this.state.revision + 1 });
layout.datarevision = this.state.revision + 1;
}
render() {
return (<div>
<Plot
data={[
this.state.line1,
this.state.line2,
]}
layout={this.state.layout}
revision={this.state.revision}
graphDiv="graph"
/>
</div>);
}
}
Conclusions
React is a powerful tool to work with interactions on the screen and Plotly is able to create many nice graphs, but unfortunately its documentation fails to have clear of certain interactions. That does not stop it from being able to work with dynamically generated data.
Much obliged @eliasluizjr for the help with text revision.