phitoduck commited on
Commit
02f17d0
·
1 Parent(s): 64bdbaf
Files changed (2) hide show
  1. streamlit_app.py +50 -18
  2. utils.py +1 -1
streamlit_app.py CHANGED
@@ -1,10 +1,9 @@
1
  import streamlit as st
2
  import pandas as pd
3
- import matplotlib.pyplot as plt
4
- from datetime import datetime, time, date
5
- from typing import List, Dict, Any, Tuple
6
  from utils import generate_random_data, evaluate_alarm_state, aggregate_data
7
  from textwrap import dedent
 
8
 
9
  # Constants
10
  HARD_CODED_DATE = date(2024, 7, 26)
@@ -21,29 +20,42 @@ def main():
21
 
22
  if not st.session_state.df.empty:
23
  display_dataframe("Raw Event Data", st.session_state.df)
24
- plot_time_series(st.session_state.df, "ResponseTime(ms)")
25
 
26
  # Section 2 - Calculate Aggregations
27
  st.header("Section 2 - Calculate Aggregations")
28
  aggregation_form()
29
 
30
  if not st.session_state.aggregated_df.empty:
31
- display_dataframe("Aggregated Summary Data", st.session_state.aggregated_df)
32
- plot_time_series(st.session_state.aggregated_df, st.session_state.aggregation_function_input)
 
 
 
 
 
 
33
 
34
  # Section 3 - Summary Data Aggregated by Period
35
  st.header("Section 3 - Summary Data Aggregated by Period")
36
  summary_by_period_form()
37
 
38
  if not st.session_state.summary_by_period_df.empty:
39
- display_dataframe("Summary Data Aggregated by Period", st.session_state.summary_by_period_df)
40
- plot_time_series(st.session_state.summary_by_period_df, st.session_state.aggregation_function_input)
 
 
 
 
 
 
41
 
42
  # Section 4 - Evaluate Alarm State
43
  st.header("Section 4 - Evaluate Alarm State")
44
  alarm_state_form()
45
 
46
  if not st.session_state.alarm_state_df.empty:
 
47
  display_alarm_state_evaluation(st.session_state.alarm_state_df)
48
 
49
  display_key_tables()
@@ -79,12 +91,6 @@ def generate_data_form() -> None:
79
 
80
  def aggregation_form() -> None:
81
  freq_input = st.selectbox("Period (bin)", ['1min', '5min', '15min'], key='freq_input', help="Select the frequency for aggregating the data.")
82
- aggregation_function_input = st.selectbox(
83
- "Aggregation Function",
84
- ['p50', 'p95', 'p99', 'max', 'min', 'average'],
85
- key='aggregation_function_input',
86
- help="Select the aggregation function for visualizing the data."
87
- )
88
  if not st.session_state.df.empty:
89
  st.session_state.aggregated_df = aggregate_data(st.session_state.df, freq_input)
90
 
@@ -109,7 +115,7 @@ def alarm_state_form() -> None:
109
  threshold=threshold_input,
110
  datapoints_to_alarm=datapoints_to_alarm_input,
111
  evaluation_range=evaluation_range_input,
112
- aggregation_function=st.session_state.aggregation_function_input,
113
  alarm_condition=alarm_condition_input
114
  )
115
 
@@ -117,9 +123,9 @@ def display_dataframe(title: str, df: pd.DataFrame) -> None:
117
  st.write(title)
118
  st.dataframe(df)
119
 
120
- def plot_time_series(df: pd.DataFrame, column: str) -> None:
121
  timestamps = df['Timestamp']
122
- response_times = df[column]
123
 
124
  segments = []
125
  current_segment = {'timestamps': [], 'values': []}
@@ -140,12 +146,38 @@ def plot_time_series(df: pd.DataFrame, column: str) -> None:
140
 
141
  color = 'tab:blue'
142
  ax1.set_xlabel('Timestamp')
143
- ax1.set_ylabel(f'{column} (ms)', color=color)
144
 
145
  for segment in segments:
146
  ax1.plot(segment['timestamps'], segment['values'], color=color, linewidth=0.5)
147
  ax1.scatter(segment['timestamps'], segment['values'], color=color, s=10)
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  fig.tight_layout()
150
  st.pyplot(fig)
151
 
 
1
  import streamlit as st
2
  import pandas as pd
3
+ from datetime import time, date
 
 
4
  from utils import generate_random_data, evaluate_alarm_state, aggregate_data
5
  from textwrap import dedent
6
+ from matplotlib import pyplot as plt
7
 
8
  # Constants
9
  HARD_CODED_DATE = date(2024, 7, 26)
 
20
 
21
  if not st.session_state.df.empty:
22
  display_dataframe("Raw Event Data", st.session_state.df)
23
+ st.scatter_chart(st.session_state.df.set_index("Timestamp"))
24
 
25
  # Section 2 - Calculate Aggregations
26
  st.header("Section 2 - Calculate Aggregations")
27
  aggregation_form()
28
 
29
  if not st.session_state.aggregated_df.empty:
30
+ display_dataframe("Aggregated Summary Data (Storage)", st.session_state.aggregated_df)
31
+ aggregation_function_input__storage = st.selectbox(
32
+ "Aggregation Function (Storage)",
33
+ ['p50', 'p95', 'p99', 'max', 'min', 'average'],
34
+ key='aggregation_function_input__storage',
35
+ help="Select the aggregation function for visualizing the data."
36
+ )
37
+ st.line_chart(st.session_state.aggregated_df.set_index("Timestamp")[st.session_state.aggregation_function_input__storage])
38
 
39
  # Section 3 - Summary Data Aggregated by Period
40
  st.header("Section 3 - Summary Data Aggregated by Period")
41
  summary_by_period_form()
42
 
43
  if not st.session_state.summary_by_period_df.empty:
44
+ display_dataframe("Summary Data Aggregated by Period (for Alarm)", st.session_state.summary_by_period_df)
45
+ aggregation_function_input__alarm = st.selectbox(
46
+ "Aggregation Function (Alarm)",
47
+ ['p50', 'p95', 'p99', 'max', 'min', 'average'],
48
+ key='aggregation_function_input__alarm',
49
+ help="Select the aggregation function for visualizing the data."
50
+ )
51
+ st.line_chart(st.session_state.summary_by_period_df.set_index("Timestamp")[st.session_state.aggregation_function_input__alarm])
52
 
53
  # Section 4 - Evaluate Alarm State
54
  st.header("Section 4 - Evaluate Alarm State")
55
  alarm_state_form()
56
 
57
  if not st.session_state.alarm_state_df.empty:
58
+ plot_time_series(st.session_state.summary_by_period_df, st.session_state.threshold_input, st.session_state.alarm_condition_input, st.session_state.evaluation_range_input)
59
  display_alarm_state_evaluation(st.session_state.alarm_state_df)
60
 
61
  display_key_tables()
 
91
 
92
  def aggregation_form() -> None:
93
  freq_input = st.selectbox("Period (bin)", ['1min', '5min', '15min'], key='freq_input', help="Select the frequency for aggregating the data.")
 
 
 
 
 
 
94
  if not st.session_state.df.empty:
95
  st.session_state.aggregated_df = aggregate_data(st.session_state.df, freq_input)
96
 
 
115
  threshold=threshold_input,
116
  datapoints_to_alarm=datapoints_to_alarm_input,
117
  evaluation_range=evaluation_range_input,
118
+ aggregation_function=st.session_state.aggregation_function_input__alarm,
119
  alarm_condition=alarm_condition_input
120
  )
121
 
 
123
  st.write(title)
124
  st.dataframe(df)
125
 
126
+ def plot_time_series(df: pd.DataFrame, threshold: int, alarm_condition: str, evaluation_range: int) -> None:
127
  timestamps = df['Timestamp']
128
+ response_times = df[st.session_state.aggregation_function_input__alarm]
129
 
130
  segments = []
131
  current_segment = {'timestamps': [], 'values': []}
 
146
 
147
  color = 'tab:blue'
148
  ax1.set_xlabel('Timestamp')
149
+ ax1.set_ylabel('Response Time (ms)', color=color)
150
 
151
  for segment in segments:
152
  ax1.plot(segment['timestamps'], segment['values'], color=color, linewidth=0.5)
153
  ax1.scatter(segment['timestamps'], segment['values'], color=color, s=10)
154
 
155
+ line_style = '--' if alarm_condition in ['<', '>'] else '-'
156
+ ax1.axhline(y=threshold, color='r', linestyle=line_style, linewidth=0.8, label='Threshold')
157
+ ax1.tick_params(axis='y', labelcolor=color)
158
+
159
+ if alarm_condition in ['<=', '<']:
160
+ ax1.fill_between(timestamps, 0, threshold, color='pink', alpha=0.3)
161
+ else:
162
+ ax1.fill_between(timestamps, threshold, response_times.max(), color='pink', alpha=0.3)
163
+
164
+ period_indices = range(len(df))
165
+ ax2 = ax1.twiny()
166
+ ax2.set_xticks(period_indices)
167
+ ax2.set_xticklabels(period_indices, fontsize=8)
168
+ ax2.set_xlabel('Time Periods', fontsize=8)
169
+ ax2.xaxis.set_tick_params(width=0.5)
170
+
171
+ for idx in period_indices:
172
+ if idx % evaluation_range == 0:
173
+ ax1.axvline(x=df['Timestamp'].iloc[idx], color='green', linestyle='-', alpha=0.3)
174
+ max_value = max(filter(lambda x: x is not None, df[st.session_state.aggregation_function_input__alarm]))
175
+ ax1.text(df['Timestamp'].iloc[idx], max_value * 0.95, f"[{idx // evaluation_range}]", rotation=90, verticalalignment='bottom', color='grey', alpha=0.7, fontsize=8)
176
+ else:
177
+ ax1.axvline(x=df['Timestamp'].iloc[idx], color='grey', linestyle='--', alpha=0.3)
178
+
179
+ ax1.annotate('Alarm threshold', xy=(0.98, threshold), xycoords=('axes fraction', 'data'), ha='right', va='bottom', fontsize=8, color='red', backgroundcolor='none')
180
+
181
  fig.tight_layout()
182
  st.pyplot(fig)
183
 
utils.py CHANGED
@@ -112,7 +112,7 @@ def evaluate_alarm_state(
112
  num_dp_that_must_be_filled: int = 0
113
 
114
  for dp in chunk:
115
- if dp is None:
116
  dp_symbol = '⚫️'
117
  elif check_condition(dp, threshold, alarm_condition):
118
  dp_symbol = '🔴'
 
112
  num_dp_that_must_be_filled: int = 0
113
 
114
  for dp in chunk:
115
+ if str(dp).lower() == "nan":
116
  dp_symbol = '⚫️'
117
  elif check_condition(dp, threshold, alarm_condition):
118
  dp_symbol = '🔴'