Search code examples
reactjsplotly

React Json data from endpoint not working with Plotly


I'm learning React and trying to understand what I'm doing wrong.

I have an endpoint like this in main.py:

def get_db_data():
   engine = create_engine(config.get('database', 'con'))
   table = 'raw_data'
   df = pd.read_sql(table, engine)
   return df

@app.get("/rawdata", tags=['data'], status_code=200)
async def raw_data():
   data = get_db_data()
   return data.to_dict()

for the sake of brevity, it renders a Pandas Dataframe that I convert to a dictionary, like this: (edited per request in comments)

{
 "Date": {
    "0": "2019-01",
    "1": "2019-02",
    "2": "2019-03",
    "3": "2019-04",
    "4": "2019-05"
 },
 "Sales": {
    "0": 71,
    "1": 67,
    "2": 84,
    "3": 65,
    "4": 78
 } 
 

then in App.js, I have this:

import './App.css';
import React, { useEffect, useState } from 'react'; 
import axios from 'axios';
import Plot from "react-plotly.js";

function App() {

  const [data, setData] = useState([]);

  useEffect(() => {
    axios.get('/rawdata').then((response) => {
      console.log(response.data)
      setData(response.data);
    })
    .catch((error) => {
      console.error('Error fetching data:', error);
    });
  }, []);


return (

    <Plot  
      data={[
        {
          x: data.map((point) => point.Date),
          y: data.map((point) => point.Sales),
          type: "scatter",
          mode: "lines+points",
          marker: { color: "blue" },
        },
      ]}
    layout={{ width: 800, height: 400, title: "Time Series Plot" }}
  />
);
}

export default App;

The console is "seeing" the JSON data from the endpoint, but I'm getting an error for these: x: data.map((point) => point.Date), y: data.map((point) => point.Sales),

"data.map is not a function TypeError: data.map is not a function"

Can anyone tell me what I'm doing wrong?


Solution

  • Because you are receiving response as object. So map function only works on array if want to pass array in x and y keys just use Object.values it will generate an array from object(key/value pair).

    I applied some best practices like show loading

    import './App.css';
    import React, { useEffect, useState } from 'react'; 
    import axios from 'axios';
    import Plot from "react-plotly.js";
    
    function App() {
    
    const [data, setData] = useState({});
    const [isLoaded, setLoaded] = useState(false);
    
    useEffect(() => {
        axios.get('/rawdata').then((response) => {
        console.log(response.data)
        setData(response.data); // react will batch this two state updated into to one
        setLoaded(true);
        })
        .catch((error) => {
        console.error('Error fetching data:', error);
        });
    }, []);
    
    if(!isLoaded){ // your loading component
        return (
            <div>
                Loading...
            </div>
        )
    }
    return (
    
        <Plot  
        data={[
            {
            x: Object.values(data.Date),
            y: Object.values(data.Sales),
            type: "scatter",
            mode: "lines+points",
            marker: { color: "blue" },
            },
        ]}
        layout={{ width: 800, height: 400, title: "Time Series Plot" }}
    />
    );
    }
    
    export default App;