Saving Data in a Panda DataFrame

How can I save the Output to a Panda Dataframe?

This Code will print a Survey with different Questions and Answers. If you click the “Submit” Button a summary of all Answers to all the different questions will be printed out. My Problem is: I want the Answers to get saved in an Panda DataFrame. Or even better in an Database, with Dates to the different Answers.

from dash import Dash, html, dcc, Input, Output, State, MATCH, ALL

app = Dash(__name__)

questionnaire = {
    1: {
        'type': 'choice',
        'question':
        '''
        Question 1
        ''',
        'options': ['-2', '-1', '+1', '+2']
    },
    2: {
        'type': 'choice',
        'question':
        '''
        Question 2
        ''',
        'options': ['-2', '-1', '+1', '+2']
    },
    3: {
        'type': 'choice',
        'question':
        '''
        Question 3
        ''',
        'options': ['-2', '-1', '+1', '+2']
    },
    4: {
        'type': 'choice',
        'question':
        '''
        Question 4
        ''',
        'options': ['-2', '-1', '+1', '+2']
    },
}


def generate(k, v):
    if 'choice':
            return html.Div([html.P(str(k)+'. '+v['question']), dcc.RadioItems(id={'index': k, 'type': v['type'], 'category':'questionnaire'}, options={i: i for i in v['options']})])


app.layout = html.Div([generate(k, v) for k, v in questionnaire.items()] +
                      [html.Br(), btn := html.Button('Submit'), answers := html.Div()])


@app.callback(
    Output(
        {
            'category': 'questionnaire',
            'type': 'choice+blank',
            'index': MATCH
        }, 'disabled'),
    Input(
        {
            'category': 'questionnaire',
            'type': 'choice+blank',
            'index': MATCH
        }, 'value'))


@app.callback(
    Output(
        btn, 'disabled'),
    Input(
        {
            'category': 'questionnaire',
            'type': ALL,
            'index': ALL
        }, 'value'))



@app.callback(Output(answers, 'children'), Input(btn, 'n_clicks'), [
    State(
        {
            'category': 'questionnaire',
            'type': ALL,
            'index': ALL
        }, 'id'),
    State(
        {
            'category': 'questionnaire',
            'type': ALL,
            'index': ALL
        }, 'value')
], prevent_initial_call=True)
def collect(n_clicks, index, answer):
    return str([v | {'answer': answer[i]} for i, v in enumerate(index)])


if __name__ == "__main__":
    app.run_server(debug=True)

Hi,

You have to first create a dataframe, which in your case could be done by e.g.:

df = pd.DataFrame.from_records([v | {'answer': answer[i]} for i, v in enumerate(index)])

Then you could use df.to_csv() to save it as a csv file in principle, however it might be tricky/dangerous to manage different submissions and store these files where the app is running. If you intend to use a database, then you can use df.to_sql (docs here), which is a better choice IMO.

Hope this helps!

1 Like

thank you very much

where is my error? why doesnt it save the data to an CSV? @jlfsjunior

from dash import Dash, html, dcc, Input, Output, State, MATCH, ALL
import pandas as pd

app = Dash(__name__)

questionnaire = {
    1: {
        'type': 'choice',
        'question':
        '''
        Question 1
        ''',
        'options': ['-2', '-1', '+1', '+2']
    },
    2: {
        'type': 'choice',
        'question':
        '''
        Question 2
        ''',
        'options': ['-2', '-1', '+1', '+2']
    },
    3: {
        'type': 'choice',
        'question':
        '''
        Question 3
        ''',
        'options': ['-2', '-1', '+1', '+2']
    },
    4: {
        'type': 'choice',
        'question':
        '''
        Question 4
        ''',
        'options': ['-2', '-1', '+1', '+2']
    },
}


def generate(k, v):
    if 'choice':
            return html.Div([html.P(str(k)+'. '+v['question']), dcc.RadioItems(id={'index': k, 'type': v['type'], 'category':'questionnaire'}, options={i: i for i in v['options']})])


app.layout = html.Div([generate(k, v) for k, v in questionnaire.items()] +
                      [html.Br(), btn := html.Button('Submit'), answers := html.Div()])


@app.callback(
    Output(
        {
            'category': 'questionnaire',
            'type': 'choice+blank',
            'index': MATCH
        }, 'disabled'),
    Input(
        {
            'category': 'questionnaire',
            'type': 'choice+blank',
            'index': MATCH
        }, 'value'))


@app.callback(
    Output(
        btn, 'disabled'),
    Input(
        {
            'category': 'questionnaire',
            'type': ALL,
            'index': ALL
        }, 'value'))



@app.callback(Output(answers, 'children'), Input(btn, 'n_clicks'), [
    State(
        {
            'category': 'questionnaire',
            'type': ALL,
            'index': ALL
        }, 'id'),
    State(
        {
            'category': 'questionnaire',
            'type': ALL,
            'index': ALL
        }, 'value')
], prevent_initial_call=True)
def collect(n_clicks, index, answer):
    return str([v | {'answer': answer[i]} for i, v in enumerate(index)])

df = pd.DataFrame.from_records([v | {'answer': answer[i]} for i, v in enumerate(index)])

df.to_csv()

if __name__ == "__main__":
    app.run_server(debug=True)

First you have to create and save the dataframe in the callback function scope, and not global… Second, you must provide a filename to to_csv:

@app.callback(Output(answers, 'children'), Input(btn, 'n_clicks'), [
def collect(n_clicks, index, answer):
    answers_list = [v | {'answer': answer[i]} for i, v in enumerate(index)]
    df = pd.DataFrame.from_records(answers_list)
    df.to_csv("answers.csv")
    return str(answers_list)
1 Like