Spaces:
Sleeping
Sleeping
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 |
|