Issue with dash graph

Hello every one
i have an issue with my code.My graph doesn’t reinitialize when I choose a new value in my drop-down.
I give you my code if someone can help me

tyimport dash
from dash import dcc, html
from dash.dependencies import Output, Input, State
import plotly.graph_objs as go
import requests
from datetime import datetime

app = dash.Dash(__name__)

# Fonction pour récupérer les réunions et courses disponibles pour la journée
def get_available_meetings_and_races():
    response = requests.get('https://online.turfinfo.api.pmu.fr/rest/client/61/programme/04032024?meteo=true&specialisation=INTERNET')
    data = response.json()
    reunions = data.get('programme', {}).get('reunions', [])
    return reunions

# Fonction pour construire les options de sélection de réunion et de course
def build_meeting_and_race_options(meetings):
    meeting_options = [{'label': f"Réunion {meeting['numOfficiel']} - {meeting['hippodrome']['libelleLong']}", 'value': meeting['numOfficiel']} for meeting in meetings]
    return meeting_options

app.layout = html.Div([
    dcc.Dropdown(id='meeting-dropdown', placeholder='Sélectionnez une réunion',style={'width': '60%'}),
    dcc.Dropdown(id='race-dropdown', placeholder='Sélectionnez une course',style={'width': '60%'}),
    dcc.Graph(id='live-graph',figure={}),
    html.Div(id='signal-counters'),
    dcc.Interval(
        id='interval-component',
        interval=1*30*1000,  # in milliseconds
        n_intervals=0
    ),
    html.Button('Actualiser les options', id='refresh-button', n_clicks=0)  # Bouton pour actualiser les options de réunion et de course
])

historical_data = []

@app.callback(
    [Output('meeting-dropdown', 'options')],
    [Input('refresh-button', 'n_clicks')]
)
def update_options(n_clicks):
    reunions = get_available_meetings_and_races()
    meeting_options = build_meeting_and_race_options(reunions)
    return [meeting_options]

@app.callback(
    [Output('race-dropdown', 'options')],
    [Input('meeting-dropdown', 'value')]
)
def update_race_options(selected_meeting):
    reunions = get_available_meetings_and_races()
    selected_reunion = next((reunion for reunion in reunions if reunion['numOfficiel'] == selected_meeting), None)
    if selected_reunion:
        race_options = [{'label': f"Course {course['numExterne']} - {course['libelle']}", 'value': course['numExterne']} for course in selected_reunion.get('courses', [])]
        return [race_options]
    else:
        return [[]]

@app.callback(
    [Output('live-graph', 'figure'), Output('signal-counters', 'children')],
    [Input('interval-component', 'n_intervals')],
    [State('meeting-dropdown', 'value'), State('race-dropdown', 'value')]
)
def update_graph(n, selected_meeting, selected_race):
    global historical_data

    # Construction de l'URL de l'API en fonction de la réunion et du numéro de course sélectionnés
    api_url = f"https://online.turfinfo.api.pmu.fr/rest/client/61/programme/{datetime.now().strftime('%d%m%Y')}/R{selected_meeting}/C{selected_race}/combinaisons?specialisation=INTERNET"

    response = requests.get(api_url)
    data = response.json()

    combinaisons = data.get('combinaisons', [])
    # Reste du code reste inchangé...
    total_enjeux = 0  # Initialiser total_enjeux à zéro
    signal_counters = {}  # Dictionnaire pour stocker les compteurs de signal pour chaque cheval

    for combinaison in combinaisons:
        if combinaison.get('pariType') == 'E_SIMPLE_PLACE':
            total_enjeux = combinaison.get('totalEnjeu')
            break

    x_data = []
    y_data = []

    for combinaison in combinaisons:
        if combinaison.get('pariType') == 'E_SIMPLE_PLACE':
            liste_combinaisons = combinaison.get('listeCombinaisons', [])
            for cheval_data in liste_combinaisons:
                num_cheval = cheval_data.get('combinaison')[0]
                enjeu = cheval_data.get('totalEnjeu')
                current_time = datetime.now()  # Obtenir l'heure actuelle

                # Normaliser l'enjeu par rapport au total des enjeux
                enjeu_normalise = enjeu / total_enjeux

                # Ajouter les nouvelles données à la liste des données historiques pour chaque cheval
                historical_data.append(
                    {'timestamp': current_time, 'numCheval': num_cheval, 'enjeu_normalise': enjeu_normalise})

    # Trier les données historiques par timestamp
    historical_data.sort(key=lambda x: x['timestamp'])

    for entry in historical_data:
        x_data.append(entry['timestamp'])
        y_data.append(entry['enjeu_normalise'])

    traces = []

    for num_cheval in set([entry['numCheval'] for entry in historical_data]):
        cheval_data = [(entry['timestamp'], entry['enjeu_normalise']) for entry in historical_data if entry['numCheval'] == num_cheval]
        cheval_data.sort(key=lambda x: x[0])
        x_cheval_data = [entry[0] for entry in cheval_data]
        y_cheval_data = [entry[1] for entry in cheval_data]

        signal_counter = 0  # Initialiser le compteur de signal pour chaque cheval à zéro

        # Vérifier la différence entre deux points successifs
        for i in range(1, len(y_cheval_data)):
            if y_cheval_data[i] - y_cheval_data[i-1] > 0.005:
                signal_counter += 1
                trace = go.Scatter(
                    x=[x_cheval_data[i]],
                    y=[y_cheval_data[i]],
                    mode='markers',
                    marker=dict(color='red', size=10),
                    name=f'Signal: Différence > 0.01',
                    showlegend=False
                )
                traces.append(trace)

        trace = go.Scatter(
            x=x_cheval_data,
            y=y_cheval_data,
            mode='lines+markers',
            name=f'Cheval {num_cheval}'
        )
        traces.append(trace)

        last_enjeu_normalise = round(y_cheval_data[-1], 3)  # Récupérer la valeur du dernier enjeu normalisé pour chaque cheval
        signal_counters[f'Cheval {num_cheval}'] = {'signal_counter': signal_counter, 'last_enjeu_normalise': last_enjeu_normalise}  # Stocker le compteur de signal et la valeur du dernier enjeu normalisé pour chaque cheval

    layout = go.Layout(
        title='Évolution de l\'enjeu normalisé pour chaque cheval',
        xaxis=dict(title='Temps'),
        yaxis=dict(title='Enjeu normalisé (par rapport au total des enjeux)'),
        legend={'itemsizing': 'constant'}
    )

    figure = {'data': traces, 'layout': layout}

    # Créer des éléments de div pour afficher les compteurs de signal pour chaque cheval
    signal_counter_divs = []
    for cheval, counters in sorted(signal_counters.items(), key=lambda x: x[1]['last_enjeu_normalise'], reverse=True):
        signal_counter = counters['signal_counter']
        last_enjeu_normalise = counters['last_enjeu_normalise']
        if signal_counter != 0:
            # Mettre en rouge les valeurs du compteur qui sont différentes de zéro
            signal_counter_divs.append(html.Div([html.Span(f'Cheval {cheval}: {signal_counter}, Last Enjeu Normalisé:{last_enjeu_normalise}', style={'color': 'red'})]))
        else:
            signal_counter_divs.append(html.Div([html.Span(f'Cheval {cheval}: {signal_counter}, Last Enjeu Normalisé:{last_enjeu_normalise}')]))

    return figure, signal_counter_divs  # Retourner les compteurs de signal dans la div signal-counters

if __name__ == '__main__':
    app.run_server(port= 8053,debug=True)pe or paste code here

Hi @manemifr, welcome to the community.

Right now you are triggering the figure update with the interval component only- so every 30 seconds. If you want it to be updated once the drop-down value changed, change the State() to Input() in this callback:

@app.callback(
    [Output('live-graph', 'figure'), Output('signal-counters', 'children')],
    [Input('interval-component', 'n_intervals')],
    [State('meeting-dropdown', 'value'), State('race-dropdown', 'value')]
)
def update_graph(n, selected_meeting, selected_race):
    global historical_data

Not necessarily related, but have a read here concerning global variables:

Thanks AIMPED for your reply.i am going to test your solution.

1 Like

I tested your solutions have always the same issue.the graph doesn’t reinitialize when I change race or meeting.
I you have another solution.
thanks