RathodHarish commited on
Commit
21fb82f
·
verified ·
1 Parent(s): 62db3ed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -55
app.py CHANGED
@@ -10,69 +10,79 @@ df = pd.DataFrame()
10
 
11
  def upload_csv(file):
12
  global df
 
13
  try:
14
  if file is None:
15
- return ["All"], ["All"], ["All"], "No file uploaded. Please upload a CSV file.", "All", "All", "All", None, None, None, None
16
 
17
  # Read the CSV file
 
18
  df = pd.read_csv(file)
19
 
20
  if df.empty:
21
- return ["All"], ["All"], ["All"], "The uploaded CSV file is empty.", "All", "All", "All", None, None, None, None
22
 
23
  # Debug: Show the CSV content and column names
24
- csv_info = f"CSV Columns: {', '.join(df.columns)}\nRaw CSV Content:\n{df.to_string()}"
25
 
26
  # Define required columns
27
  required_columns = {'DeviceID', 'Lab', 'Type', 'Timestamp', 'Status', 'UsageCount'}
28
  if not required_columns.issubset(df.columns):
29
  missing_cols = required_columns - set(df.columns)
30
- return ["All"], ["All"], ["All"], f"{csv_info}\n\nError: CSV is missing required columns: {', '.join(missing_cols)}", "All", "All", "All", None, None, None, None
31
 
32
  # Debug: Check data types and sample values
33
- debug_msg = f"{csv_info}\n\nData Types:\n{df.dtypes}\n\nSample Values:\n{df.head().to_string()}"
34
 
35
  # Check for empty or all-NaN columns
 
 
 
 
36
  if df['Lab'].dropna().empty or df['Type'].dropna().empty:
37
- return ["All"], ["All"], ["All"], f"{debug_msg}\n\nError: Lab or Type columns are empty or contain only NaN values.", "All", "All", "All", None, None, None, None
38
 
39
  # Convert Timestamp to datetime with error handling
 
40
  try:
41
  df['Timestamp'] = pd.to_datetime(df['Timestamp'], errors='coerce')
42
- debug_msg += f"\n\nTimestamps after conversion:\n{df['Timestamp'].head().to_string()}"
43
  if df['Timestamp'].isna().all():
44
- return ["All"], ["All"], ["All"], f"{debug_msg}\n\nError: All Timestamp values are invalid or unparseable.", "All", "All", "All", None, None, None, None
45
  except Exception as e:
46
- return ["All"], ["All"], ["All"], f"{debug_msg}\n\nError: Failed to parse Timestamp column: {str(e)}", "All", "All", "All", None, None, None, None
47
 
48
  # Extract unique values for dropdowns
 
49
  labs = ['All'] + sorted([str(lab) for lab in df['Lab'].fillna('Unknown').unique()])
50
  types = ['All'] + sorted([str(type_) for type_ in df['Type'].fillna('Unknown').unique()])
 
51
 
52
  # Extract date range for filter
53
  min_date = df['Timestamp'].min()
54
  max_date = df['Timestamp'].max()
55
  if pd.isna(min_date) or pd.isna(max_date):
56
  date_ranges = ['All']
57
- debug_msg += "\n\nWarning: Could not determine date range due to invalid timestamps."
58
  else:
59
  min_date = min_date.strftime('%Y-%m-%d')
60
  max_date = max_date.strftime('%Y-%m-%d')
61
  date_ranges = ['All', f"{min_date} to {max_date}"]
62
- debug_msg += f"\n\nDate Range: {min_date} to {max_date}"
63
 
64
  # Automatically trigger filter_and_visualize after upload with default filters
 
65
  try:
66
  result = filter_and_visualize("All", "All", "All")
67
  device_cards, plot_daily, plot_uptime, anomaly_text, filter_msg = result
68
- debug_msg += f"\n\nInitial Filter Result: {filter_msg}"
69
  except Exception as e:
70
- debug_msg += f"\n\nInitial Filter Error: {str(e)}"
71
  device_cards, plot_daily, plot_uptime, anomaly_text = None, None, None, None
72
 
73
  return labs, types, date_ranges, debug_msg, "All", "All", "All", device_cards, plot_daily, plot_uptime, anomaly_text
74
  except Exception as e:
75
- return ["All"], ["All"], ["All"], f"Failed to load CSV: {str(e)}", "All", "All", "All", None, None, None, None
76
 
77
  def filter_and_visualize(selected_lab, selected_type, selected_date_range):
78
  global df
@@ -80,84 +90,123 @@ def filter_and_visualize(selected_lab, selected_type, selected_date_range):
80
  return None, None, None, None, "No data available."
81
 
82
  # Debug: Log the filter parameters
83
- error_msg = f"Applying filters: Lab={selected_lab}, Type={selected_type}, Date Range={selected_date_range}"
84
 
85
  # Filter the DataFrame
86
  filtered_df = df.copy()
 
 
87
  if selected_lab != "All":
88
  filtered_df = filtered_df[filtered_df["Lab"] == selected_lab]
89
- error_msg += f"\nAfter Lab filter ({selected_lab}): {len(filtered_df)} rows"
90
  if selected_type != "All":
91
  filtered_df = filtered_df[filtered_df["Type"] == selected_type]
92
- error_msg += f"\nAfter Type filter ({selected_type}): {len(filtered_df)} rows"
93
  if selected_date_range != "All" and selected_date_range != "No data available.":
94
  try:
95
  start_date, end_date = selected_date_range.split(" to ")
96
  start_date = pd.to_datetime(start_date)
97
  end_date = pd.to_datetime(end_date) + timedelta(days=1) # Include end date
98
  filtered_df = filtered_df[(filtered_df["Timestamp"] >= start_date) & (filtered_df["Timestamp"] < end_date)]
99
- error_msg += f"\nAfter Date Range filter ({start_date} to {end_date}): {len(filtered_df)} rows"
100
  except Exception as e:
101
- error_msg += f"\nError parsing date range: {str(e)}"
102
  return None, None, None, None, error_msg
103
 
104
  if filtered_df.empty:
105
- return None, None, None, None, f"{error_msg}\nNo data matches the selected filters."
106
 
107
  # Debug: Log the filtered DataFrame
108
- error_msg += f"\nFiltered DataFrame:\n{filtered_df.to_string()}"
109
 
110
  # Device Cards (as a table)
111
  device_cards = filtered_df[['DeviceID', 'Lab', 'Type', 'UsageCount', 'Timestamp']].sort_values(by='Timestamp', ascending=False)
112
 
113
  # Daily Log Trends (Line Chart)
114
- daily_logs = filtered_df.groupby(filtered_df['Timestamp'].dt.date).size()
115
- plt.figure(figsize=(8, 4))
116
- daily_logs.plot(kind='line', marker='o', color='blue')
117
- plt.title("Daily Log Trends")
118
- plt.xlabel("Date")
119
- plt.ylabel("Number of Logs")
120
- plt.xticks(rotation=45)
121
- buf1 = io.BytesIO()
122
- plt.savefig(buf1, format="png", bbox_inches="tight")
123
- plt.close()
124
- buf1.seek(0)
125
-
126
- # Weekly Uptime % (Bar Chart)
127
- end_date = filtered_df['Timestamp'].max()
128
- start_date = end_date - timedelta(days=7)
129
- weekly_df = filtered_df[(filtered_df['Timestamp'] >= start_date) & (filtered_df['Timestamp'] <= end_date)]
130
- if weekly_df.empty:
131
- error_msg += "\nWarning: No data for Weekly Uptime % (date range too narrow)."
132
- buf2 = io.BytesIO()
 
 
 
 
 
 
133
  plt.figure(figsize=(8, 4))
134
- plt.title("Weekly Uptime % - No Data")
135
  plt.xlabel("Date")
136
- plt.ylabel("Uptime %")
137
- plt.savefig(buf2, format="png", bbox_inches="tight")
 
138
  plt.close()
139
- buf2.seek(0)
140
- else:
141
- uptime = weekly_df.groupby(weekly_df['Timestamp'].dt.date)['Status'].apply(lambda x: (x == 'Up').mean() * 100)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  plt.figure(figsize=(8, 4))
143
- uptime.plot(kind='bar', color='green')
144
- plt.title("Weekly Uptime %")
145
  plt.xlabel("Date")
146
  plt.ylabel("Uptime %")
147
- plt.xticks(rotation=45)
148
  buf2 = io.BytesIO()
149
  plt.savefig(buf2, format="png", bbox_inches="tight")
150
  plt.close()
151
  buf2.seek(0)
152
 
153
  # Anomaly Alerts (Text)
154
- anomalies = filtered_df[(filtered_df['UsageCount'] > 80) | (filtered_df['Status'] == 'Down')]
155
- if anomalies.empty:
156
- anomaly_text = "No anomalies detected."
157
- else:
158
- anomaly_text = "Anomalies Detected:\n" + anomalies[['DeviceID', 'Lab', 'Type', 'Status', 'UsageCount']].to_string(index=False)
 
 
 
 
159
 
160
- return device_cards, buf1, buf2, anomaly_text, f"{error_msg}\nFilters applied successfully."
161
 
162
  def download_pdf(selected_lab, selected_type, selected_date_range):
163
  global df
 
10
 
11
  def upload_csv(file):
12
  global df
13
+ debug_msg = "Starting CSV upload process...\n"
14
  try:
15
  if file is None:
16
+ return ["All"], ["All"], ["All"], f"{debug_msg}No file uploaded. Please upload a CSV file.", "All", "All", "All", None, None, None, None
17
 
18
  # Read the CSV file
19
+ debug_msg += "Reading CSV file...\n"
20
  df = pd.read_csv(file)
21
 
22
  if df.empty:
23
+ return ["All"], ["All"], ["All"], f"{debug_msg}The uploaded CSV file is empty.", "All", "All", "All", None, None, None, None
24
 
25
  # Debug: Show the CSV content and column names
26
+ debug_msg += f"CSV Columns: {', '.join(df.columns)}\nRaw CSV Content:\n{df.to_string()}\n\n"
27
 
28
  # Define required columns
29
  required_columns = {'DeviceID', 'Lab', 'Type', 'Timestamp', 'Status', 'UsageCount'}
30
  if not required_columns.issubset(df.columns):
31
  missing_cols = required_columns - set(df.columns)
32
+ return ["All"], ["All"], ["All"], f"{debug_msg}Error: CSV is missing required columns: {', '.join(missing_cols)}", "All", "All", "All", None, None, None, None
33
 
34
  # Debug: Check data types and sample values
35
+ debug_msg += f"Data Types:\n{df.dtypes}\n\nSample Values:\n{df.head().to_string()}\n\n"
36
 
37
  # Check for empty or all-NaN columns
38
+ if df['Lab'].dropna().empty:
39
+ debug_msg += "Error: Lab column is empty or contains only NaN values.\n"
40
+ if df['Type'].dropna().empty:
41
+ debug_msg += "Error: Type column is empty or contains only NaN values.\n"
42
  if df['Lab'].dropna().empty or df['Type'].dropna().empty:
43
+ return ["All"], ["All"], ["All"], debug_msg, "All", "All", "All", None, None, None, None
44
 
45
  # Convert Timestamp to datetime with error handling
46
+ debug_msg += "Converting Timestamp column...\n"
47
  try:
48
  df['Timestamp'] = pd.to_datetime(df['Timestamp'], errors='coerce')
49
+ debug_msg += f"Timestamps after conversion:\n{df['Timestamp'].to_string()}\n\n"
50
  if df['Timestamp'].isna().all():
51
+ return ["All"], ["All"], ["All"], f"{debug_msg}Error: All Timestamp values are invalid or unparseable.", "All", "All", "All", None, None, None, None
52
  except Exception as e:
53
+ return ["All"], ["All"], ["All"], f"{debug_msg}Error: Failed to parse Timestamp column: {str(e)}", "All", "All", "All", None, None, None, None
54
 
55
  # Extract unique values for dropdowns
56
+ debug_msg += "Extracting unique values for dropdowns...\n"
57
  labs = ['All'] + sorted([str(lab) for lab in df['Lab'].fillna('Unknown').unique()])
58
  types = ['All'] + sorted([str(type_) for type_ in df['Type'].fillna('Unknown').unique()])
59
+ debug_msg += f"Lab options: {labs}\nType options: {types}\n\n"
60
 
61
  # Extract date range for filter
62
  min_date = df['Timestamp'].min()
63
  max_date = df['Timestamp'].max()
64
  if pd.isna(min_date) or pd.isna(max_date):
65
  date_ranges = ['All']
66
+ debug_msg += "Warning: Could not determine date range due to invalid timestamps.\n"
67
  else:
68
  min_date = min_date.strftime('%Y-%m-%d')
69
  max_date = max_date.strftime('%Y-%m-%d')
70
  date_ranges = ['All', f"{min_date} to {max_date}"]
71
+ debug_msg += f"Date Range: {min_date} to {max_date}\n"
72
 
73
  # Automatically trigger filter_and_visualize after upload with default filters
74
+ debug_msg += "Triggering initial visualization with default filters...\n"
75
  try:
76
  result = filter_and_visualize("All", "All", "All")
77
  device_cards, plot_daily, plot_uptime, anomaly_text, filter_msg = result
78
+ debug_msg += f"Initial Filter Result: {filter_msg}\n"
79
  except Exception as e:
80
+ debug_msg += f"Initial Filter Error: {str(e)}\n"
81
  device_cards, plot_daily, plot_uptime, anomaly_text = None, None, None, None
82
 
83
  return labs, types, date_ranges, debug_msg, "All", "All", "All", device_cards, plot_daily, plot_uptime, anomaly_text
84
  except Exception as e:
85
+ return ["All"], ["All"], ["All"], f"{debug_msg}Failed to load CSV: {str(e)}", "All", "All", "All", None, None, None, None
86
 
87
  def filter_and_visualize(selected_lab, selected_type, selected_date_range):
88
  global df
 
90
  return None, None, None, None, "No data available."
91
 
92
  # Debug: Log the filter parameters
93
+ error_msg = f"Applying filters: Lab={selected_lab}, Type={selected_type}, Date Range={selected_date_range}\n"
94
 
95
  # Filter the DataFrame
96
  filtered_df = df.copy()
97
+ error_msg += f"Initial DataFrame: {len(filtered_df)} rows\n"
98
+
99
  if selected_lab != "All":
100
  filtered_df = filtered_df[filtered_df["Lab"] == selected_lab]
101
+ error_msg += f"After Lab filter ({selected_lab}): {len(filtered_df)} rows\n"
102
  if selected_type != "All":
103
  filtered_df = filtered_df[filtered_df["Type"] == selected_type]
104
+ error_msg += f"After Type filter ({selected_type}): {len(filtered_df)} rows\n"
105
  if selected_date_range != "All" and selected_date_range != "No data available.":
106
  try:
107
  start_date, end_date = selected_date_range.split(" to ")
108
  start_date = pd.to_datetime(start_date)
109
  end_date = pd.to_datetime(end_date) + timedelta(days=1) # Include end date
110
  filtered_df = filtered_df[(filtered_df["Timestamp"] >= start_date) & (filtered_df["Timestamp"] < end_date)]
111
+ error_msg += f"After Date Range filter ({start_date} to {end_date}): {len(filtered_df)} rows\n"
112
  except Exception as e:
113
+ error_msg += f"Error parsing date range: {str(e)}\n"
114
  return None, None, None, None, error_msg
115
 
116
  if filtered_df.empty:
117
+ return None, None, None, None, f"{error_msg}No data matches the selected filters."
118
 
119
  # Debug: Log the filtered DataFrame
120
+ error_msg += f"Filtered DataFrame:\n{filtered_df.to_string()}\n"
121
 
122
  # Device Cards (as a table)
123
  device_cards = filtered_df[['DeviceID', 'Lab', 'Type', 'UsageCount', 'Timestamp']].sort_values(by='Timestamp', ascending=False)
124
 
125
  # Daily Log Trends (Line Chart)
126
+ try:
127
+ daily_logs = filtered_df.groupby(filtered_df['Timestamp'].dt.date).size()
128
+ if daily_logs.empty:
129
+ error_msg += "Warning: No data for Daily Log Trends (invalid timestamps).\n"
130
+ plt.figure(figsize=(8, 4))
131
+ plt.title("Daily Log Trends - No Data")
132
+ plt.xlabel("Date")
133
+ plt.ylabel("Number of Logs")
134
+ buf1 = io.BytesIO()
135
+ plt.savefig(buf1, format="png", bbox_inches="tight")
136
+ plt.close()
137
+ buf1.seek(0)
138
+ else:
139
+ plt.figure(figsize=(8, 4))
140
+ daily_logs.plot(kind='line', marker='o', color='blue')
141
+ plt.title("Daily Log Trends")
142
+ plt.xlabel("Date")
143
+ plt.ylabel("Number of Logs")
144
+ plt.xticks(rotation=45)
145
+ buf1 = io.BytesIO()
146
+ plt.savefig(buf1, format="png", bbox_inches="tight")
147
+ plt.close()
148
+ buf1.seek(0)
149
+ except Exception as e:
150
+ error_msg += f"Error generating Daily Log Trends: {str(e)}\n"
151
  plt.figure(figsize=(8, 4))
152
+ plt.title("Daily Log Trends - Error")
153
  plt.xlabel("Date")
154
+ plt.ylabel("Number of Logs")
155
+ buf1 = io.BytesIO()
156
+ plt.savefig(buf1, format="png", bbox_inches="tight")
157
  plt.close()
158
+ buf1.seek(0)
159
+
160
+ # Weekly Uptime % (Bar Chart)
161
+ try:
162
+ end_date = filtered_df['Timestamp'].max()
163
+ start_date = end_date - timedelta(days=7)
164
+ weekly_df = filtered_df[(filtered_df['Timestamp'] >= start_date) & (filtered_df['Timestamp'] <= end_date)]
165
+ if weekly_df.empty:
166
+ error_msg += "Warning: No data for Weekly Uptime % (date range too narrow).\n"
167
+ plt.figure(figsize=(8, 4))
168
+ plt.title("Weekly Uptime % - No Data")
169
+ plt.xlabel("Date")
170
+ plt.ylabel("Uptime %")
171
+ buf2 = io.BytesIO()
172
+ plt.savefig(buf2, format="png", bbox_inches="tight")
173
+ plt.close()
174
+ buf2.seek(0)
175
+ else:
176
+ uptime = weekly_df.groupby(weekly_df['Timestamp'].dt.date)['Status'].apply(lambda x: (x == 'Up').mean() * 100)
177
+ plt.figure(figsize=(8, 4))
178
+ uptime.plot(kind='bar', color='green')
179
+ plt.title("Weekly Uptime %")
180
+ plt.xlabel("Date")
181
+ plt.ylabel("Uptime %")
182
+ plt.xticks(rotation=45)
183
+ buf2 = io.BytesIO()
184
+ plt.savefig(buf2, format="png", bbox_inches="tight")
185
+ plt.close()
186
+ buf2.seek(0)
187
+ except Exception as e:
188
+ error_msg += f"Error generating Weekly Uptime %: {str(e)}\n"
189
  plt.figure(figsize=(8, 4))
190
+ plt.title("Weekly Uptime % - Error")
 
191
  plt.xlabel("Date")
192
  plt.ylabel("Uptime %")
 
193
  buf2 = io.BytesIO()
194
  plt.savefig(buf2, format="png", bbox_inches="tight")
195
  plt.close()
196
  buf2.seek(0)
197
 
198
  # Anomaly Alerts (Text)
199
+ try:
200
+ anomalies = filtered_df[(filtered_df['UsageCount'] > 80) | (filtered_df['Status'] == 'Down')]
201
+ if anomalies.empty:
202
+ anomaly_text = "No anomalies detected."
203
+ else:
204
+ anomaly_text = "Anomalies Detected:\n" + anomalies[['DeviceID', 'Lab', 'Type', 'Status', 'UsageCount']].to_string(index=False)
205
+ except Exception as e:
206
+ error_msg += f"Error generating Anomaly Alerts: {str(e)}\n"
207
+ anomaly_text = "Error generating anomaly alerts."
208
 
209
+ return device_cards, buf1, buf2, anomaly_text, f"{error_msg}Filters applied successfully."
210
 
211
  def download_pdf(selected_lab, selected_type, selected_date_range):
212
  global df