Spaces:
Running
Running
gauravlochab
commited on
Commit
·
aae782c
1
Parent(s):
b7d068b
fix: add moving avg and top 5 agents to toggle
Browse files
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
|
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:
|
637 |
-
#
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
642 |
|
643 |
-
#
|
644 |
-
|
|
|
|
|
|
|
645 |
|
646 |
-
#
|
647 |
-
|
648 |
-
|
649 |
-
logger.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
650 |
|
651 |
-
#
|
652 |
-
|
653 |
|
654 |
-
#
|
655 |
-
|
656 |
-
|
657 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
658 |
|
659 |
# Explicitly convert to Python lists
|
660 |
-
x_values =
|
661 |
-
y_values =
|
662 |
|
663 |
-
#
|
664 |
-
|
665 |
-
logger.info(f" Point {i+1}: x={x}, y={y}")
|
666 |
|
667 |
-
#
|
668 |
fig.add_trace(
|
669 |
go.Scatter(
|
670 |
x=x_values,
|
671 |
y=y_values,
|
672 |
-
mode='
|
673 |
marker=dict(
|
674 |
-
color=
|
675 |
symbol='circle',
|
676 |
-
size=
|
677 |
-
line=dict(width=
|
678 |
),
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
showlegend=True,
|
683 |
-
hovertemplate='Time: %{x}<br>APR: %{y:.2f}<br>Agent: ' + agent_name + '<extra></extra>'
|
684 |
)
|
685 |
)
|
686 |
-
logger.info(f"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
687 |
|
688 |
# Update layout - use simple boolean values everywhere
|
689 |
fig.update_layout(
|
690 |
-
title="APR Values
|
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 |
-
#
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
# Sort by timestamp
|
770 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
771 |
|
772 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
773 |
simple_fig.add_trace(
|
774 |
go.Scatter(
|
775 |
-
x=
|
776 |
-
y=
|
777 |
-
mode='lines
|
778 |
-
name=
|
779 |
-
|
780 |
-
line=dict(width=2)
|
781 |
)
|
782 |
)
|
783 |
|
784 |
# Simplified layout
|
785 |
simple_fig.update_layout(
|
786 |
-
title="APR Values
|
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 |
-
#
|
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 |
|