reab5555 commited on
Commit
11e16fe
·
verified ·
1 Parent(s): c2daf8a

Update visualization.py

Browse files
Files changed (1) hide show
  1. visualization.py +187 -176
visualization.py CHANGED
@@ -1,177 +1,188 @@
1
- import matplotlib.pyplot as plt
2
- import seaborn as sns
3
- import numpy as np
4
- import pandas as pd
5
- from matplotlib.patches import Rectangle
6
- from utils import seconds_to_timecode
7
- from anomaly_detection import determine_anomalies
8
-
9
- def plot_mse(df, mse_values, title, color='navy', time_threshold=3, anomaly_threshold=4):
10
- plt.figure(figsize=(16, 8), dpi=400)
11
- fig, ax = plt.subplots(figsize=(16, 8))
12
-
13
- if 'Seconds' not in df.columns:
14
- df['Seconds'] = df['Timecode'].apply(
15
- lambda x: sum(float(t) * 60 ** i for i, t in enumerate(reversed(x.split(':')))))
16
-
17
- # Ensure df and mse_values have the same length and remove NaN values
18
- min_length = min(len(df), len(mse_values))
19
- df = df.iloc[:min_length]
20
- mse_values = mse_values[:min_length]
21
-
22
- # Remove NaN values
23
- mask = ~np.isnan(mse_values)
24
- df = df[mask]
25
- mse_values = mse_values[mask]
26
-
27
- mean = pd.Series(mse_values).rolling(window=10).mean()
28
- std = pd.Series(mse_values).rolling(window=10).std()
29
- median = np.median(mse_values)
30
-
31
- ax.scatter(df['Seconds'], mse_values, color=color, alpha=0.3, s=5)
32
- ax.plot(df['Seconds'], mean, color=color, linewidth=0.5)
33
- ax.fill_between(df['Seconds'], mean - std, mean + std, color=color, alpha=0.1)
34
-
35
- # Add median line
36
- ax.axhline(y=median, color='black', linestyle='--', label='Median Baseline')
37
-
38
- # Add threshold line
39
- threshold = np.mean(mse_values) + anomaly_threshold * np.std(mse_values)
40
- ax.axhline(y=threshold, color='red', linestyle='--', label=f'Threshold: {anomaly_threshold:.1f}')
41
- ax.text(ax.get_xlim()[1], threshold, f'Threshold: {anomaly_threshold:.1f}', verticalalignment='center', horizontalalignment='left', color='red')
42
-
43
- anomalies = determine_anomalies(mse_values, anomaly_threshold)
44
- anomaly_frames = df['Frame'].iloc[anomalies].tolist()
45
-
46
- ax.scatter(df['Seconds'].iloc[anomalies], mse_values[anomalies], color='red', s=20, zorder=5)
47
-
48
- anomaly_data = list(zip(df['Timecode'].iloc[anomalies],
49
- df['Seconds'].iloc[anomalies],
50
- mse_values[anomalies]))
51
- anomaly_data.sort(key=lambda x: x[1])
52
-
53
- grouped_anomalies = []
54
- current_group = []
55
- for timecode, sec, mse in anomaly_data:
56
- if not current_group or sec - current_group[-1][1] <= time_threshold:
57
- current_group.append((timecode, sec, mse))
58
- else:
59
- grouped_anomalies.append(current_group)
60
- current_group = [(timecode, sec, mse)]
61
- if current_group:
62
- grouped_anomalies.append(current_group)
63
-
64
- for group in grouped_anomalies:
65
- start_sec = group[0][1]
66
- end_sec = group[-1][1]
67
- rect = Rectangle((start_sec, ax.get_ylim()[0]), end_sec - start_sec, ax.get_ylim()[1] - ax.get_ylim()[0],
68
- facecolor='red', alpha=0.2, zorder=1)
69
- ax.add_patch(rect)
70
-
71
- for group in grouped_anomalies:
72
- highest_mse_anomaly = max(group, key=lambda x: x[2])
73
- timecode, sec, mse = highest_mse_anomaly
74
- ax.annotate(timecode, (sec, mse), textcoords="offset points", xytext=(0, 10),
75
- ha='center', fontsize=6, color='red')
76
-
77
- max_seconds = df['Seconds'].max()
78
- num_ticks = 100
79
- tick_locations = np.linspace(0, max_seconds, num_ticks)
80
- tick_labels = [seconds_to_timecode(int(s)) for s in tick_locations]
81
-
82
- ax.set_xticks(tick_locations)
83
- ax.set_xticklabels(tick_labels, rotation=90, ha='center', fontsize=6)
84
-
85
- ax.set_xlabel('Timecode')
86
- ax.set_ylabel('Mean Squared Error')
87
- ax.set_title(title)
88
-
89
- ax.grid(True, linestyle='--', alpha=0.7)
90
- ax.legend()
91
- plt.tight_layout()
92
- plt.close()
93
- return fig, anomaly_frames
94
-
95
- def plot_mse_histogram(mse_values, title, anomaly_threshold, color='blue'):
96
- plt.figure(figsize=(16, 3), dpi=400)
97
- fig, ax = plt.subplots(figsize=(16, 3))
98
-
99
- ax.hist(mse_values, bins=100, edgecolor='black', color=color, alpha=0.7)
100
- ax.set_xlabel('Mean Squared Error')
101
- ax.set_ylabel('Number of Samples')
102
- ax.set_title(title)
103
-
104
- mean = np.mean(mse_values)
105
- std = np.std(mse_values)
106
- threshold = mean + anomaly_threshold * std
107
-
108
- ax.axvline(x=threshold, color='red', linestyle='--', linewidth=2)
109
-
110
- plt.tight_layout()
111
- plt.close()
112
- return fig
113
-
114
- def plot_mse_heatmap(mse_values, title, df):
115
- plt.figure(figsize=(20, 3), dpi=400)
116
- fig, ax = plt.subplots(figsize=(20, 3))
117
-
118
- # Reshape MSE values to 2D array for heatmap
119
- mse_2d = mse_values.reshape(1, -1)
120
-
121
- # Create heatmap
122
- sns.heatmap(mse_2d, cmap='YlOrRd', cbar=False, ax=ax)
123
-
124
- # Set x-axis ticks to timecodes
125
- num_ticks = 60
126
- tick_locations = np.linspace(0, len(mse_values) - 1, num_ticks).astype(int)
127
- tick_labels = [df['Timecode'].iloc[i] for i in tick_locations]
128
-
129
- ax.set_xticks(tick_locations)
130
- ax.set_xticklabels(tick_labels, rotation=90, ha='center', va='top')
131
-
132
- ax.set_title(title)
133
-
134
- # Remove y-axis labels
135
- ax.set_yticks([])
136
-
137
- plt.tight_layout()
138
- plt.close()
139
- return fig
140
-
141
- def plot_posture(df, posture_scores, color='blue', anomaly_threshold=3):
142
- plt.figure(figsize=(16, 8), dpi=400)
143
- fig, ax = plt.subplots(figsize=(16, 8))
144
-
145
- df['Seconds'] = df['Timecode'].apply(
146
- lambda x: sum(float(t) * 60 ** i for i, t in enumerate(reversed(x.split(':')))))
147
-
148
- posture_data = [(frame, score) for frame, score in posture_scores.items() if score is not None]
149
- posture_frames, posture_scores = zip(*posture_data)
150
-
151
- # Create a new dataframe for posture data
152
- posture_df = pd.DataFrame({'Frame': posture_frames, 'Score': posture_scores})
153
-
154
-
155
- posture_df = posture_df.merge(df[['Frame', 'Seconds']], on='Frame', how='inner')
156
-
157
- ax.scatter(posture_df['Seconds'], posture_df['Score'], color=color, alpha=0.3, s=5)
158
- mean = posture_df['Score'].rolling(window=10).mean()
159
- ax.plot(posture_df['Seconds'], mean, color=color, linewidth=0.5)
160
-
161
- ax.set_xlabel('Timecode')
162
- ax.set_ylabel('Posture Score')
163
- ax.set_title("Body Posture Over Time")
164
-
165
- ax.grid(True, linestyle='--', alpha=0.7)
166
-
167
- max_seconds = df['Seconds'].max()
168
- num_ticks = 80
169
- tick_locations = np.linspace(0, max_seconds, num_ticks)
170
- tick_labels = [seconds_to_timecode(int(s)) for s in tick_locations]
171
-
172
- ax.set_xticks(tick_locations)
173
- ax.set_xticklabels(tick_labels, rotation=90, ha='center', fontsize=6)
174
-
175
- plt.tight_layout()
176
- plt.close()
 
 
 
 
 
 
 
 
 
 
 
177
  return fig
 
1
+ import matplotlib.pyplot as plt
2
+ import seaborn as sns
3
+ import numpy as np
4
+ import pandas as pd
5
+ from matplotlib.patches import Rectangle
6
+ from utils import seconds_to_timecode
7
+ from anomaly_detection import determine_anomalies
8
+
9
+ def plot_mse(df, mse_values, title, color='navy', time_threshold=3, anomaly_threshold=4):
10
+ plt.figure(figsize=(16, 8), dpi=400)
11
+ fig, ax = plt.subplots(figsize=(16, 8))
12
+
13
+ if 'Seconds' not in df.columns:
14
+ df['Seconds'] = df['Timecode'].apply(
15
+ lambda x: sum(float(t) * 60 ** i for i, t in enumerate(reversed(x.split(':')))))
16
+
17
+ # Ensure df and mse_values have the same length and remove NaN values
18
+ min_length = min(len(df), len(mse_values))
19
+ df = df.iloc[:min_length]
20
+ mse_values = mse_values[:min_length]
21
+
22
+ # Remove NaN values
23
+ mask = ~np.isnan(mse_values)
24
+ df = df[mask]
25
+ mse_values = mse_values[mask]
26
+
27
+ # Calculate rolling mean and std
28
+ mean = pd.Series(mse_values).rolling(window=10, min_periods=1).mean()
29
+ std = pd.Series(mse_values).rolling(window=10, min_periods=1).std()
30
+
31
+ # Plot scatter points
32
+ ax.scatter(df['Seconds'], mse_values, color=color, alpha=0.3, s=5)
33
+
34
+ # Plot mean line and std fill only for continuous valid segments
35
+ valid_mask = ~np.isnan(mse_values)
36
+ segments = np.split(np.arange(len(df)), np.where(~valid_mask)[0])
37
+ for segment in segments:
38
+ if len(segment) > 0 and valid_mask[segment[0]]:
39
+ ax.plot(df['Seconds'].iloc[segment], mean.iloc[segment], color=color, linewidth=0.5)
40
+ ax.fill_between(df['Seconds'].iloc[segment],
41
+ mean.iloc[segment] - std.iloc[segment],
42
+ mean.iloc[segment] + std.iloc[segment],
43
+ color=color, alpha=0.1)
44
+
45
+ # Add median line
46
+ median = np.median(mse_values)
47
+ ax.axhline(y=median, color='black', linestyle='--', label='Median Baseline')
48
+
49
+ # Add threshold line
50
+ threshold = np.mean(mse_values) + anomaly_threshold * np.std(mse_values)
51
+ ax.axhline(y=threshold, color='red', linestyle='--', label=f'Threshold: {anomaly_threshold:.1f}')
52
+ ax.text(ax.get_xlim()[1], threshold, f'Threshold: {anomaly_threshold:.1f}', verticalalignment='center', horizontalalignment='left', color='red')
53
+
54
+ anomalies = determine_anomalies(mse_values, anomaly_threshold)
55
+ anomaly_frames = df['Frame'].iloc[anomalies].tolist()
56
+
57
+ ax.scatter(df['Seconds'].iloc[anomalies], mse_values[anomalies], color='red', s=20, zorder=5)
58
+
59
+ anomaly_data = list(zip(df['Timecode'].iloc[anomalies],
60
+ df['Seconds'].iloc[anomalies],
61
+ mse_values[anomalies]))
62
+ anomaly_data.sort(key=lambda x: x[1])
63
+
64
+ grouped_anomalies = []
65
+ current_group = []
66
+ for timecode, sec, mse in anomaly_data:
67
+ if not current_group or sec - current_group[-1][1] <= time_threshold:
68
+ current_group.append((timecode, sec, mse))
69
+ else:
70
+ grouped_anomalies.append(current_group)
71
+ current_group = [(timecode, sec, mse)]
72
+ if current_group:
73
+ grouped_anomalies.append(current_group)
74
+
75
+ for group in grouped_anomalies:
76
+ start_sec = group[0][1]
77
+ end_sec = group[-1][1]
78
+ rect = Rectangle((start_sec, ax.get_ylim()[0]), end_sec - start_sec, ax.get_ylim()[1] - ax.get_ylim()[0],
79
+ facecolor='red', alpha=0.2, zorder=1)
80
+ ax.add_patch(rect)
81
+
82
+ for group in grouped_anomalies:
83
+ highest_mse_anomaly = max(group, key=lambda x: x[2])
84
+ timecode, sec, mse = highest_mse_anomaly
85
+ ax.annotate(timecode, (sec, mse), textcoords="offset points", xytext=(0, 10),
86
+ ha='center', fontsize=6, color='red')
87
+
88
+ max_seconds = df['Seconds'].max()
89
+ num_ticks = 100
90
+ tick_locations = np.linspace(0, max_seconds, num_ticks)
91
+ tick_labels = [seconds_to_timecode(int(s)) for s in tick_locations]
92
+
93
+ ax.set_xticks(tick_locations)
94
+ ax.set_xticklabels(tick_labels, rotation=90, ha='center', fontsize=6)
95
+
96
+ ax.set_xlabel('Timecode')
97
+ ax.set_ylabel('Mean Squared Error')
98
+ ax.set_title(title)
99
+
100
+ ax.grid(True, linestyle='--', alpha=0.7)
101
+ ax.legend()
102
+ plt.tight_layout()
103
+ plt.close()
104
+ return fig, anomaly_frames
105
+
106
+ def plot_mse_histogram(mse_values, title, anomaly_threshold, color='blue'):
107
+ plt.figure(figsize=(16, 3), dpi=400)
108
+ fig, ax = plt.subplots(figsize=(16, 3))
109
+
110
+ ax.hist(mse_values, bins=100, edgecolor='black', color=color, alpha=0.7)
111
+ ax.set_xlabel('Mean Squared Error')
112
+ ax.set_ylabel('Number of Samples')
113
+ ax.set_title(title)
114
+
115
+ mean = np.mean(mse_values)
116
+ std = np.std(mse_values)
117
+ threshold = mean + anomaly_threshold * std
118
+
119
+ ax.axvline(x=threshold, color='red', linestyle='--', linewidth=2)
120
+
121
+ plt.tight_layout()
122
+ plt.close()
123
+ return fig
124
+
125
+ def plot_mse_heatmap(mse_values, title, df):
126
+ plt.figure(figsize=(20, 3), dpi=400)
127
+ fig, ax = plt.subplots(figsize=(20, 3))
128
+
129
+ # Reshape MSE values to 2D array for heatmap
130
+ mse_2d = mse_values.reshape(1, -1)
131
+
132
+ # Create heatmap
133
+ sns.heatmap(mse_2d, cmap='YlOrRd', cbar=False, ax=ax)
134
+
135
+ # Set x-axis ticks to timecodes
136
+ num_ticks = 60
137
+ tick_locations = np.linspace(0, len(mse_values) - 1, num_ticks).astype(int)
138
+ tick_labels = [df['Timecode'].iloc[i] for i in tick_locations]
139
+
140
+ ax.set_xticks(tick_locations)
141
+ ax.set_xticklabels(tick_labels, rotation=90, ha='center', va='top')
142
+
143
+ ax.set_title(title)
144
+
145
+ # Remove y-axis labels
146
+ ax.set_yticks([])
147
+
148
+ plt.tight_layout()
149
+ plt.close()
150
+ return fig
151
+
152
+ def plot_posture(df, posture_scores, color='blue', anomaly_threshold=3):
153
+ plt.figure(figsize=(16, 8), dpi=400)
154
+ fig, ax = plt.subplots(figsize=(16, 8))
155
+
156
+ df['Seconds'] = df['Timecode'].apply(
157
+ lambda x: sum(float(t) * 60 ** i for i, t in enumerate(reversed(x.split(':')))))
158
+
159
+ posture_data = [(frame, score) for frame, score in posture_scores.items() if score is not None]
160
+ posture_frames, posture_scores = zip(*posture_data)
161
+
162
+ # Create a new dataframe for posture data
163
+ posture_df = pd.DataFrame({'Frame': posture_frames, 'Score': posture_scores})
164
+
165
+
166
+ posture_df = posture_df.merge(df[['Frame', 'Seconds']], on='Frame', how='inner')
167
+
168
+ ax.scatter(posture_df['Seconds'], posture_df['Score'], color=color, alpha=0.3, s=5)
169
+ mean = posture_df['Score'].rolling(window=10).mean()
170
+ ax.plot(posture_df['Seconds'], mean, color=color, linewidth=0.5)
171
+
172
+ ax.set_xlabel('Timecode')
173
+ ax.set_ylabel('Posture Score')
174
+ ax.set_title("Body Posture Over Time")
175
+
176
+ ax.grid(True, linestyle='--', alpha=0.7)
177
+
178
+ max_seconds = df['Seconds'].max()
179
+ num_ticks = 80
180
+ tick_locations = np.linspace(0, max_seconds, num_ticks)
181
+ tick_labels = [seconds_to_timecode(int(s)) for s in tick_locations]
182
+
183
+ ax.set_xticks(tick_locations)
184
+ ax.set_xticklabels(tick_labels, rotation=90, ha='center', fontsize=6)
185
+
186
+ plt.tight_layout()
187
+ plt.close()
188
  return fig