J.erome
J.erome

Reputation: 788

Flask, pass dataframe as a JSON to the client in order to display it

My scenario is the following one: the client upload a CSV to the Flask server, Flask convert the CSV to a Pandas dataframe in order to perform task then it send it back as a JSON object, finally the client display the result in a <p></p>

My problem is : Objects are not valid as a React child (found: object with keys {label, text}). If you meant to render a collection of children, use an array instead.

So after some research I understand that the problem comes from the way I transfer the data from Flask to the client.

Here is my Flask code:

@app.route('/analyse_dataset', methods=['GET','POST'])
def analyse_dataset_route():
    print('/analyse_dataset called', file=sys.stderr)
    try:

        # check if the post request has the dataset part
        if 'file' not in request.files:
            data = {'error': 'Dataset not in requested files'}
            return Response(data, status=400, mimetype='application/json')
        
        print('request.files : ' + str(request.files))
        uploaded_file = request.files['file']

        # no dataset
        if uploaded_file.filename == '':
            logger.debug('Dataset not found, returning to /')
            return redirect('/')

        # dataset ok
        if uploaded_file:

            uploaded_file.stream.seek(0)                   
            df = pd.read_csv(uploaded_file)
            print(df.shape,file=sys.stderr)
            for index, row in df.iterrows():
                print((row['label'], row['text']), file=sys.stderr)
                
            df = df.loc[:, ~df.columns.str.contains('^Unnamed')]                
            print(dumps(df),file=sys.stderr)
            return Response(dumps(df), status=200, mimetype='application/json')
            
        else:
            data = {'error': 'Something went wrong...'}
            return Response(data, status=400, mimetype='application/json')
            
    except Exception as e:
        data = {'error': 'An error occurred while analysing dataset'}
        return Response(data, status=400, mimetype='application/json')

Then my front-end is in ReactJS and here is App.js code where I call the Flask function :

onClickHandler = () => {
        if (this.state.selectedFile == null) {
            toast.error('No file selected')
        } else {
            const data = new FormData()
            data.append('file', this.state.selectedFile)
            let req = "http://localhost:5001/analyse_dataset"
            
            axios.post(req, data, {
                onUploadProgress: ProgressEvent => {
                    this.setState({
                        loaded: (ProgressEvent.loaded / ProgressEvent.total * 100),
                        loading: true
                    })
                },
            })
                .then(res => { // then print response status
                    console.log("file processed: " + res.data)
                    this.setState({
                        redirect: true,
                        jsondata: res.data
                    })
                })
                .catch(err => { // then print response status
                    console.log(err)
                    this.setState({
                        selectedFile: null,
                        loaded: 0,
                        loading: false
                    })
                    setTimeout(() => {
                        toast.error("Process failed, be sure to upload a correct file.")
                    }, 500)
                })
        }
    }

it's also where I store the result to use it in success.js like this:

export default class Success extends React.Component {

    constructor(props) {
        super();
        if (props.location.state) {
            this.state = {
                jsondata: props.location.state.referrer,
                upload: true
            } //put jsons data in state object
            toast.success('Upload success')
        } else {
            this.state = {
                upload: false
            }
        }
    }

    render() {
        if (!this.state.upload) {
            return <Redirect push to={{
                pathname: "/"
            }}/>
        } else return (
            <div className="container">
                <p style={{textAlignVertical: "center", textAlign: "center", fontSize: 30}}> Sentiment analysis done </p>
                <div className="row">
                    <div style={{padding: '50px 300px 100px 300px'}} className="col-md-12 offset-md-12 card">
                        <p style={{textAlignVertical: "center", textAlign: "center", fontSize: 22, color: "green"}}>File processed with success</p>
                        
                    </div>
                </div>
                <p style={{textAlignVertical: "center", textAlign: "center", fontSize: 30, marginTop: '50px'}}>Some infos about the extracted data</p>
                <div className="row">
                    <div className="column">
                        <p style={{textAlign: 'center'}}>
                            {this.state.jsondata}
                        </p>
                    </div>
                </div>
            </div>
        )
    }
}

I want to display it where I wrote {this.state.jsondata} but I can't figure out where and what I do wrong, can you help me ?

[EDIT]

here is the result of dumps(df):

{
   "label":{
      "0":0,
      "1":0,
      "2":0,
      "3":0,
      "4":0
   },
   "text":{
      "0":"- Awww, c'est un bummer. Tu devrais avoir david carr du troisième jour pour le faire. ;ré",
      "1":"Est contrarié qu'il ne puisse pas mettre à jour son facebook en le télémaignant ... et peut-être pleurer en conséquence, l'école aujourd'hui aussi. blabla!",
      "2":"J'ai plongé plusieurs fois pour la balle. A réussi à économiser 50% le reste sort de limites",
      "3":"Tout mon corps a des démangeaisons et comme si c'était en feu",
      "4":"Non, il ne se comporte pas du tout. je suis en colère. pourquoi suis-je ici? Parce que je ne peux pas vous voir partout."
   }
}

Upvotes: 0

Views: 990

Answers (1)

Dean James
Dean James

Reputation: 2623

It depends on how you want to display it. If you just want to print out the whole object, you can simply wrap it in JSON.stringify:

<p style={{textAlign: 'center'}}>
  {JSON.stringify(this.state.jsondata)}
</p>

Looking at your structure, you can iterate over the entries of the object with Object.keys because it isn't an Array and we can't iterate over that object directly:

<p style={{textAlign: 'center'}}>
  {Object.keys(this.state.jsondata.label).map(k => `${k}: ${this.state.jsondata.text[k]}`)}
</p>

Upvotes: 1

Related Questions