Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -29,17 +29,21 @@ def upload_csv(file):
|
|
| 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 |
# Check for empty or all-NaN columns
|
| 33 |
if df['Lab'].dropna().empty or df['Type'].dropna().empty:
|
| 34 |
-
return ["All"], ["All"], ["All"], f"{
|
| 35 |
|
| 36 |
# Convert Timestamp to datetime with error handling
|
| 37 |
try:
|
| 38 |
df['Timestamp'] = pd.to_datetime(df['Timestamp'], errors='coerce')
|
|
|
|
| 39 |
if df['Timestamp'].isna().all():
|
| 40 |
-
return ["All"], ["All"], ["All"], f"{
|
| 41 |
except Exception as e:
|
| 42 |
-
return ["All"], ["All"], ["All"], f"{
|
| 43 |
|
| 44 |
# Extract unique values for dropdowns
|
| 45 |
labs = ['All'] + sorted([str(lab) for lab in df['Lab'].fillna('Unknown').unique()])
|
|
@@ -50,23 +54,23 @@ def upload_csv(file):
|
|
| 50 |
max_date = df['Timestamp'].max()
|
| 51 |
if pd.isna(min_date) or pd.isna(max_date):
|
| 52 |
date_ranges = ['All']
|
| 53 |
-
|
| 54 |
else:
|
| 55 |
min_date = min_date.strftime('%Y-%m-%d')
|
| 56 |
max_date = max_date.strftime('%Y-%m-%d')
|
| 57 |
date_ranges = ['All', f"{min_date} to {max_date}"]
|
| 58 |
-
|
| 59 |
|
| 60 |
# Automatically trigger filter_and_visualize after upload with default filters
|
| 61 |
try:
|
| 62 |
result = filter_and_visualize("All", "All", "All")
|
| 63 |
device_cards, plot_daily, plot_uptime, anomaly_text, filter_msg = result
|
| 64 |
-
|
| 65 |
except Exception as e:
|
| 66 |
-
|
| 67 |
device_cards, plot_daily, plot_uptime, anomaly_text = None, None, None, None
|
| 68 |
|
| 69 |
-
return labs, types, date_ranges,
|
| 70 |
except Exception as e:
|
| 71 |
return ["All"], ["All"], ["All"], f"Failed to load CSV: {str(e)}", "All", "All", "All", None, None, None, None
|
| 72 |
|
|
@@ -82,14 +86,17 @@ def filter_and_visualize(selected_lab, selected_type, selected_date_range):
|
|
| 82 |
filtered_df = df.copy()
|
| 83 |
if selected_lab != "All":
|
| 84 |
filtered_df = filtered_df[filtered_df["Lab"] == selected_lab]
|
|
|
|
| 85 |
if selected_type != "All":
|
| 86 |
filtered_df = filtered_df[filtered_df["Type"] == selected_type]
|
|
|
|
| 87 |
if selected_date_range != "All" and selected_date_range != "No data available.":
|
| 88 |
try:
|
| 89 |
start_date, end_date = selected_date_range.split(" to ")
|
| 90 |
start_date = pd.to_datetime(start_date)
|
| 91 |
end_date = pd.to_datetime(end_date) + timedelta(days=1) # Include end date
|
| 92 |
filtered_df = filtered_df[(filtered_df["Timestamp"] >= start_date) & (filtered_df["Timestamp"] < end_date)]
|
|
|
|
| 93 |
except Exception as e:
|
| 94 |
error_msg += f"\nError parsing date range: {str(e)}"
|
| 95 |
return None, None, None, None, error_msg
|
|
@@ -120,17 +127,28 @@ def filter_and_visualize(selected_lab, selected_type, selected_date_range):
|
|
| 120 |
end_date = filtered_df['Timestamp'].max()
|
| 121 |
start_date = end_date - timedelta(days=7)
|
| 122 |
weekly_df = filtered_df[(filtered_df['Timestamp'] >= start_date) & (filtered_df['Timestamp'] <= end_date)]
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
|
| 135 |
# Anomaly Alerts (Text)
|
| 136 |
anomalies = filtered_df[(filtered_df['UsageCount'] > 80) | (filtered_df['Status'] == 'Down')]
|
|
|
|
| 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()])
|
|
|
|
| 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 |
|
|
|
|
| 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
|
|
|
|
| 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')]
|