Raw data download working locally and not online

Hey,

Basically the title. When running locally, the downloaded .xlsx is perfect but once online I get the error Excel cannot open the file “rawdata.xlsx” because the file format or file extension is not valid.

Had to dig around a lot in the different “download raw data” topics to get it working locally, so maybe the error comes from there? Can’t really tell. Seems weird to me that it works perfectly locally but not online.

Here is the code:

# Inside app layout
html.A('Download Data', id='download-link', download="rawdata.xlsx", href="", target="_blank")

# [...]

# Creating the excel file & letting user download it
@app.callback(Output('download-link', 'href'), 
             [Input('memory-output', 'data')])
def update_download_link(data):
    # skipping details of variables used to create the excel file, can add them if required

    strIO = io.BytesIO()
    excel_writer = pd.ExcelWriter(strIO, engine="xlsxwriter")

    for output in list_of_outputs:
      temp = pd.DataFrame(index=np.arange(0,tree__periods+1))
      temp.loc[:,0] = pd.Series(output[0])

      for j in range(1, tree__periods+1):
        temp.loc[:, j] = pd.Series(output[startbis[j]:endbis[j]+1])

      temp.index = np.arange(1, tree__periods+2)
      temp.to_excel(excel_writer, sheet_name=f"{list_of_names[counter]}")
      counter += 1

    excel_writer.save()
    strIO.seek(0)

    media_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    data = base64.b64encode(strIO.read()).decode("utf-8")
    href_data_downloadable = f'data:{media_type};base64,{data}'
    return href_data_downloadable 

If relevant, find here the excels local and online: Dash excels - Google Drive
Local is perfect and online cannot be opened.

Any help would be greatly appreciated, thanks ! :slight_smile:

Update: have tried another way to create & update the file, found here (https://stackoverflow.com/questions/57272903/programmatically-download-a-file-from-flask-dash)

The problem did not go away: excel can be downloaded and works perfectly locally, and cannot be opened if downloaded online.

@app.callback(Output('download-link', 'href'), 
             [Input('memory-output', 'data')])
def update_href(data):
# [...]

    relative_filename = os.path.join('downloads','{}-download.xlsx'.format("data"))
    absolute_filename = os.path.join(os.getcwd(), relative_filename)

    writer = pd.ExcelWriter(absolute_filename)

    for output in list_of_outputs:
      temp = pd.DataFrame(index=np.arange(0,tree__periods+1))
      temp.loc[:,0] = pd.Series(output[0])
      for j in range(1, tree__periods+1):
        temp.loc[:, j] = pd.Series(output[startbis[j]:endbis[j]+1])

      temp.index = np.arange(1, tree__periods+2)
      temp.to_excel(writer, sheet_name=f"{list_of_names[counter]}")
      counter += 1

    writer.save()
    return f'/{relative_filename}'


@app.server.route('/downloads/<path:path>')
def serve_static(path):
    root_dir = os.getcwd()
    return flask.send_from_directory(os.path.join(root_dir, 'downloads'), path)

Any ideas what might cause this problem?

EDIT: while trying to open the online excel, I changed its type from .xlsx to .csv and found out this:

It appears that once online, the html.A link reference changed to the html of a dash component (for both methods). But what causes this change, given that everything works fine locally ?

anyone has an idea? :frowning:

The download component might solve your issue,

1 Like

I believe it just did. I cannot thank you enough. Deadline for my thesis is coming up soon, and I really needed this to work out. Thanks man.

On a different note, I encountered the same bug as this guy

Where you tried to help him as well. I followed your advice and checked the heroku log, and it appeared that xlsxwriter was not imported; simply had to add it to requirements.txt.

Once again, thanks so much. Have a great one!

EDIT: the data for the excel is taken from charts, which vary on user inputs. Everytime I change an input, the excel is re-downloaded automatically. Do you know how to prevent this specific callback from being called every input change, and only called when I click on the button?

If you only intend the download to be triggered on click, you should add the data as State instead of Input :slight_smile:

1 Like