✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

Export csv button saves previous run's data even after new parameters

I have a dash button that exports a .csv after clicking. The export function requires a Predict Button to be clicked first and takes in a dataframe produced after the prediction function completes.

The button works functionally but if i want to change the parameters and predict again, the export button will export the csv of the previous run first and then only if clicked again will output the correct data. The only thing that fixes this is if i refresh the page after each prediction

See code below

html.Div([dcc.Input(id=‘uplift_comment’, type=‘text’, placeholder=‘Comment’,
style={‘min-width’: ‘500px’, ‘display’: ‘inline-block’}),

          html.A(html.Button('Export CSV',id='ebutton',style={'color':'coral'}), 
                 id='export_link',
                 download='DT_'+dt.today().strftime("%m.%d.%Y")+'.csv',
                 href="",
                 target="_blank",
                   style={'width': '50px', 'display': 'inline-block','position':'relative','margin-left':'7%'}) ]

@app.callback(Output(‘export_link’,‘href’),
[Input(‘ebutton’,‘n_clicks’)],
[State(‘uplift-df’, ‘data’), #DATA FROM PREDICT FUNCTION
State(‘pbutton’,‘n_clicks’),
State(‘uplift_comment’,‘value’)]
)
def export(eclicks,pred_json,pclicks,comment):

if pclicks is None:
    return None
else:
    

    
    
    out_df = pd.read_json(pred_json, orient='split')
    timestamp=out_df['time'].drop_duplicates()

    csv_string=None
    
    
    timestamp=out_df['time'].drop_duplicates()

    df_export = out_df[out_df['DT'] > 0].copy()
    # TODO: add default project name here
    df_export['Project'] = +str(timestamp.iloc[0])
    df_export['Dur'] = '7D'
    df_export['Comment'] = ''
    

    csv_string = df_export.to_csv(index=False, encoding='utf-8')
    csv_string = "data:text/csv;charset=utf-8," + parse.quote(csv_string)

    del df_export
    return csv_string

Is this a caching issue?

I am using an older version of Python, could that be the issue?

As i read you code (i can’t try it out as you example is incomplete), the link is probably updated only after the click event takes place, which would explain the behavior you see. I think the simplest way to enable a one-click download would be to use the Download component. Here is some example code demonstrating the syntax,

import dash
import dash_html_components as html
import pandas as pd

from datetime import datetime as dt
from dash.dependencies import Input, State, Output
from dash.exceptions import PreventUpdate
from dash_extensions.snippets import send_data_frame
from dash_extensions import Download

app = dash.Dash()
app.layout = html.Div([
    # Your layout here.
    Download(id="download")
])

@app.callback(Output('download', 'data'), [Input('ebutton', 'n_clicks')], [State('uplift-df', 'data')])
def export(eclicks, pred_json):
    if eclicks is None:
        raise PreventUpdate
    # Prepare df for export.
    out_df = pd.read_json(pred_json, orient='split')
    timestamp = out_df['time'].drop_duplicates()
    df_export = out_df[out_df['DT'] > 0].copy()
    # TODO: add default project name here
    df_export['Project'] = +str(timestamp.iloc[0])
    df_export['Dur'] = '7D'
    df_export['Comment'] = ''
    return send_data_frame(df_export.to_csv, 'DT_' + dt.today().strftime("%m.%d.%Y") + '.csv')

For more details, see this post.

Thanks, this worked.

Is there a way to omit the index column in send_data_frame?

Yes, just add add index=False to the send_data_frame call. All extra keyword arguments are passed to pandas.

Thanks, i was making the mistake of putting index=False after the df_export.to_csv part of the command instead of at the end of the command after ‘.csv’