gauravlochab commited on
Commit
aae782c
·
1 Parent(s): b7d068b

fix: add moving avg and top 5 agents to toggle

Browse files
Files changed (1) hide show
  1. app.py +214 -64
app.py CHANGED
@@ -534,7 +534,7 @@ def write_debug_info(df, fig):
534
  return False
535
 
536
  def create_combined_time_series_graph(df):
537
- """Create a combined time series graph for all agents using Plotly"""
538
  if len(df) == 0:
539
  logger.error("No data to plot combined graph")
540
  fig = go.Figure()
@@ -593,10 +593,6 @@ def create_combined_time_series_graph(df):
593
  # Create Plotly figure in a clean state
594
  fig = go.Figure()
595
 
596
- # Get unique agents
597
- unique_agents = df['agent_id'].unique()
598
- colors = px.colors.qualitative.Plotly[:len(unique_agents)]
599
-
600
  # Update y-axis range to include negative values
601
  min_apr = min(df['apr'].min() * 1.1, -10) # Add 10% padding, minimum of -10
602
  max_apr = max(df['apr'].max() * 1.1, 10) # Add 10% padding, minimum of 10
@@ -633,61 +629,141 @@ def create_combined_time_series_graph(df):
633
  x0=min_time, x1=max_time
634
  )
635
 
636
- # MODIFIED: Changed order of trace addition - only need APR values now
637
- # Add data for each agent
638
- for i, agent_id in enumerate(unique_agents):
639
- agent_data = df[df['agent_id'] == agent_id].copy()
640
- agent_name = agent_data['agent_name'].iloc[0]
641
- color = colors[i % len(colors)]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
642
 
643
- # Sort the data by timestamp
644
- agent_data = agent_data.sort_values('timestamp')
 
 
 
645
 
646
- # Log actual points being plotted for this agent
647
- logger.info(f"Plotting agent: {agent_name} (ID: {agent_id}) with {len(agent_data)} points")
648
- for idx, row in agent_data.iterrows():
649
- logger.info(f" Point {idx}: timestamp={row['timestamp']}, apr={row['apr']}, type={row['metric_type']}")
 
 
 
 
 
 
 
 
 
 
 
 
650
 
651
- # Get the APR data - this is what we'll plot
652
- apr_data = agent_data[agent_data['metric_type'] == 'APR']
653
 
654
- # SIMPLIFIED APPROACH: Use a single trace with lines+markers mode
655
- # This is much more reliable across different platforms
656
- if not apr_data.empty:
657
- logger.info(f" Adding combined line+markers for {agent_name}")
 
 
 
 
 
 
 
 
658
 
659
  # Explicitly convert to Python lists
660
- x_values = apr_data['timestamp'].tolist()
661
- y_values = apr_data['apr'].tolist()
662
 
663
- # Log what we're about to plot
664
- for i, (x, y) in enumerate(zip(x_values, y_values)):
665
- logger.info(f" Point {i+1}: x={x}, y={y}")
666
 
667
- # Use a single trace for both markers and lines
668
  fig.add_trace(
669
  go.Scatter(
670
  x=x_values,
671
  y=y_values,
672
- mode='lines+markers', # Important: use both lines and markers
673
  marker=dict(
674
- color='blue',
675
  symbol='circle',
676
- size=12,
677
- line=dict(width=2, color='black')
678
  ),
679
- line=dict(color='blue', width=2),
680
- name=agent_name,
681
- legendgroup=agent_name,
682
- showlegend=True,
683
- hovertemplate='Time: %{x}<br>APR: %{y:.2f}<br>Agent: ' + agent_name + '<extra></extra>'
684
  )
685
  )
686
- logger.info(f" Added combined line+markers trace for {agent_name}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
687
 
688
  # Update layout - use simple boolean values everywhere
689
  fig.update_layout(
690
- title="APR Values for All Agents",
691
  xaxis_title="Time",
692
  yaxis_title="Value",
693
  template="plotly_white",
@@ -705,6 +781,17 @@ def create_combined_time_series_graph(df):
705
  hovermode="closest"
706
  )
707
 
 
 
 
 
 
 
 
 
 
 
 
708
  # FORCE FIXED Y-AXIS RANGE
709
  fig.update_yaxes(
710
  showgrid=True,
@@ -760,30 +847,87 @@ def create_combined_time_series_graph(df):
760
  x0=min_time, x1=max_time
761
  )
762
 
763
- # Simply plot each agent's data as a line with markers
764
- for i, agent_id in enumerate(unique_agents):
765
- agent_data = df[df['agent_id'] == agent_id].copy()
766
- agent_name = agent_data['agent_name'].iloc[0]
767
- color = colors[i % len(colors)]
768
-
769
  # Sort by timestamp
770
- agent_data = agent_data.sort_values('timestamp')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
771
 
772
- # Add a single trace with markers+lines
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
773
  simple_fig.add_trace(
774
  go.Scatter(
775
- x=agent_data['timestamp'],
776
- y=agent_data['apr'],
777
- mode='lines+markers',
778
- name=agent_name,
779
- marker=dict(size=10),
780
- line=dict(width=2)
781
  )
782
  )
783
 
784
  # Simplified layout
785
  simple_fig.update_layout(
786
- title="APR Values for All Agents",
787
  xaxis_title="Time",
788
  yaxis_title="Value",
789
  yaxis=dict(range=[min_apr, max_apr]),
@@ -791,6 +935,17 @@ def create_combined_time_series_graph(df):
791
  width=1000
792
  )
793
 
 
 
 
 
 
 
 
 
 
 
 
794
  # Return the simple figure
795
  return simple_fig
796
 
@@ -1235,15 +1390,7 @@ def dashboard():
1235
  )
1236
  return error_fig
1237
 
1238
- # Set up the button click event with error handling
1239
- try:
1240
- # Use Gradio's button click properly
1241
- refresh_btn.click(fn=update_apr_graph, outputs=combined_graph)
1242
- except Exception as e:
1243
- logger.error(f"Error setting up button handler: {e}")
1244
-
1245
- # Initialize the graph on load
1246
- # We'll use placeholder figure initially
1247
  placeholder_fig = go.Figure()
1248
  placeholder_fig.add_annotation(
1249
  text="Click 'Refresh APR Data' to load APR graph",
@@ -1252,6 +1399,9 @@ def dashboard():
1252
  font=dict(size=15)
1253
  )
1254
  combined_graph.value = placeholder_fig
 
 
 
1255
 
1256
  return demo
1257
 
 
534
  return False
535
 
536
  def create_combined_time_series_graph(df):
537
+ """Create a time series graph showing average APR values across all agents"""
538
  if len(df) == 0:
539
  logger.error("No data to plot combined graph")
540
  fig = go.Figure()
 
593
  # Create Plotly figure in a clean state
594
  fig = go.Figure()
595
 
 
 
 
 
596
  # Update y-axis range to include negative values
597
  min_apr = min(df['apr'].min() * 1.1, -10) # Add 10% padding, minimum of -10
598
  max_apr = max(df['apr'].max() * 1.1, 10) # Add 10% padding, minimum of 10
 
629
  x0=min_time, x1=max_time
630
  )
631
 
632
+ # MODIFIED: Calculate average APR values across all agents for each timestamp
633
+ # Filter for APR data only
634
+ apr_data = df[df['metric_type'] == 'APR'].copy()
635
+
636
+ # Group by timestamp and calculate mean APR
637
+ avg_apr_data = apr_data.groupby('timestamp')['apr'].mean().reset_index()
638
+
639
+ # Sort by timestamp
640
+ avg_apr_data = avg_apr_data.sort_values('timestamp')
641
+
642
+ # Log the average APR data
643
+ logger.info(f"Calculated average APR data with {len(avg_apr_data)} points")
644
+ for idx, row in avg_apr_data.iterrows():
645
+ logger.info(f" Average point {idx}: timestamp={row['timestamp']}, avg_apr={row['apr']}")
646
+
647
+ # Calculate moving average based on a time window (2 hours)
648
+ # Sort data by timestamp
649
+ apr_data_sorted = apr_data.sort_values('timestamp')
650
+
651
+ # Create a new dataframe for the moving average
652
+ avg_apr_data_with_ma = avg_apr_data.copy()
653
+ avg_apr_data_with_ma['moving_avg'] = None # Initialize the moving average column
654
+
655
+ # Define the time window for the moving average (2 hours)
656
+ time_window = pd.Timedelta(hours=2)
657
+ logger.info(f"Calculating moving average with time window of {time_window}")
658
+
659
+ # Calculate the moving average for each timestamp
660
+ for i, row in avg_apr_data_with_ma.iterrows():
661
+ current_time = row['timestamp']
662
+ window_start = current_time - time_window
663
 
664
+ # Get all data points within the time window
665
+ window_data = apr_data_sorted[
666
+ (apr_data_sorted['timestamp'] >= window_start) &
667
+ (apr_data_sorted['timestamp'] <= current_time)
668
+ ]
669
 
670
+ # Calculate the average APR for the time window
671
+ if not window_data.empty:
672
+ avg_apr_data_with_ma.at[i, 'moving_avg'] = window_data['apr'].mean()
673
+ logger.debug(f"Time window {window_start} to {current_time}: {len(window_data)} points, avg={window_data['apr'].mean()}")
674
+ else:
675
+ # If no data points in the window, use the current value
676
+ avg_apr_data_with_ma.at[i, 'moving_avg'] = row['apr']
677
+ logger.debug(f"No data points in time window for {current_time}, using current value {row['apr']}")
678
+
679
+ logger.info(f"Calculated time-based moving average with {len(avg_apr_data_with_ma)} points")
680
+
681
+ # Plot individual agent data points with agent names in hover, but limit display for scalability
682
+ if not apr_data.empty:
683
+ # Group by agent to use different colors for each agent
684
+ unique_agents = apr_data['agent_name'].unique()
685
+ colors = px.colors.qualitative.Plotly[:len(unique_agents)]
686
 
687
+ # Create a color map for agents
688
+ color_map = {agent: colors[i % len(colors)] for i, agent in enumerate(unique_agents)}
689
 
690
+ # Calculate the total number of data points per agent to determine which are most active
691
+ agent_counts = apr_data['agent_name'].value_counts()
692
+
693
+ # Determine how many agents to show individually (limit to top 5 most active)
694
+ MAX_VISIBLE_AGENTS = 5
695
+ top_agents = agent_counts.nlargest(min(MAX_VISIBLE_AGENTS, len(agent_counts))).index.tolist()
696
+
697
+ logger.info(f"Showing {len(top_agents)} agents by default out of {len(unique_agents)} total agents")
698
+
699
+ # Add data points for each agent, but only make top agents visible by default
700
+ for agent_name in unique_agents:
701
+ agent_data = apr_data[apr_data['agent_name'] == agent_name]
702
 
703
  # Explicitly convert to Python lists
704
+ x_values = agent_data['timestamp'].tolist()
705
+ y_values = agent_data['apr'].tolist()
706
 
707
+ # Determine if this agent should be visible by default
708
+ is_visible = agent_name in top_agents
 
709
 
710
+ # Add data points as markers
711
  fig.add_trace(
712
  go.Scatter(
713
  x=x_values,
714
  y=y_values,
715
+ mode='markers', # Only markers for original data
716
  marker=dict(
717
+ color=color_map[agent_name],
718
  symbol='circle',
719
+ size=10,
720
+ line=dict(width=1, color='black')
721
  ),
722
+ name=f'Agent: {agent_name}',
723
+ hovertemplate='Time: %{x}<br>APR: %{y:.2f}<br>Agent: ' + agent_name + '<extra></extra>',
724
+ visible=is_visible # Only top agents visible by default
 
 
725
  )
726
  )
727
+ logger.info(f"Added data points for agent {agent_name} with {len(x_values)} points (visible: {is_visible})")
728
+
729
+ # Add moving average as a smooth line
730
+ x_values_ma = avg_apr_data_with_ma['timestamp'].tolist()
731
+ y_values_ma = avg_apr_data_with_ma['moving_avg'].tolist()
732
+
733
+ # Create a more detailed hover template for the moving average line
734
+ # that includes information about all agents at each timestamp and the time window
735
+ hover_data = []
736
+ for idx, row in avg_apr_data_with_ma.iterrows():
737
+ timestamp = row['timestamp']
738
+ window_start = timestamp - time_window
739
+
740
+ # Find all agents with data in the time window
741
+ agents_in_window = apr_data[
742
+ (apr_data['timestamp'] >= window_start) &
743
+ (apr_data['timestamp'] <= timestamp)
744
+ ]
745
+
746
+ # Simplified hover text without detailed data points
747
+ hover_data.append(
748
+ f"Time: {timestamp}<br>Moving Avg APR (2h window): {row['moving_avg']:.2f}"
749
+ )
750
+
751
+ fig.add_trace(
752
+ go.Scatter(
753
+ x=x_values_ma,
754
+ y=y_values_ma,
755
+ mode='lines', # Only lines for moving average
756
+ line=dict(color='red', width=3),
757
+ name='Moving Average APR (2h window)',
758
+ hovertext=hover_data,
759
+ hoverinfo='text'
760
+ )
761
+ )
762
+ logger.info(f"Added time-based moving average APR trace with {len(x_values_ma)} points")
763
 
764
  # Update layout - use simple boolean values everywhere
765
  fig.update_layout(
766
+ title="Average APR Values Across All Agents",
767
  xaxis_title="Time",
768
  yaxis_title="Value",
769
  template="plotly_white",
 
781
  hovermode="closest"
782
  )
783
 
784
+ # Add a note about hidden agents if there are more than MAX_VISIBLE_AGENTS
785
+ if len(unique_agents) > MAX_VISIBLE_AGENTS:
786
+ fig.add_annotation(
787
+ text=f"Note: Only showing top {MAX_VISIBLE_AGENTS} agents by default. Toggle others in legend.",
788
+ xref="paper", yref="paper",
789
+ x=0.5, y=1.05,
790
+ showarrow=False,
791
+ font=dict(size=12, color="gray"),
792
+ align="center"
793
+ )
794
+
795
  # FORCE FIXED Y-AXIS RANGE
796
  fig.update_yaxes(
797
  showgrid=True,
 
847
  x0=min_time, x1=max_time
848
  )
849
 
850
+ # Define colors for the fallback graph
851
+ fallback_colors = px.colors.qualitative.Plotly
852
+
853
+ # Simply plot the average APR data with moving average
854
+ if not avg_apr_data.empty:
 
855
  # Sort by timestamp
856
+ avg_apr_data = avg_apr_data.sort_values('timestamp')
857
+
858
+ # Calculate time-based moving average for the fallback graph
859
+ avg_apr_data_with_ma = avg_apr_data.copy()
860
+ avg_apr_data_with_ma['moving_avg'] = None
861
+
862
+ # Define the time window (2 hours)
863
+ time_window = pd.Timedelta(hours=2)
864
+
865
+ # Calculate the moving average for each timestamp
866
+ for i, row in avg_apr_data_with_ma.iterrows():
867
+ current_time = row['timestamp']
868
+ window_start = current_time - time_window
869
+
870
+ # Get all data points within the time window
871
+ window_data = apr_data[
872
+ (apr_data['timestamp'] >= window_start) &
873
+ (apr_data['timestamp'] <= current_time)
874
+ ]
875
+
876
+ # Calculate the average APR for the time window
877
+ if not window_data.empty:
878
+ avg_apr_data_with_ma.at[i, 'moving_avg'] = window_data['apr'].mean()
879
+ else:
880
+ # If no data points in the window, use the current value
881
+ avg_apr_data_with_ma.at[i, 'moving_avg'] = row['apr']
882
+
883
+ # Add data points for each agent, but only make top agents visible by default
884
+ unique_agents = apr_data['agent_name'].unique()
885
+ colors = px.colors.qualitative.Plotly[:len(unique_agents)]
886
+ color_map = {agent: colors[i % len(colors)] for i, agent in enumerate(unique_agents)}
887
 
888
+ # Calculate the total number of data points per agent
889
+ agent_counts = apr_data['agent_name'].value_counts()
890
+
891
+ # Determine how many agents to show individually (limit to top 5 most active)
892
+ MAX_VISIBLE_AGENTS = 5
893
+ top_agents = agent_counts.nlargest(min(MAX_VISIBLE_AGENTS, len(agent_counts))).index.tolist()
894
+
895
+ for agent_name in unique_agents:
896
+ agent_data = apr_data[apr_data['agent_name'] == agent_name]
897
+
898
+ # Determine if this agent should be visible by default
899
+ is_visible = agent_name in top_agents
900
+
901
+ # Add data points as markers
902
+ simple_fig.add_trace(
903
+ go.Scatter(
904
+ x=agent_data['timestamp'],
905
+ y=agent_data['apr'],
906
+ mode='markers',
907
+ name=f'Agent: {agent_name}',
908
+ marker=dict(
909
+ size=10,
910
+ color=color_map[agent_name]
911
+ ),
912
+ hovertemplate='Time: %{x}<br>APR: %{y:.2f}<br>Agent: ' + agent_name + '<extra></extra>',
913
+ visible=is_visible # Only top agents visible by default
914
+ )
915
+ )
916
+
917
+ # Add moving average as a line
918
  simple_fig.add_trace(
919
  go.Scatter(
920
+ x=avg_apr_data_with_ma['timestamp'],
921
+ y=avg_apr_data_with_ma['moving_avg'],
922
+ mode='lines',
923
+ name='Moving Average APR (2h window)',
924
+ line=dict(width=3, color='red')
 
925
  )
926
  )
927
 
928
  # Simplified layout
929
  simple_fig.update_layout(
930
+ title="Average APR Values Across All Agents",
931
  xaxis_title="Time",
932
  yaxis_title="Value",
933
  yaxis=dict(range=[min_apr, max_apr]),
 
935
  width=1000
936
  )
937
 
938
+ # Add a note about hidden agents if there are more than MAX_VISIBLE_AGENTS
939
+ if len(unique_agents) > MAX_VISIBLE_AGENTS:
940
+ simple_fig.add_annotation(
941
+ text=f"Note: Only showing top {MAX_VISIBLE_AGENTS} agents by default. Toggle others in legend.",
942
+ xref="paper", yref="paper",
943
+ x=0.5, y=1.05,
944
+ showarrow=False,
945
+ font=dict(size=12, color="gray"),
946
+ align="center"
947
+ )
948
+
949
  # Return the simple figure
950
  return simple_fig
951
 
 
1390
  )
1391
  return error_fig
1392
 
1393
+ # Initialize the graph on load with a placeholder
 
 
 
 
 
 
 
 
1394
  placeholder_fig = go.Figure()
1395
  placeholder_fig.add_annotation(
1396
  text="Click 'Refresh APR Data' to load APR graph",
 
1399
  font=dict(size=15)
1400
  )
1401
  combined_graph.value = placeholder_fig
1402
+
1403
+ # Set up the button click event
1404
+ refresh_btn.click(fn=update_apr_graph, outputs=[combined_graph])
1405
 
1406
  return demo
1407