Download data frame from DASH App

row13 = html.Div([
    dbc.Row([
        dbc.Col([
            html.Button(id='submit-button-get', type='submit', children='Submit', style={'width': '300px'}),

        ], width={"order": "first"}, style={'margin-top': 20, 'margin-left': -235, 'display': 'table-cell',
                                            'verticalAlign': 'middle'}),
        dbc.Col([
            html.Div(id='output_div-get'),
        ])
    ])
])

tab_1_layout = dbc.Container(children=[
    row13
]
)

Could you suggest where to put the download component?

You can put it anywhere, it does not matter (it’s invisible). It just have to be in the layout for the callback to be invoked. I typically put it in the end of the most outer div of the app layout.

So i have just put the Download component with call back and layout.

row13 = html.Div([
    dbc.Row([
        dbc.Col([
            html.Button(id='submit-button-get', type='submit', children='Submit', style={'width': '300px'}),

        ], width={"order": "first"}, style={'margin-top': 20, 'margin-left': -235, 'display': 'table-cell',
                                            'verticalAlign': 'middle'}),
        dbc.Col([
                 html.Div(id='output_div-get'),
                 ])
        dbc.Col([html.Div(Download(id="download"))])
    ])
])


tab_1_layout = dbc.Container(children=[row13
]
)


@app.callback([Output('output_div-fb', 'children'), Output('download', 'children')],
              [Input('submit-button', 'n_clicks')],
              [State('ad_account_id', 'value'),
               State('app_id', 'value'),
               State('access_token', 'value'),
               State('app_secret', 'value'),
               State('metrics', 'value'),
               State('breakdown', 'value'),
               State('start-date', 'date'),
               State('end-date', 'date'),
               ],
              )
def facebook_output(clicks, ad_account_id, app_id, access_token, app_secret, metrics, breakdown,
                    start_date, end_date):
    if clicks is not None:
        my_ad_account = ad_account_id
        my_app_id = app_id
        my_access_token = access_token
        my_app_secret = app_secret
        my_metrics = metrics
        my_breakdown = breakdown
        my_start_date = start_date
        my_end_date = end_date
        my_action_type = 'action_type'
        my_level = 'ad'
        my_time_increment = 1
        FacebookAdsApi.init(my_app_id, my_app_secret, my_access_token,
                            api_version='v5.0')
        me = User(fbid="me")
        new_col_list = my_metrics
        # print(new_col_list)
        act = AdAccount(my_ad_account)
        async_job = act.get_insights(params={'time_range': {'since': my_start_date, 'until': my_end_date},
                                             'breakdowns': list(my_breakdown),
                                             'action_breakdowns': my_action_type, 'level': my_level,
                                             'time_increment': my_time_increment},
                                     fields=list(new_col_list))
        df = pd.DataFrame(async_job)
        dff = df[new_col_list]
        html.Br()
        report_name = 'facebook_{}.csv'.format(datetime.datetime.now().strftime("%Y_%m_%d-%H_%M_%S"))
        str_io = io.StringIO()
        dff.to_csv(str_io, index=False)
        content = str_io.getvalue().encode('utf-8')
        return dict(filename=report_name, content=content, type="text/csv")

I am getting this error

dash.exceptions.InvalidCallbackReturnValue: The callback ..output_div-fb.children...download.children.. is a multi-output.
Expected the output type to be a list or tuple but got:

Why do you have two outputs? Shouldn’t it just be one? Also, the target property of the download component is ‘data’, not children, i.e.

@app.callback(Output('download', 'data'),
              [Input('submit-button', 'n_clicks')],

I did the change still getting this error

dash.exceptions.InvalidCallbackReturnValue: The callback for property `data` of component `download`
returned a value which is not JSON serializable.

In general, Dash properties can only be dash components, strings,
dictionaries, numbers, None, or lists of those.

here is the updated call back

@app.callback(Output('download', 'data'),
              [Input('submit-button', 'n_clicks')],
              [State('ad_account_id', 'value'),
               State('app_id', 'value'),
               State('access_token', 'value'),
               State('app_secret', 'value'),
               State('metrics', 'value'),
               State('breakdown', 'value'),
               State('start-date', 'date'),
               State('end-date', 'date'),
               ],
              )
def facebook_output(clicks, ad_account_id, app_id, access_token, app_secret, metrics, breakdown,
                    start_date, end_date):
    if clicks is not None:
        my_ad_account = ad_account_id
        my_app_id = app_id
        my_access_token = access_token
        my_app_secret = app_secret
        my_metrics = metrics
        my_breakdown = breakdown
        my_start_date = start_date
        my_end_date = end_date
        my_action_type = 'action_type'
        my_level = 'ad'
        my_time_increment = 1
        FacebookAdsApi.init(my_app_id, my_app_secret, my_access_token,
                            api_version='v5.0')
        me = User(fbid="me")
        new_col_list = my_metrics
        # print(new_col_list)
        act = AdAccount(my_ad_account)
        async_job = act.get_insights(params={'time_range': {'since': my_start_date, 'until': my_end_date},
                                             'breakdowns': list(my_breakdown),
                                             'action_breakdowns': my_action_type, 'level': my_level,
                                             'time_increment': my_time_increment},
                                     fields=list(new_col_list))
        df = pd.DataFrame(async_job)
        dff = df[new_col_list]
        html.Br()
        report_name = 'facebook_{}.csv'.format(datetime.datetime.now().strftime("%Y_%m_%d-%H_%M_%S"))
        str_io = io.StringIO()
        dff.to_csv(str_io, index=False)
        content = str_io.getvalue().encode('utf-8')
        return dict(filename=report_name, content=content, type="text/csv")

It looks like something is wrong with the way you are formatting the data. I just release a new version (0.0.15) of the dash-extensions, which contains performance improvements and syntax sugar,

For your particular case, with the new version, i guess you could do something like,

...
from dash_extensions.download import send_data_frame
df = pd.DataFrame(async_job)
dff = df[new_col_list]
report_name = 'facebook_{}.csv'.format(datetime.datetime.now().strftime("%Y_%m_%d-%H_%M_%S"))
return send_data_frame(dff.to_csv, report_name)

are you saying with download component i should call the send_data_frame? also i tried with “pip install dash-extensions==0.0.15” its installed but while importing its not working.

If you look at the link, you can see a full example. Your code should be adopted accordingly, i.e.

from dash_extensions.download import send_data_frame

@app.callback(Output('download', 'data'),
              [Input('submit-button', 'n_clicks')],
              [State('ad_account_id', 'value'),
               State('app_id', 'value'),
               State('access_token', 'value'),
               State('app_secret', 'value'),
               State('metrics', 'value'),
               State('breakdown', 'value'),
               State('start-date', 'date'),
               State('end-date', 'date'),
               ],
              )
def facebook_output(clicks, ad_account_id, app_id, access_token, app_secret, metrics, breakdown,
                    start_date, end_date):
    if clicks is not None:
        my_ad_account = ad_account_id
        my_app_id = app_id
        my_access_token = access_token
        my_app_secret = app_secret
        my_metrics = metrics
        my_breakdown = breakdown
        my_start_date = start_date
        my_end_date = end_date
        my_action_type = 'action_type'
        my_level = 'ad'
        my_time_increment = 1
        FacebookAdsApi.init(my_app_id, my_app_secret, my_access_token,
                            api_version='v5.0')
        me = User(fbid="me")
        new_col_list = my_metrics
        # print(new_col_list)
        act = AdAccount(my_ad_account)
        async_job = act.get_insights(params={'time_range': {'since': my_start_date, 'until': my_end_date},
                                             'breakdowns': list(my_breakdown),
                                             'action_breakdowns': my_action_type, 'level': my_level,
                                             'time_increment': my_time_increment},
                                     fields=list(new_col_list))
        df = pd.DataFrame(async_job)
        dff = df[new_col_list]
        report_name = 'facebook_{}.csv'.format(datetime.datetime.now().strftime("%Y_%m_%d-%H_%M_%S"))
        return send_data_frame(dff.to_csv, report_name)

I guess something is wrong with the package i tried to run your example from here “https://pypi.org/project/dash-extensions/” seems not working its giving me Download package error, thought i already have installed 0.0.15.

error:

Traceback (most recent call last):
  File "C:/Dash_App/tabs/test.py", line 6, in <module>
    from dash_extensions import Download
  File "C:\myvenv\lib\site-packages\dash_extensions\__init__.py", line 10, in <module>
    from ._imports_ import *
  File "C:\myvenv\lib\site-packages\dash_extensions\_imports_.py", line 1, in <module>
    from .Download import Download
ImportError: cannot import name 'Download' from 'dash_extensions.Download' (C:\myvenv\lib\site-packages\dash_extensions\Download.py)

also in your examples it should be

from dash_extensions.Download import send_data_frame 

not
from dash_extensions.download import send_data_frame

i guess on your imports this Download package is not available.

from .Download import Download
from .Lottie import Lottie

__all__ = [
    "Download",
    "Lottie"
]

Please help me how can I get rid of this import error.

Hmm, i don’t see the import error on my system (Linux). Maybe it’s due to case sensitivity on Windows (i have a file called “download.py” and one called “Download.py” in the same folder). I have tried moving the util functions to snippets.py instead in version 0.0.16 (should be on pypi now), i.e. the imports would be

from dash_extensions import Download
from dash_extensions.snippets import send_data_frame

Does that make any difference on your side?

let me install version 0.0.16 first. is it pip install dash_extensions == 0.0.16?

Almost, in pip it is with a dash rather than underscore,

pip install dash-extensions==0.0.16

In imports, it is with an underscore (it is a little confusing, i know…). Also make sure pip is up to date,

pip install pip --upgrade

Otherwise, it might not find the new package version (at least not om my system).

its working fine now. thank you for your help.

1 Like

Can i get rid of the index part when I am doing this?

return send_data_frame(dff.to_csv, report_name)

Yes, then it would be,

return send_data_frame(lambda x: df.to_csv(x, index=False), report_name)
1 Like

saved…alot of time.

Great! I have improved the syntax slight in version 0.0.18, now additional arguments are passed directly to the writer, i.e. the previous code can now be written as,

return send_data_frame(df.to_csv, report_name, index=False)

Hi @MishD, I’m trying to use the send_data_frame() to dowload the dataframe, but I don´t know why is not working.

@app.callback(Output("download", "data"), [Input("btn", "n_clicks")], [State('alocacao_tb', 'data'),])
def func(n_nlicks, dataset):
    df = pd.DataFrame(dataset)
    print(df)
    return send_data_frame(df.to_excel, "mydf.xls")

this is my code.
When I click in dowload the print(df) is working but nothing happens with the file.

could you help me ?

I got the impor t error for Download, then installed dash_extensions 0.0.16.
Now, I get

ModuleNotFoundError: No module named ‘dash_extensions.enrich’

The Download component has been merged into the main Dash repo as part of the dcc module,