Improving page performance

Friends, my fight previously was to update the data automatically, this case was solved with the code below:
The thing is, it was insanely slow.
Assuming my df_general_data_func function correctly retrieves my dataframe (I certify that this is true) .
what could I do to improve the performance of my charts and tables?

'''
*** Projeto dentro da pasta ProjetoDash ***
pip install openpyxl
pip3 install psycopg2
pip3 install peewee
pip3 install dash
pip3 install pandas
pip install dash-bootstrap-components
pip install dash-bootstrap-templates
https://docs.microsoft.com/en-GB/cpp/windows/latest-supported-vc-redist?view=msvc-170

No PowerShell rode o comando:
Set-ExecutionPolicy Unrestricted

'''
from datetime import date
import plotly.graph_objs as go
import dash
from dash import html, dcc, Input, Output, State, dash_table
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd

from dash_bootstrap_templates import ThemeSwitchAIO

# Importei meu dataframe do arquivo movimento_geral.py
from movimento_geral import df_dados_gerais_func  # , df_pivot
from graficos_geral import graficos
from tabela_geral import tabelas

# Formatação das tabelas
formatted = {'specifier': ',.2f', 'locale': {'group': '.', 'decimal': ',', }}

# Note que são muitos os dados, isso deve ser fitrado por ANO mas por enquanto limito o número de linhas com .head(15)
# este não é um gráfico adequado para mostrar nomes de produtos.
# print(df_dados_gerais_bar.head(15))

# import theme changer
from dash_bootstrap_templates import ThemeSwitchAIO

# ================================================================== #
from flask import Flask

dbc_css = "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates/dbc.min.css"

server = Flask(__name__)

app = dash.Dash(__name__, server=server, suppress_callback_exceptions=True,
                external_stylesheets=[dbc.themes.BOOTSTRAP, dbc_css])

# ============================Styles================================ #
tab_card = {'height': '100%'}

main_config = {
    'hovermode': 'x unified',
    'legend': {
        'yanchor': 'top',
        'y': 0.9,
        'xanchor': 'left',
        'x': 0.1,
        'title': {'text': None},
        'font': {'color': 'white'},
        'bgcolor': 'rgba(0,0,0,0.0)'},
    'margin': {'l': 0, 'r': 0, 't': 20, 'b': 0}
}


#df_dados_gerais = meus_dados()
# Aparência do sistema, cuidado com a ordem do Template_theme1 e 2
# em relação a url_teme
template_theme1 = 'cyborg'
template_theme2 = 'spacelab'
url_theme1 = dbc.themes.CYBORG
url_theme2 = dbc.themes.SPACELAB

# To dict - Para salvar no dcc.store
df = df_dados_gerais_func()

# Separando Cidades + Global
s1_cidade_bairros = df.groupby(['CIDADE', 'BAIRRO'])['TOTAL_OPERACAO'].sum().reset_index()
s2_todos = pd.DataFrame()
s2_todos['CIDADE'] = ['TODAS']
s2_todos['BAIRRO'] = ['TODOS']
s2_todos['TOTAL_OPERACAO'] = [0]
cidade_bairros = pd.concat([s1_cidade_bairros, s2_todos], ignore_index=True)



app.layout = dbc.Container([
    dcc.Store(id='store-data', data=df.to_dict('records'), storage_type='memory'),
    dcc.Interval(id='interval-component',
                interval=3600 * 1000,), 
    dbc.Row([
        dbc.Col([
            dbc.Card([
                dbc.CardBody([
                    dbc.Row([
                        dbc.Col([
                            html.Legend("Bag Sales Metrics")
                        ], sm=9),
                        # dbc.Col([         
                        #    html.I(className='fa fa-gamepad', style={'font-size': '300%'})
                        # ], sm=3, align="left")
                    ]),
                    dbc.Row([
                        dbc.Col([
                            ThemeSwitchAIO(aio_id="theme", themes=[url_theme1, url_theme2]),
                            html.Legend("Rika Embalagens")
                        ])
                    ], style={'margin-top': '10px'}),
                    dbc.Row([
                        dbc.Button( "Visite o Site", href="https://ajuda.alterdata.com.br/suporteexpress",
                                target="_blank", id="salva_excel")
                    ], style={'margin-top': '10px'})
                ])
            ], style=tab_card)
        ], sm=12, lg=3),

        dbc.Col([
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardBody([
                            dbc.Col([
                                # html.H5('Escolha o ano da sua pesquisa.', style={"font-weight": "bold"}),
                                dbc.Label("Escolha o ano da sua pesquisa."),
                                dcc.Slider(id='year-slider',
                                        min=int(df['ANO'][1]),
                                        max=int(df['ANO'].max()),
                                        marks={str(year): str(year) for year in
                                                sorted(df['ANO'].unique())},
                                        value=int(df['ANO'].max()),
                                        step=None,
                                        tooltip={'always_visible': False, 'placement': 'bottom'},
                                        className="mb-2"),
                            ], sm=12, style={'margin-top': '7px'}),
                        ])
                    ], style=tab_card)
                ])
            ]),

            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardBody([
                            dbc.Col([
                                dbc.Label("Marque os mezes de sua pesquisa."),
                                dbc.Checklist(
                                    options=[
                                        {"label": "JAN", "value": 1},
                                        {"label": "FEV", "value": 2},
                                        {"label": "MAR", "value": 3},
                                        {"label": "ABR", "value": 4},
                                        {"label": "MAI", "value": 5},
                                        {"label": "JUN", "value": 6},
                                        {"label": "JUL", "value": 7},
                                        {"label": "AGO", "value": 8},
                                        {"label": "SET", "value": 9},
                                        {"label": "OUT", "value": 10},
                                        {"label": "NOV", "value": 11},
                                        {"label": "DEZ", "value": 12},
                                    ],
                                    #1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
                                    value=[11],
                                    id="check-inline-mes",
                                    inline=True,
                                    # switch=True,
                                ),
                            ], style={'margin-top': '7px'})
                        ])

                    ], style=tab_card)
                ], sm=12, lg=12),
            ], className='g-2 my-auto')
        ], sm=12, lg=9)

    ], className='g-2 my-auto', style={'margin-top': '7px'}),

    # Row 2
    dbc.Row([

        dbc.Col([
            dbc.Card([
                dbc.CardBody([
                    dbc.Row([
                        dbc.Col([
                            html.H5('Filtro por Cidade', style={"font-weight": "bold"}),
                            dcc.Dropdown(id='drop-cidade', multi=True, value=['TODAS', ],
                                        options=[{'label': name, 'value': name} for name in
                                                cidade_bairros['CIDADE'].unique()], className='dbc'),
                        ])
                    ])
                ])
            ], style=tab_card)
        ], sm=12, lg=6),

        dbc.Col([
            dbc.Card([
                dbc.CardBody([
                    dbc.Row([
                        dbc.Col([
                            html.H5('Filtro por Bairro', style={"font-weight": "bold"}),
                            dcc.Dropdown(id='drop-bairro', multi=True, value=['TODOS', ], className='dbc'),
                        ])
                    ])
                ])
            ], style=tab_card)
        ], sm=12, lg=6),

    ], className='g-2 my-auto', style={'margin-top': '7px'}),

    dbc.Row([
        dbc.Col([

            dbc.Tabs(
                [
                    dbc.Tab(
                        label="Gráficos", activeTabClassName="fw-bold fst-italic",
                        # active_tab_style={"textTransform": "uppercase"},
                        children=html.Div(graficos, className="p-4 border"),
                    ),
                    dbc.Tab(
                        label="Tabelas", activeTabClassName="fw-bold fst-italic",
                        # active_tab_style={"textTransform": "uppercase"},                        
                        # label="tab 2", active_label_style={"color": "#FB79B3"}
                        children=html.Div(tabelas, className="p-4 border"),
                    ),
                ], className="dbc",
            ),
        ], sm=12, lg=12)
    ], className='g-2 my-auto', style={'margin-top': '7px'})

], fluid=True, style={'height': '100vh'})




# * * * * * A FAZER * * * * *
# 1 - Adicionar filtro de canceladas.
# 2 - Adicionar check "Marca todas" nos meses.
# 3 - Adicionar Painel de valores:
#     a) Vendas
#     b) Devolução
#     c) Compras
#     a) Entradas


# ======== Callbacks ========== #

@app.callback(
    Output('store-data', 'data'),
    Input('interval-component', 'n_intervals'),
)
def atualiza_dados(n_intervals):
    print(f'Atualizando....{n_intervals}')
    df = df_dados_gerais_func()
    print('Atualizado!')
    return df.to_dict('records')



@app.callback(
    Output('drop-bairro', 'options'),
    Input('drop-cidade', 'value'))
def set_cities_options(selected_country):
    mask = cidade_bairros['CIDADE'].isin(selected_country)
    df_cidade_bairros = cidade_bairros.loc[mask]

    return [{'label': i, 'value': i} for i in df_cidade_bairros['BAIRRO'].unique()]


# Pie Charts
@app.callback(
    Output('graph0', 'figure'),
    Input('year-slider', 'value'),
    Input('drop-cidade', 'value'),
    Input('check-inline-mes', 'value'),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
    Input('drop-bairro', 'value'),
    Input('store-data', 'data'),
    Input('interval-component', 'n_intervals'),
)
def graph0(date, dropdown_cidade, mes, toggle, dropdown_bairro, d, n_intervals):
    template = template_theme1 if toggle else template_theme2

    df_dados_gerais = pd.DataFrame.from_dict(d)

    if 'TODAS' in dropdown_cidade:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')
    else:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['CIDADE'].isin(dropdown_cidade)) & \
            (df_dados_gerais['BAIRRO'].isin(dropdown_bairro)) & (df_dados_gerais['MES'].isin(mes))  & (df_dados_gerais['CANCELADO'] != '*')

    df_subplot = df_dados_gerais.loc[mask]
    # Cria o mask de df_dados_gerais e faz os filtros
    # procura em df_dados_gerais as cidades do dropdown
    # cria novo objeto df_subplot recebendo o que aparecer de df_dados_gerais.loc[mask]    

    df_groups_v = df_subplot[df_subplot['OPERACAO'] == 'V'].groupby(['GRUPO'])[['TOTAL_OPERACAO']].sum()
    df_groups_v = df_groups_v.reset_index()
    df_groups_v.sort_values(by=['TOTAL_OPERACAO'], ascending=False, inplace=True)
    # df_subplot.to_excel('C:/Users/EliasPai/Desktop/df_groups.xlsx')

    df_groups_s = df_subplot[df_subplot['OPERACAO'] == 'S'].groupby(['GRUPO'])[['TOTAL_OPERACAO']].sum()
    df_groups_s = df_groups_s.reset_index()
    df_groups_s.sort_values(by=['TOTAL_OPERACAO'], ascending=False, inplace=True)

    df_groups_c = df_subplot[df_subplot['OPERACAO'] == 'C'].groupby(['GRUPO'])[['TOTAL_OPERACAO']].sum()
    df_groups_c = df_groups_c.reset_index()
    df_groups_c.sort_values(by=['TOTAL_OPERACAO'], ascending=False, inplace=True)

    df_groups_e = df_subplot[df_subplot['OPERACAO'] == 'E'].groupby(['GRUPO'])[['TOTAL_OPERACAO']].sum()
    df_groups_e = df_groups_e.reset_index()
    df_groups_e.sort_values(by=['TOTAL_OPERACAO'], ascending=False, inplace=True)

    subplot_topgames = make_subplots(rows=1, cols=4,
                                    specs=[[{"type": "pie"}, {"type": "pie"}, {"type": "pie"}, {"type": "pie"}]],
                                    subplot_titles=(
                                    "<b>Vendas</b>", "<b>Saídas</b>", "<b>Compras</b>", "<b>Entradas</b>"))

    values_v = df_groups_v['TOTAL_OPERACAO']
    subplot_topgames.add_trace(go.Pie(
        labels=df_groups_v['GRUPO'], values=values_v, hole=.2), row=1, col=1)

    subplot_topgames.add_trace(go.Pie(
        labels=df_groups_s['GRUPO'], values=df_groups_s['TOTAL_OPERACAO'], hole=.2), row=1, col=2)

    subplot_topgames.add_trace(go.Pie(
        labels=df_groups_c['GRUPO'], values=df_groups_c['TOTAL_OPERACAO'], hole=.2), row=1, col=3)

    subplot_topgames.add_trace(go.Pie(
        labels=df_groups_e['GRUPO'], values=df_groups_e['TOTAL_OPERACAO'], hole=.2), row=1, col=4)

    subplot_topgames.update_layout(margin={"l": 0, "r": 0, "t": 20, "b": 0}, height=200, template=template)

    return subplot_topgames


# --------------------------------------------------------------------------------------------

# Graph1 - Horizontal Bars
@app.callback(
    Output('graph1', 'figure'),
    Input('year-slider', 'value'),
    Input('drop-cidade', 'value'),
    Input('check-inline-mes', 'value'),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
    Input('drop-bairro', 'value'),
    Input('store-data', 'data'),
    Input('interval-component', 'n_intervals'),    
)
def fig1(date, dropdown_cidade, mes, toggle, dropdown_bairro, d, n_intervals):
    template = template_theme1 if toggle else template_theme2

    df_dados_gerais = pd.DataFrame.from_dict(d)

    if 'TODAS' in dropdown_cidade:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') &  \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')
    else:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') & \
            (df_dados_gerais['CIDADE'].isin(dropdown_cidade)) & (df_dados_gerais['BAIRRO'].isin(dropdown_bairro)) & \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')

    df_topglobal = df_dados_gerais.loc[mask]

    df_topglobal = df_topglobal.groupby(['VENDEDOR'])[['TOTAL_OPERACAO']].sum()
    df_topglobal = df_topglobal.reset_index()
    df_topglobal.sort_values(by=['TOTAL_OPERACAO'], ascending=False, inplace=True)
    #df_topglobal = df_topglobal.head(10).sort_values(by=['TOTAL_OPERACAO'])
    df_topglobal = df_topglobal.sort_values(by=['TOTAL_OPERACAO'])

    #    df_topglobal.to_excel('C:/Users/EliasPai/Desktop/2021.xlsx')

    text = [f'{x} - R${y:_.2f} '.replace('.', ',').replace('_', '.') for x, y in
            zip(df_topglobal['VENDEDOR'].unique(), df_topglobal['TOTAL_OPERACAO'].unique())]

    fig = go.Figure(go.Bar(x=df_topglobal['TOTAL_OPERACAO'], y=df_topglobal['VENDEDOR'], orientation='h', text=text))
    fig.update_layout(main_config, height=310, xaxis={'title': None, 'showticklabels': False},
                    yaxis={'title': None, 'showticklabels': False}, template=template)
    return fig


# Graph 2 - Line Chart
@app.callback(
    Output('graph2', 'figure'),
    Input('year-slider', 'value'),
    Input('drop-cidade', 'value'),
    Input('check-inline-mes', 'value'),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
    Input('drop-bairro', 'value'),
    Input('store-data', 'data'),
    Input('interval-component', 'n_intervals'),     
)
def long(date, dropdown_cidade, mes, toggle, dropdown_bairro, d, n_intervals):
    template = template_theme1 if toggle else template_theme2

    df_dados_gerais = pd.DataFrame.from_dict(d)

    if 'TODAS' in dropdown_cidade:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') &  \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')
    else:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') & \
            (df_dados_gerais['CIDADE'].isin(dropdown_cidade)) & (df_dados_gerais['BAIRRO'].isin(dropdown_bairro)) & \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')

    df_anos = df_dados_gerais.loc[mask]

    trace = df_anos.groupby('MES')['TOTAL_OPERACAO'].sum().reset_index()

    trace['MES'] = trace['MES'].map({1: 'JAN',
                                    2: 'FEV',
                                    3: 'MAR',
                                    4: 'ABR',
                                    5: 'MAI',
                                    6: 'JUN',
                                    7: 'JUL',
                                    8: 'AGO',
                                    9: 'SET',
                                    10: 'OUT',
                                    11: 'NOV',
                                    12: 'DEZ'},
                                    na_action=None)

    fig_anos = go.Figure(go.Scatter(x=trace['MES'], y=trace['TOTAL_OPERACAO'], mode='lines+markers', fill='tonexty',
                                    name='Global Sales'))

    fig_anos.update_layout(main_config, height=200, xaxis={'title': 'None'}, yaxis={'title': None}, template=template)

    fig_anos.add_annotation(text=f'Vendas em Reais de {date}',
                            xref="paper", yref="paper",
                            font=dict(
                                size=20,
                                color='white'
                            ),
                            align="center", bgcolor="rgba(0,0,0,0.8)", opacity=0.8,
                            x=0.5, y=0.5, showarrow=False)

    return fig_anos


# Indicator 1 and 2
@app.callback(
    Output('card_venda', 'children'),
    Output('card_desconto', 'children'),
    Output('card_devolucao', 'children'),
    Output('card_venda_liquida', 'children'),
    Input('year-slider', 'value'),
    Input('drop-cidade', 'value'),
    Input('check-inline-mes', 'value'),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
    Input('drop-bairro', 'value'),
    Input('store-data', 'data'),
    Input('interval-component', 'n_intervals'),
)
def ind1(date, dropdown_cidade, mes, toggle, dropdown_bairro, d, n_intervals):
    template = template_theme1 if toggle else template_theme2

    df_dados_gerais = pd.DataFrame.from_dict(d)

    if 'TODAS' in dropdown_cidade:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['MES'].isin(mes))
    else:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['CIDADE'].isin(dropdown_cidade)) & \
            (df_dados_gerais['BAIRRO'].isin(dropdown_bairro)) & (df_dados_gerais['MES'].isin(mes))
    

    df_vendas = df_dados_gerais[(df_dados_gerais['OPERACAO'] == 'V') & (df_dados_gerais['CANCELADO'] != '*')].loc[mask]    
    venda_bruta = df_vendas['TOTAL_OPERACAO'].sum()

    df_desconto = df_dados_gerais[(df_dados_gerais['OPERACAO'] == 'V') & (df_dados_gerais['CANCELADO'] != '*')].loc[mask].drop_duplicates(subset='NUMERO')
    df_desconto = df_desconto['DESCONTO_GLOBAL'].sum() 
    desconto = df_desconto

    troca_devolucao = ['T', 'D']
    df_devolucao = df_dados_gerais[(df_dados_gerais['OPERACAO'] == 'E') & \
                                (df_dados_gerais['DEVOLUCAO'].isin(troca_devolucao))].loc[mask]

    #df_devolucao.to_excel('C:/Users/EliasPai/Desktop/df_devolucao.xlsx') 
    devolucao = df_devolucao['TOTAL_OPERACAO'].sum() - df_devolucao['DESCONTO_GLOBAL'].sum()

    venda_liquida = venda_bruta - df_desconto


    return f'Vendas: R${venda_bruta:_.2f} '.replace('.', ',').replace('_', '.'), \
        f'Descontos: R${desconto:_.2f} '.replace('.', ',').replace('_', '.'), \
        f'Devoluções: R${devolucao:_.2f} '.replace('.', ',').replace('_', '.'), \
        f'Total: R${venda_liquida:_.2f} '.replace('.', ',').replace('_', '.')


# Na aba TABELAS, conteúdo da tabela.
@app.callback(
    Output('datatable-data', 'data'),
    Output('datatable-data', 'columns'),
    Input('year-slider', 'value'),
    Input('drop-cidade', 'value'),
    Input('check-inline-mes', 'value'),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
    Input('drop-bairro', 'value'),
    Input('store-data', 'data'),
    Input('interval-component', 'n_intervals'),
    )
    
def update_table(date, dropdown_cidade, mes, toggle, dropdown_bairro, d, n_intervals):
    template = template_theme1 if toggle else template_theme2

    df_dados_gerais = pd.DataFrame.from_dict(d)

    if ('TODAS' in dropdown_cidade):
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') &  \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')
    else:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') & \
            (df_dados_gerais['CIDADE'].isin(dropdown_cidade)) & (df_dados_gerais['BAIRRO'].isin(dropdown_bairro)) & \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')

    #'QT_PRATELEIRA', 'QT_DEPOSITO', 
    df_pivot = pd.pivot_table(
        df_dados_gerais.loc[mask], index=['CODIGO', 'DESCRICAO',
                'ESTOQUE', 'GRUPO',
                'FAMILIA', 'UNIDADE',],
        values='QUANTIDADE',
        columns='MES',
        aggfunc=sum).reset_index().fillna(0)
    
    df_pivot = df_pivot.rename(
        {1: 'JAN', 2: 'FEV', 3: 'MAR', 4: 'ABR', 5: 'MAI', 6: 'JUN', 
        7: 'JUL', 8: 'AGO', 9: 'SET', 10: 'OUT', 11: 'NOV', 12: 'DEZ'}, axis=1)
    
    cols = []

    textCols = ['CODIGO', 'DESCRICAO', 'GRUPO', 'FAMILIA', 'UNIDADE']

    for i in df_pivot.columns:
        if i not in textCols:
            cols.append({"name": str(i),
                    "id": str(i),
                    "type": "numeric",
                    "format": formatted})
        else:
            cols.append({"name": str(i),
                        "id": str(i),
                        "type": "text"})



    return df_pivot.to_dict('records'), cols

if __name__ == '__main__':
    app.run_server(debug=False)

Hello @EliasCoutinho,

It looks like you are using a dcc store to drive your data and then updating everything fairly quickly.

While this is nice to have stuff up to date, it obviously drives down the interface usage.

What you can try is to do server side caching with the dcc.Store, this would allow for less heavy transactions. This can speed up the process some, but it sounds like there is an issue with the updates trickling down.

What if is instead of always updating the dcc.Store you only updated it if something changed. Then you would only refresh charts if that was the case.

Another thing, would be instead of chaining the callbacks, have the interval update the charts and tables directly from the interval query.

What I modified made it quite fast.
It is generating cache on the server.
I just couldn’t get the system to update the new data that is entered into Postgres.
Below is the new code for any tip:

'''
*** Projeto dentro da pasta ProjetoDash ***
pip install openpyxl
pip3 install psycopg2
pip3 install peewee
pip3 install dash
pip3 install pandas
pip install dash-bootstrap-components
pip install dash-bootstrap-templates
https://docs.microsoft.com/en-GB/cpp/windows/latest-supported-vc-redist?view=msvc-170

No PowerShell rode o comando:
Set-ExecutionPolicy Unrestricted

'''
from datetime import date
import plotly.graph_objs as go
import dash
from dash import html, dcc, Input, Output, State, dash_table
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
from flask_caching import Cache

from dash_bootstrap_templates import ThemeSwitchAIO

# Importei meu dataframe do arquivo movimento_geral.py
from movimento_geral import df_dados_gerais_func  # , df_pivot
from graficos_geral import graficos
from tabela_geral import tabelas

# Formatação das tabelas
formatted = {'specifier': ',.2f', 'locale': {'group': '.', 'decimal': ',', }}

# Note que são muitos os dados, isso deve ser fitrado por ANO mas por enquanto limito o número de linhas com .head(15)
# este não é um gráfico adequado para mostrar nomes de produtos.
# print(df_dados_gerais_bar.head(15))

# import theme changer
from dash_bootstrap_templates import ThemeSwitchAIO

# ================================================================== #
from flask import Flask

dbc_css = "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates/dbc.min.css"

server = Flask(__name__)

app = dash.Dash(__name__, server=server, suppress_callback_exceptions=True,
                external_stylesheets=[dbc.themes.BOOTSTRAP, dbc_css])

cache = Cache(app.server, config={
    'CACHE_TYPE': 'filesystem',
    'CACHE_DIR': 'cache-directory'
})

TIMEOUT = 60

@cache.memoize(timeout=TIMEOUT)
def query_data():
    df = df_dados_gerais_func()
    return df

def dataframe():
    return query_data()

# ============================Styles================================ #
tab_card = {'height': '100%'}

main_config = {
    'hovermode': 'x unified',
    'legend': {
        'yanchor': 'top',
        'y': 0.9,
        'xanchor': 'left',
        'x': 0.1,
        'title': {'text': None},
        'font': {'color': 'white'},
        'bgcolor': 'rgba(0,0,0,0.0)'},
    'margin': {'l': 0, 'r': 0, 't': 20, 'b': 0}
}


#df_dados_gerais = meus_dados()
# Aparência do sistema, cuidado com a ordem do Template_theme1 e 2
# em relação a url_teme
template_theme1 = 'cyborg'
template_theme2 = 'spacelab'
url_theme1 = dbc.themes.CYBORG
url_theme2 = dbc.themes.SPACELAB

# To dict - Para salvar no dcc.store
df_dados_gerais = dataframe()

# Separando Cidades + Global
s1_cidade_bairros = df_dados_gerais.groupby(['CIDADE', 'BAIRRO'])['TOTAL_OPERACAO'].sum().reset_index()
s2_todos = pd.DataFrame()
s2_todos['CIDADE'] = ['TODAS']
s2_todos['BAIRRO'] = ['TODOS']
s2_todos['TOTAL_OPERACAO'] = [0]
cidade_bairros = pd.concat([s1_cidade_bairros, s2_todos], ignore_index=True)



app.layout = dbc.Container([
    ##dcc.Store(id='store-data', data=df_dados_gerais.to_dict('records'), storage_type='memory'),
    dcc.Interval(id='interval-component',
                interval=15 * 1000,), 
    dbc.Row([
        dbc.Col([
            dbc.Card([
                dbc.CardBody([
                    dbc.Row([
                        dbc.Col([
                            html.Legend("Bag Sales Metrics")
                        ], sm=9),
                        # dbc.Col([         
                        #    html.I(className='fa fa-gamepad', style={'font-size': '300%'})
                        # ], sm=3, align="left")
                    ]),
                    dbc.Row([
                        dbc.Col([
                            ThemeSwitchAIO(aio_id="theme", themes=[url_theme1, url_theme2]),
                            html.Legend("Rika Embalagens")
                        ])
                    ], style={'margin-top': '10px'}),
                    dbc.Row([
                        dbc.Button( "Visite o Site", href="https://ajuda.alterdata.com.br/suporteexpress",
                                target="_blank", id="salva_excel")
                    ], style={'margin-top': '10px'})
                ])
            ], style=tab_card)
        ], sm=12, lg=3),

        dbc.Col([
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardBody([
                            dbc.Col([
                                # html.H5('Escolha o ano da sua pesquisa.', style={"font-weight": "bold"}),
                                dbc.Label("Escolha o ano da sua pesquisa."),
                                dcc.Slider(id='year-slider',
                                        min=int(df_dados_gerais['ANO'][1]),
                                        max=int(df_dados_gerais['ANO'].max()),
                                        marks={str(year): str(year) for year in
                                                sorted(df_dados_gerais['ANO'].unique())},
                                        value=int(df_dados_gerais['ANO'].max()),
                                        step=None,
                                        tooltip={'always_visible': False, 'placement': 'bottom'},
                                        className="mb-2"),
                            ], sm=12, style={'margin-top': '7px'}),
                        ])
                    ], style=tab_card)
                ])
            ]),

            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardBody([
                            dbc.Col([
                                dbc.Label("Marque os mezes de sua pesquisa."),
                                dbc.Checklist(
                                    options=[
                                        {"label": "JAN", "value": 1},
                                        {"label": "FEV", "value": 2},
                                        {"label": "MAR", "value": 3},
                                        {"label": "ABR", "value": 4},
                                        {"label": "MAI", "value": 5},
                                        {"label": "JUN", "value": 6},
                                        {"label": "JUL", "value": 7},
                                        {"label": "AGO", "value": 8},
                                        {"label": "SET", "value": 9},
                                        {"label": "OUT", "value": 10},
                                        {"label": "NOV", "value": 11},
                                        {"label": "DEZ", "value": 12},
                                    ],
                                    #1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
                                    value=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
                                    id="check-inline-mes",
                                    inline=True,
                                    # switch=True,
                                ),
                            ], style={'margin-top': '7px'})
                        ])

                    ], style=tab_card)
                ], sm=12, lg=12),
            ], className='g-2 my-auto')
        ], sm=12, lg=9)

    ], className='g-2 my-auto', style={'margin-top': '7px'}),

    # Row 2
    dbc.Row([

        dbc.Col([
            dbc.Card([
                dbc.CardBody([
                    dbc.Row([
                        dbc.Col([
                            html.H5('Filtro por Cidade', style={"font-weight": "bold"}),
                            dcc.Dropdown(id='drop-cidade', multi=True, value=['TODAS', ],
                                        options=[{'label': name, 'value': name} for name in
                                                cidade_bairros['CIDADE'].unique()], className='dbc'),
                        ])
                    ])
                ])
            ], style=tab_card)
        ], sm=12, lg=6),

        dbc.Col([
            dbc.Card([
                dbc.CardBody([
                    dbc.Row([
                        dbc.Col([
                            html.H5('Filtro por Bairro', style={"font-weight": "bold"}),
                            dcc.Dropdown(id='drop-bairro', multi=True, value=['TODOS', ], className='dbc'),
                        ])
                    ])
                ])
            ], style=tab_card)
        ], sm=12, lg=6),

    ], className='g-2 my-auto', style={'margin-top': '7px'}),

    dbc.Row([
        dbc.Col([

            dbc.Tabs(
                [
                    dbc.Tab(
                        label="Gráficos", activeTabClassName="fw-bold fst-italic",
                        # active_tab_style={"textTransform": "uppercase"},
                        children=html.Div(graficos, className="p-4 border"),
                    ),
                    dbc.Tab(
                        label="Tabelas", activeTabClassName="fw-bold fst-italic",
                        # active_tab_style={"textTransform": "uppercase"},                        
                        # label="tab 2", active_label_style={"color": "#FB79B3"}
                        children=html.Div(tabelas, className="p-4 border"),
                    ),
                ], className="dbc",
            ),
        ], sm=12, lg=12)
    ], className='g-2 my-auto', style={'margin-top': '7px'})

], fluid=True, style={'height': '100vh'})




# * * * * * A FAZER * * * * *
# 1 - Adicionar filtro de canceladas.
# 2 - Adicionar check "Marca todas" nos meses.
# 3 - Adicionar Painel de valores:
#     a) Vendas
#     b) Devolução
#     c) Compras
#     a) Entradas


# ======== Callbacks ========== #


@app.callback(
    Output('drop-bairro', 'options'),
    Input('drop-cidade', 'value'))
def set_cities_options(selected_country):
    mask = cidade_bairros['CIDADE'].isin(selected_country)
    df_cidade_bairros = cidade_bairros.loc[mask]

    return [{'label': i, 'value': i} for i in df_cidade_bairros['BAIRRO'].unique()]


# Pie Charts
@app.callback(
    Output('graph0', 'figure'),
    Input('year-slider', 'value'),
    Input('drop-cidade', 'value'),
    Input('check-inline-mes', 'value'),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
    Input('drop-bairro', 'value'),
    
    Input('interval-component', 'n_intervals'),
)
def graph0(date, dropdown_cidade, mes, toggle, dropdown_bairro, n_intervals):
    template = template_theme1 if toggle else template_theme2

    #df_dados_gerais = dataframe()

    if 'TODAS' in dropdown_cidade:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')
    else:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['CIDADE'].isin(dropdown_cidade)) & \
            (df_dados_gerais['BAIRRO'].isin(dropdown_bairro)) & (df_dados_gerais['MES'].isin(mes))  & (df_dados_gerais['CANCELADO'] != '*')

    df_subplot = df_dados_gerais.loc[mask]
    # Cria o mask de df_dados_gerais e faz os filtros
    # procura em df_dados_gerais as cidades do dropdown
    # cria novo objeto df_subplot recebendo o que aparecer de df_dados_gerais.loc[mask]    

    df_groups_v = df_subplot[df_subplot['OPERACAO'] == 'V'].groupby(['GRUPO'])[['TOTAL_OPERACAO']].sum()
    df_groups_v = df_groups_v.reset_index()
    df_groups_v.sort_values(by=['TOTAL_OPERACAO'], ascending=False, inplace=True)
    # df_subplot.to_excel('C:/Users/EliasPai/Desktop/df_groups.xlsx')

    df_groups_s = df_subplot[df_subplot['OPERACAO'] == 'S'].groupby(['GRUPO'])[['TOTAL_OPERACAO']].sum()
    df_groups_s = df_groups_s.reset_index()
    df_groups_s.sort_values(by=['TOTAL_OPERACAO'], ascending=False, inplace=True)

    df_groups_c = df_subplot[df_subplot['OPERACAO'] == 'C'].groupby(['GRUPO'])[['TOTAL_OPERACAO']].sum()
    df_groups_c = df_groups_c.reset_index()
    df_groups_c.sort_values(by=['TOTAL_OPERACAO'], ascending=False, inplace=True)

    df_groups_e = df_subplot[df_subplot['OPERACAO'] == 'E'].groupby(['GRUPO'])[['TOTAL_OPERACAO']].sum()
    df_groups_e = df_groups_e.reset_index()
    df_groups_e.sort_values(by=['TOTAL_OPERACAO'], ascending=False, inplace=True)

    subplot_topgames = make_subplots(rows=1, cols=4,
                                    specs=[[{"type": "pie"}, {"type": "pie"}, {"type": "pie"}, {"type": "pie"}]],
                                    subplot_titles=(
                                    "<b>Vendas</b>", "<b>Saídas</b>", "<b>Compras</b>", "<b>Entradas</b>"))

    values_v = df_groups_v['TOTAL_OPERACAO']
    subplot_topgames.add_trace(go.Pie(
        labels=df_groups_v['GRUPO'], values=values_v, hole=.2), row=1, col=1)

    subplot_topgames.add_trace(go.Pie(
        labels=df_groups_s['GRUPO'], values=df_groups_s['TOTAL_OPERACAO'], hole=.2), row=1, col=2)

    subplot_topgames.add_trace(go.Pie(
        labels=df_groups_c['GRUPO'], values=df_groups_c['TOTAL_OPERACAO'], hole=.2), row=1, col=3)

    subplot_topgames.add_trace(go.Pie(
        labels=df_groups_e['GRUPO'], values=df_groups_e['TOTAL_OPERACAO'], hole=.2), row=1, col=4)

    subplot_topgames.update_layout(margin={"l": 0, "r": 0, "t": 20, "b": 0}, height=200, template=template)

    return subplot_topgames


# --------------------------------------------------------------------------------------------

# Graph1 - Horizontal Bars
@app.callback(
    Output('graph1', 'figure'),
    Input('year-slider', 'value'),
    Input('drop-cidade', 'value'),
    Input('check-inline-mes', 'value'),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
    Input('drop-bairro', 'value'),
    
    Input('interval-component', 'n_intervals'),    
)
def fig1(date, dropdown_cidade, mes, toggle, dropdown_bairro, n_intervals):
    template = template_theme1 if toggle else template_theme2

    #df_dados_gerais = dataframe()

    if 'TODAS' in dropdown_cidade:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') &  \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')
    else:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') & \
            (df_dados_gerais['CIDADE'].isin(dropdown_cidade)) & (df_dados_gerais['BAIRRO'].isin(dropdown_bairro)) & \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')

    df_topglobal = df_dados_gerais.loc[mask]

    df_topglobal = df_topglobal.groupby(['VENDEDOR'])[['TOTAL_OPERACAO']].sum()
    df_topglobal = df_topglobal.reset_index()
    df_topglobal.sort_values(by=['TOTAL_OPERACAO'], ascending=False, inplace=True)
    #df_topglobal = df_topglobal.head(10).sort_values(by=['TOTAL_OPERACAO'])
    df_topglobal = df_topglobal.sort_values(by=['TOTAL_OPERACAO'])

    #    df_topglobal.to_excel('C:/Users/EliasPai/Desktop/2021.xlsx')

    text = [f'{x} - R${y:_.2f} '.replace('.', ',').replace('_', '.') for x, y in
            zip(df_topglobal['VENDEDOR'].unique(), df_topglobal['TOTAL_OPERACAO'].unique())]

    fig = go.Figure(go.Bar(x=df_topglobal['TOTAL_OPERACAO'], y=df_topglobal['VENDEDOR'], orientation='h', text=text))
    fig.update_layout(main_config, height=310, xaxis={'title': None, 'showticklabels': False},
                    yaxis={'title': None, 'showticklabels': False}, template=template)
    return fig


# Graph 2 - Line Chart
@app.callback(
    Output('graph2', 'figure'),
    Input('year-slider', 'value'),
    Input('drop-cidade', 'value'),
    Input('check-inline-mes', 'value'),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
    Input('drop-bairro', 'value'),
    
    Input('interval-component', 'n_intervals'),     
)
def long(date, dropdown_cidade, mes, toggle, dropdown_bairro, n_intervals):
    template = template_theme1 if toggle else template_theme2

    #df_dados_gerais = dataframe()

    if 'TODAS' in dropdown_cidade:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') &  \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')
    else:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') & \
            (df_dados_gerais['CIDADE'].isin(dropdown_cidade)) & (df_dados_gerais['BAIRRO'].isin(dropdown_bairro)) & \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')

    df_anos = df_dados_gerais.loc[mask]

    trace = df_anos.groupby('MES')['TOTAL_OPERACAO'].sum().reset_index()

    trace['MES'] = trace['MES'].map({1: 'JAN',
                                    2: 'FEV',
                                    3: 'MAR',
                                    4: 'ABR',
                                    5: 'MAI',
                                    6: 'JUN',
                                    7: 'JUL',
                                    8: 'AGO',
                                    9: 'SET',
                                    10: 'OUT',
                                    11: 'NOV',
                                    12: 'DEZ'},
                                    na_action=None)

    fig_anos = go.Figure(go.Scatter(x=trace['MES'], y=trace['TOTAL_OPERACAO'], mode='lines+markers', fill='tonexty',
                                    name='Global Sales'))

    fig_anos.update_layout(main_config, height=200, xaxis={'title': 'None'}, yaxis={'title': None}, template=template)

    fig_anos.add_annotation(text=f'Vendas em Reais de {date}',
                            xref="paper", yref="paper",
                            font=dict(
                                size=20,
                                color='white'
                            ),
                            align="center", bgcolor="rgba(0,0,0,0.8)", opacity=0.8,
                            x=0.5, y=0.5, showarrow=False)

    return fig_anos


# Indicator 1 and 2
@app.callback(
    Output('card_venda', 'children'),
    Output('card_desconto', 'children'),
    Output('card_devolucao', 'children'),
    Output('card_venda_liquida', 'children'),
    Input('year-slider', 'value'),
    Input('drop-cidade', 'value'),
    Input('check-inline-mes', 'value'),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
    Input('drop-bairro', 'value'),
    
    Input('interval-component', 'n_intervals'),
)
def ind1(date, dropdown_cidade, mes, toggle, dropdown_bairro, n_intervals):
    template = template_theme1 if toggle else template_theme2

    #df_dados_gerais = dataframe()

    if 'TODAS' in dropdown_cidade:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['MES'].isin(mes))
    else:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['CIDADE'].isin(dropdown_cidade)) & \
            (df_dados_gerais['BAIRRO'].isin(dropdown_bairro)) & (df_dados_gerais['MES'].isin(mes))
    

    df_vendas = df_dados_gerais[(df_dados_gerais['OPERACAO'] == 'V') & (df_dados_gerais['CANCELADO'] != '*')].loc[mask]    
    venda_bruta = df_vendas['TOTAL_OPERACAO'].sum()

    df_desconto = df_dados_gerais[(df_dados_gerais['OPERACAO'] == 'V') & (df_dados_gerais['CANCELADO'] != '*')].loc[mask].drop_duplicates(subset='NUMERO')
    df_desconto = df_desconto['DESCONTO_GLOBAL'].sum() 
    desconto = df_desconto

    troca_devolucao = ['T', 'D']
    df_devolucao = df_dados_gerais[(df_dados_gerais['OPERACAO'] == 'E') & \
                                (df_dados_gerais['DEVOLUCAO'].isin(troca_devolucao))].loc[mask]

    #df_devolucao.to_excel('C:/Users/EliasPai/Desktop/df_devolucao.xlsx') 
    devolucao = df_devolucao['TOTAL_OPERACAO'].sum() - df_devolucao['DESCONTO_GLOBAL'].sum()

    venda_liquida = venda_bruta - df_desconto


    return f'Vendas: R${venda_bruta:_.2f} '.replace('.', ',').replace('_', '.'), \
        f'Descontos: R${desconto:_.2f} '.replace('.', ',').replace('_', '.'), \
        f'Devoluções: R${devolucao:_.2f} '.replace('.', ',').replace('_', '.'), \
        f'Total: R${venda_liquida:_.2f} '.replace('.', ',').replace('_', '.')


# Na aba TABELAS, conteúdo da tabela.
@app.callback(
    Output('datatable-data', 'data'),
    Output('datatable-data', 'columns'),
    Input('year-slider', 'value'),
    Input('drop-cidade', 'value'),
    Input('check-inline-mes', 'value'),
    Input(ThemeSwitchAIO.ids.switch("theme"), "value"),
    Input('drop-bairro', 'value'),
    
    Input('interval-component', 'n_intervals'),
    )
    
def update_table(date, dropdown_cidade, mes, toggle, dropdown_bairro, n_intervals):
    template = template_theme1 if toggle else template_theme2

    #df_dados_gerais = dataframe()

    if ('TODAS' in dropdown_cidade):
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') &  \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')
    else:
        mask = (df_dados_gerais['ANO'] == date) & (df_dados_gerais['OPERACAO'] == 'V') & \
            (df_dados_gerais['CIDADE'].isin(dropdown_cidade)) & (df_dados_gerais['BAIRRO'].isin(dropdown_bairro)) & \
            (df_dados_gerais['MES'].isin(mes)) & (df_dados_gerais['CANCELADO'] != '*')

    #'QT_PRATELEIRA', 'QT_DEPOSITO', 
    df_pivot = pd.pivot_table(
        df_dados_gerais.loc[mask], index=['CODIGO', 'DESCRICAO',
                'ESTOQUE', 'GRUPO',
                'FAMILIA', 'UNIDADE',],
        values='QUANTIDADE',
        columns='MES',
        aggfunc=sum).reset_index().fillna(0)
    
    df_pivot = df_pivot.rename(
        {1: 'JAN', 2: 'FEV', 3: 'MAR', 4: 'ABR', 5: 'MAI', 6: 'JUN', 
        7: 'JUL', 8: 'AGO', 9: 'SET', 10: 'OUT', 11: 'NOV', 12: 'DEZ'}, axis=1)
    
    cols = []

    textCols = ['CODIGO', 'DESCRICAO', 'GRUPO', 'FAMILIA', 'UNIDADE']

    for i in df_pivot.columns:
        if i not in textCols:
            cols.append({"name": str(i),
                    "id": str(i),
                    "type": "numeric",
                    "format": formatted})
        else:
            cols.append({"name": str(i),
                        "id": str(i),
                        "type": "text"})
    return df_pivot.to_dict('records'), cols


if __name__ == '__main__':
    app.run_server(debug=False)

I think you need to uncomment these lines, and then it should work.

Then. Uncommenting will be very slow.

That is what updates your dataframe which would update your charts, etc.