akono-app-v4 / app.py
mzufferey
1210_3
f74de9f
import dash_daq as daq
from settings import *
from utils_fcts import *
import plotly.express as px
from datetime import timedelta
import pandas as pd
import openpyxl
import numpy as np
from dash import dash_table
import pandas as pd
from datetime import datetime, timedelta
from app_settings import *
from plotly.subplots import make_subplots
from dash.dependencies import ALL
# from callbacks.common_callbacks import register_callbacks as register_dashboard_common
from callbacks.tab_répartFréq_callbacks import register_callbacks as register_répartFréq
from callbacks.render_content_callback import register_callbacks as register_render_content
from callbacks.tab_grapheàchoix_callbacks import register_callbacks as register_timeevo
from callbacks.tab_chargedécharge_callbacks import register_callbacks as register_chargedécharge
from callbacks.tab_accueil_callbacks import register_callbacks as register_accueil
##################################### TODO IN PROCESS : dashboard
# https://dash.gallery/dash-manufacture-spc-dashboard/
# https://github.com/plotly/dash-sample-apps/blob/main/apps/dash-manufacture-spc-dashboard/app.py
conn = sqlite3.connect(db_file)
time_df = pd.read_sql_query(f"SELECT * FROM {dbTime_name}", conn)
day_df = pd.read_sql_query(f"SELECT * FROM {dbDayI_name}", conn)
conn.close()
time_df[db_timecol] = pd.to_datetime(time_df[db_timecol])
time_df[db_daycol] = time_df[db_timecol].dt.date
day_df[db_daycol] = pd.to_datetime(day_df[db_daycol])
# Initialiser l'application Dash avec suppression des exceptions de callback
app = dash.Dash(__name__,
external_stylesheets=[dbc.themes.BOOTSTRAP, FONT_AWESOME],
suppress_callback_exceptions=True
)
register_répartFréq(app)
register_render_content(app)
register_chargedécharge(app)
register_timeevo(app)
register_accueil(app)
# Définir la mise en page de l'application
all_confirm_dialogs = [dcc.ConfirmDialog(id=x,message='')
for x in all_confirm_dialogs]
all_maxvar_dialogs = [dcc.ConfirmDialog(id=x,message=popupmsg_maxvar)
for x in ['confirm-dialog-evotime',
'confirm-dialog-daydataP',
'confirm-dialog-daydataI',
]]
all_dates = list(set(day_df[db_daycol]))
all_times = list(set(time_df[db_timecol]))
all_range_pickers = [get_range_picker(x, all_dates) for x in all_range_pickers]
app.layout = html.Div([
dbc.Modal(
[
dbc.ModalHeader("Graph Full Screen"),
dbc.ModalBody(
dcc.Graph(
id='evotime-modal-graph', # Ce sera le graphique dans la modale
)
),
dbc.ModalFooter(
dbc.Button("Close", id="close-modal", className="ml-auto")
),
],
id="evotime-modal-graph-modal",
size="xl",
is_open=False,
),
get_graph_modal(modal_tit="Graphe statistiques",
graph_id="stat-modal-graph",
closebtn_id="close-modal-stat",
modal_id="stat-modal-graph-modal"),
dcc.Store(id='stored_timeDB', data=time_df.to_dict()),
dcc.Store(id='stored_dayDB', data=day_df.to_dict()),
dcc.Store(id='defaut_stored_timeDB', data=time_df.to_dict()),
dcc.Store(id='defaut_stored_dayDB', data=day_df.to_dict()),
dcc.Store(id='stored_stat_dropdownval', data=None),
dcc.Store(id='stored_dataShowDB_dropdownval', data=None),
dcc.Store(id='stored_dataExportDB_dropdownval', data=None),
dcc.Store(id='stored_evotime_dropdownval', data=None),
dcc.Store(id='stored_analyseGraph_dropdownval', data=None),
dcc.Store(id='stored_appXT_dropdownval', data=None),
dcc.Store(id='stored_appBSP_dropdownval', data=None),
dcc.Store(id='stored_appVT_dropdownval', data=None),
dcc.Store(id='stored_fctBat_dropdownval', data=None),
dcc.Store(id='stored_dashMin_dropdownval', data=None),
dcc.Store(id='stored_dashDay_dropdownval', data=None),
dcc.Tabs(id="tabs-example", value='tab-accueil', children=[ # value ici définit l'onglet par défaut
dcc.Tab(label='Accueil', value='tab-accueil',
className='mytab', selected_className='mytab-slctd',
children=[
html.Div([
# html.I(className="fas fa-sun") , html.H3("~ Bienvenue ~",
# style={'textAlign': 'center', 'marginBottom': '20px'}),
html.H3([
html.I(className="fas fa-sun", style={"color": "#FFD700", "marginRight": "10px"}),
# Soleil à gauche
"Bienvenue",
html.I(className="fas fa-sun", style={"color": "#FFD700", "marginLeft": "10px"})
# Soleil à droite
], style={"textAlign": "center", "marginTop": "20px"}),
html.H5("sur la plateforme de visualisation des données Akonolinga",
style={'textAlign': 'center', 'marginBottom': '20px'}),
html.Hr(),
dcc.Checklist(
id='default-data-checkbox',
options=[
{'label': 'Données par défaut', 'value': 'default'},
],
value=['default'], # Coche par défaut
style={'marginBottom': '20px'}
),
html.Div([
dcc.Upload(
id='upload-stored-data',
children=html.Button('Charger des fichiers'),
style={
'width': '100%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'marginBottom': '20px'
},
multiple=True
),
], id='upload-stored-container', style={'display': 'none'}), # Masqué par défaut
html.Div(id='stored-data-content'),
html.Hr(),
dbc.Container([
dbc.Row([
dbc.Col([
dcc.Markdown(""""""),
], width=2),
dbc.Col([
dcc.Markdown("""
**Évolution temporelle** : choisir une base de données puis une ou plusieurs (max. 4) variables ;
visualisation à choix (line, bar, box).
"""),
get_navbtn(lab="Évolution temporelle", id='landpage-btn-evotime')
], width=3),
dbc.Col([
dcc.Markdown(""""""),
], width=2),
dbc.Col([
dcc.Markdown("""
**Bilan charge/décharge** : batterie ; bilan charge/décharge ; nombre de cycles ; variables BSP (barplot) ; température batterie.
"""),
get_navbtn(lab="Charge/décharge", id='landpage-btn-stat')
], width=3),
dbc.Col([
dcc.Markdown(""""""),
], width=2),
]),
dbc.Row([
dbc.Col([
dcc.Markdown(""""""),
], width=2),
dbc.Col([
dcc.Markdown("""
**Répartition fréquences** : fréquences génératrice ou réseau ; XTender.
"""),
get_navbtn(lab="Analyse (Graphes)", id='landpage-btn-analyseGraph')
], width=3),
dbc.Col([
dcc.Markdown(""""""),
], width=2),
dbc.Col([
html.P([
html.B("Données"),
" : Gérer, ajouter ou exporter des données de la base de données. ",
"Obtenez un aperçu des tables disponibles. ",
html.Ul([
html.Li(["Le sous-onglet pour ",
get_nav_link("landpage-data-manage-link", "Gérer les données"),
" permet d'ajouter (fichier(s) csv) ou supprimer des données de la base de données."]),
html.Li(["Le sous-onglet pour ",
get_nav_link("landpage-data-export-link", "Exporter des données"),
" permet de télécharger les données pour une période sélectionnée (.xlsx) ou la base donnée complète (.db)."]),
html.Li(["Le sous-onglet ",
get_nav_link("landpage-data-overview-link", "Aperçu"),
" permet d'afficher une partie du contenu de la base de données."])
], ),
]),
get_navbtn(lab="Données", id='landpage-btn-data')
], width=3),
dbc.Col([
dcc.Markdown(""""""),
], width=2),
]),
], fluid=True)
], style={'padding': '40px', 'backgroundColor': '#f8f9fa'})
]),
dcc.Tab(label='Evolution temporelle', value='tab-evotime',
className='mytab', selected_className='mytab-slctd'),
dcc.Tab(label='Bilan charge-décharge', value='tab-stat',
className='mytab', selected_className='mytab-slctd'),
dcc.Tab(label='Répartition fréquences', value='tab-analyseGraph',
className='mytab', selected_className='mytab-slctd'),
dcc.Tab(label='Données', value='tab-data',
className='mytab', selected_className='mytab-slctd',
children=[
dcc.Tabs(id="subtabs-data", value='subtab-updateDB', children=[
dcc.Tab(label='Gérer les données', value='subtab-updateDB',
className='mysubtab', selected_className='mysubtab-slctd'),
dcc.Tab(label='Exporter des données', value='subtab-exportDB',
className='mysubtab', selected_className='mysubtab-slctd'),
dcc.Tab(label='Aperçu de la base de données', value='subtab-showDB',
className='mysubtab', selected_className='mysubtab-slctd')
])])
]),
dcc.DatePickerSingle(
id='date-picker-dbdata',
date=None,
display_format='DD.MM.YYYY',
min_date_allowed=min(all_times),
max_date_allowed=max(all_times),
disabled_days=[pd.to_datetime(date).date() for date in
pd.date_range(start=min(all_times),
end=max(all_times)).
difference(pd.to_datetime(all_times))],
style={'display': 'none'} # Initialement caché
# attention : pd.date_range(...).retourne un DatetimeIndex
# pd.to_datetime pour convertir all_dates aussi en DatetimeIndex pr comparer
)] +
all_range_pickers +
all_maxvar_dialogs +
all_confirm_dialogs+
[html.Div(id='tabs-content')]
)
# Callback pour gérer la navigation vers les onglets et sous-onglets
@app.callback(
[Output('tabs-example', 'value'),
Output('subtabs-data', 'value')],
[Input('landpage-btn-evotime', 'n_clicks'),
Input('landpage-btn-stat', 'n_clicks'),
Input('landpage-btn-analyseGraph', 'n_clicks'),
Input('landpage-btn-data', 'n_clicks'),
Input('landpage-data-export-link', 'n_clicks'),
Input('landpage-data-overview-link', 'n_clicks'),
Input('landpage-data-manage-link', 'n_clicks')
],
[State('tabs-example', 'value')]
)
def navigate_to_tabs_and_subtabs(*args):
current_tab = args[-1]
ctx = dash.callback_context
# Valeurs par défaut pour les onglets et sous-onglets
tab_value = current_tab or 'tab-accueil'
subtab_appareils_value = 'subtab-bsp' # Valeur par défaut pour les sous-onglets d'appareils
subtab_data_value = 'subtab-updateDB' # Valeur par défaut pour les sous-onglets de données
# Si un bouton est cliqué
if ctx.triggered:
button_id = ctx.triggered[0]['prop_id'].split('.')[0]
# Gestion de la navigation pour les onglets principaux
if button_id in ['landpage-btn-dashboard','landpage-dashb-minutes-link',
'landpage-dashb-dayI-link']:
tab_value = 'tab-dashboard'
if button_id == 'landpage-dashb-minutes-link':
subtab_data_value = 'subtab-minutesdata'
elif button_id == 'landpage-dashb-dayI-link':
subtab_data_value = 'subtab-dayIdata'
elif button_id == 'landpage-btn-evotime':
tab_value = 'tab-evotime'
elif button_id == 'landpage-btn-stat':
tab_value = 'tab-stat'
elif button_id == 'landpage-btn-analyseGraph':
tab_value = 'tab-analyseGraph'
elif button_id in ['landpage-btn-appareils','landpage-btn-appareils2', 'landpage-appareil-variotrack-link',
"landpage-appareil-bsp-link", "landpage-appareil-xtender-link", ]:
tab_value = 'tab-appareils'
if button_id == 'landpage-appareil-variotrack-link':
subtab_appareils_value = 'subtab-variotrack'
elif button_id == 'landpage-appareil-xtender-link':
subtab_appareils_value = 'subtab-xtender'
elif button_id == 'landpage-appareil-bsp-link':
subtab_appareils_value = 'subtab-bsp'
elif button_id == 'landpage-btn-fonctions':
tab_value = 'tab-fonctions'
elif button_id in ['landpage-btn-data',
'landpage-data-export-link',
'landpage-data-manage-link',
'landpage-data-overview-link']:
tab_value = 'tab-data'
if button_id == 'landpage-export-link':
subtab_data_value = 'subtab-exportDB'
elif button_id == 'landpage-data-manage-link':
subtab_data_value = 'subtab-updateDB'
elif button_id == 'landpage-data-overview-link':
subtab_data_value = 'subtab-showDB'
# Retourner les valeurs des onglets et sous-onglets
return tab_value, subtab_data_value
# Exécuter l'application
if __name__ == '__main__':
#app.run_server(debug=True,host='0.0.0.0', port=7860)
# for deploy
app.run(debug=True, host='0.0.0.0', port=7860)