Skip to content

Commit bcb973e

Browse files
committed
Update statistics.py
1 parent b2fcf26 commit bcb973e

2 files changed

Lines changed: 33 additions & 134 deletions

File tree

backend/api/app.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55
import time
66
import os
77
import json
8-
from statistics import generate_statistics_images
8+
from statistics import (
9+
load_data_from_mongodb,
10+
create_language_chart,
11+
create_screen_resolution_chart,
12+
create_os_visualization,
13+
create_browser_visualization,
14+
create_media_devices_table
15+
)
916

1017
# Configuration
1118
STATS_DIR = "/var/www/stats"
@@ -21,7 +28,7 @@ def get_time_periods():
2128
}
2229

2330
def update_stats_file(app):
24-
"""Background task to update statistics JSON file"""
31+
"""Background task to update statistics JSON file and images"""
2532
while True:
2633
try:
2734
with app.app_context():
@@ -39,7 +46,16 @@ def update_stats_file(app):
3946
with open(JSON_FILE, 'w') as f:
4047
json.dump(stats_data, f)
4148

42-
generate_statistics_images(stats_data, IMAGE_PATTERN)
49+
# Load data from MongoDB
50+
df = load_data_from_mongodb(app)
51+
52+
if not df.empty:
53+
# Generate five visualization images
54+
create_language_chart(df, IMAGE_PATTERN, num=1)
55+
create_screen_resolution_chart(df, IMAGE_PATTERN, num=2)
56+
create_os_visualization(df, IMAGE_PATTERN, num=3)
57+
create_browser_visualization(df, IMAGE_PATTERN, num=4)
58+
create_media_devices_table(df, IMAGE_PATTERN, num=5)
4359

4460
except Exception as e:
4561
app.logger.error(f"Error updating stats: {str(e)}")

backend/api/statistics.py

Lines changed: 14 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -25,39 +25,27 @@ def get_geo_data(ip):
2525
def load_data_from_mongodb(app):
2626
"""Load data from MongoDB into pandas DataFrame"""
2727
try:
28-
# Get all records from the visits collection
2928
cursor = app.data_collection.find({})
3029
data = list(cursor)
31-
32-
# Convert to DataFrame
3330
df = pd.DataFrame(data)
34-
35-
# Update geo data for records with missing coordinates
3631
for index, row in df.iterrows():
3732
if not row.get('geo') or row.get('geoAccuracy') == '—' or row.get('geoAccuracy') == '':
3833
ip = row.get('ip')
3934
if ip:
4035
geo_data = get_geo_data(ip)
4136
if geo_data:
4237
df.at[index, 'geo'] = geo_data
43-
4438
return df
4539
except Exception as e:
4640
print(f"Error loading data from MongoDB: {str(e)}")
4741
return pd.DataFrame()
4842

49-
def create_map_visualization(df, output_pattern):
43+
def create_map_visualization(df, output_pattern, num):
5044
"""Create a map visualization of visitor locations"""
5145
try:
52-
# Create a map centered at a default location
5346
m = folium.Map(location=[0, 0], zoom_start=2)
54-
55-
# Add a marker cluster
5647
marker_cluster = MarkerCluster().add_to(m)
57-
58-
# Count occurrences of each location
5948
location_counts = {}
60-
6149
for _, row in df.iterrows():
6250
geo = row.get('geo')
6351
if geo and ',' in geo:
@@ -67,8 +55,6 @@ def create_map_visualization(df, output_pattern):
6755
location_counts[location_key] = location_counts.get(location_key, 0) + 1
6856
except ValueError:
6957
continue
70-
71-
# Add markers for each location
7258
for loc_key, count in location_counts.items():
7359
try:
7460
lat, lon = map(float, loc_key.split(','))
@@ -80,70 +66,54 @@ def create_map_visualization(df, output_pattern):
8066
).add_to(marker_cluster)
8167
except ValueError:
8268
continue
83-
84-
# Save the map
85-
map_file = output_pattern.format(3)
69+
map_file = output_pattern.format(num)
8670
m.save(map_file)
87-
8871
return True
8972
except Exception as e:
9073
print(f"Error creating map visualization: {str(e)}")
9174
return False
9275

93-
def create_language_chart(df, output_pattern):
76+
def create_language_chart(df, output_pattern, num):
9477
"""Create a bar chart of visitor languages"""
9578
try:
96-
# Get unique visitors by IP
9779
unique_df = df.drop_duplicates(subset=['ip'])
98-
99-
# Count languages
10080
language_counts = unique_df['language'].value_counts()
101-
10281
plt.figure(figsize=(12, 6))
10382
language_counts.plot(kind='bar')
10483
plt.title('Languages of Unique Visitors')
10584
plt.xlabel('Language')
10685
plt.ylabel('Count')
10786
plt.tight_layout()
108-
plt.savefig(output_pattern.format(4))
87+
plt.savefig(output_pattern.format(num))
10988
plt.close()
110-
11189
return True
11290
except Exception as e:
11391
print(f"Error creating language chart: {str(e)}")
11492
return False
11593

116-
def create_screen_resolution_chart(df, output_pattern):
94+
def create_screen_resolution_chart(df, output_pattern, num):
11795
"""Create a bar chart of screen resolutions"""
11896
try:
119-
# Get unique visitors by IP
12097
unique_df = df.drop_duplicates(subset=['ip'])
121-
122-
# Count screen resolutions
123-
screen_counts = unique_df['screen'].value_counts().head(10) # Top 10 resolutions
124-
98+
screen_counts = unique_df['screen'].value_counts().head(10)
12599
plt.figure(figsize=(12, 6))
126100
screen_counts.plot(kind='bar')
127101
plt.title('Screen Resolutions of Unique Visitors (Top 10)')
128102
plt.xlabel('Resolution')
129103
plt.ylabel('Count')
130104
plt.xticks(rotation=45)
131105
plt.tight_layout()
132-
plt.savefig(output_pattern.format(5))
106+
plt.savefig(output_pattern.format(num))
133107
plt.close()
134-
135108
return True
136109
except Exception as e:
137110
print(f"Error creating screen resolution chart: {str(e)}")
138111
return False
139112

140-
def create_os_visualization(df, output_pattern):
113+
def create_os_visualization(df, output_pattern, num):
141114
"""Create visualization of operating systems"""
142115
try:
143-
# Get unique visitors by IP
144116
unique_df = df.drop_duplicates(subset=['ip'])
145-
146-
# Define OS categories and their patterns
147117
os_categories = {
148118
'Windows': ['Win32', 'Win64', 'Win16', 'WinCE', 'Windows'],
149119
'Mac': ['MacIntel', 'MacPPC', 'Mac68K', 'Mac', 'macOS'],
@@ -152,198 +122,111 @@ def create_os_visualization(df, output_pattern):
152122
'Android': ['Android'],
153123
'Other': ['SunOS', 'HP-UX']
154124
}
155-
156-
# Categorize platforms
157125
def categorize_os(platform):
158126
for category, patterns in os_categories.items():
159127
if any(pattern in platform for pattern in patterns):
160128
return category
161129
return 'Other'
162-
163130
unique_df['os_category'] = unique_df['platform'].apply(categorize_os)
164131
os_counts = unique_df['os_category'].value_counts()
165-
166-
# Create figure with OS icons
167132
fig, ax = plt.subplots(figsize=(14, 8))
168-
169-
# Define positions for each OS category
170133
categories = list(os_categories.keys())
171134
positions = np.arange(len(categories))
172-
173-
# Create bars
174135
bars = ax.bar(positions, [os_counts.get(cat, 0) for cat in categories])
175-
176-
# Add percentages and counts
177136
total = os_counts.sum()
178137
for i, bar in enumerate(bars):
179138
count = os_counts.get(categories[i], 0)
180139
percentage = (count / total) * 100 if total > 0 else 0
181140
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 5,
182141
f"{percentage:.1f}%\n({count})",
183142
ha='center', va='bottom')
184-
185143
ax.set_xticks(positions)
186144
ax.set_xticklabels(categories)
187145
ax.set_title('Operating Systems of Unique Visitors')
188146
ax.set_ylabel('Count')
189-
190147
plt.tight_layout()
191-
plt.savefig(output_pattern.format(6))
148+
plt.savefig(output_pattern.format(num))
192149
plt.close()
193-
194150
return True
195151
except Exception as e:
196152
print(f"Error creating OS visualization: {str(e)}")
197153
return False
198154

199-
def create_browser_visualization(df, output_pattern):
155+
def create_browser_visualization(df, output_pattern, num):
200156
"""Create visualization of browsers"""
201157
try:
202-
# Get unique visitors by IP
203158
unique_df = df.drop_duplicates(subset=['ip'])
204-
205-
# Count browsers
206159
browser_counts = unique_df['browserName'].value_counts()
207-
208-
# Create figure
209160
fig, ax = plt.subplots(figsize=(14, 8))
210-
211-
# Create bars
212161
positions = np.arange(len(browser_counts))
213162
bars = ax.bar(positions, browser_counts.values)
214-
215-
# Add percentages and counts
216163
total = browser_counts.sum()
217164
for i, bar in enumerate(bars):
218165
count = browser_counts.values[i]
219166
percentage = (count / total) * 100
220167
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 5,
221168
f"{percentage:.1f}%\n({count})",
222169
ha='center', va='bottom')
223-
224170
ax.set_xticks(positions)
225171
ax.set_xticklabels(browser_counts.index)
226172
ax.set_title('Browsers of Unique Visitors')
227173
ax.set_ylabel('Count')
228-
229174
plt.tight_layout()
230-
plt.savefig(output_pattern.format(7))
175+
plt.savefig(output_pattern.format(num))
231176
plt.close()
232-
233177
return True
234178
except Exception as e:
235179
print(f"Error creating browser visualization: {str(e)}")
236180
return False
237181

238-
def create_media_devices_table(df, output_pattern):
182+
def create_media_devices_table(df, output_pattern, num):
239183
"""Create table of media devices access"""
240184
try:
241-
# Get unique visitors by IP
242185
unique_df = df.drop_duplicates(subset=['ip'])
243-
244-
# Extract media device information
245186
media_data = {
246187
'Device': ['Speakers', 'Microphones', 'Webcams'],
247188
'Count': [0, 0, 0],
248189
'Percentage': [0, 0, 0]
249190
}
250-
251191
total_visitors = len(unique_df)
252-
253192
if 'multimediaDevices' in unique_df.columns:
254-
# Count devices
255193
speakers_count = unique_df['multimediaDevices'].apply(
256194
lambda x: x.get('speakers', 0) > 0 if isinstance(x, dict) else False
257195
).sum()
258-
259196
micros_count = unique_df['multimediaDevices'].apply(
260197
lambda x: x.get('micros', 0) > 0 if isinstance(x, dict) else False
261198
).sum()
262-
263199
webcams_count = unique_df['multimediaDevices'].apply(
264200
lambda x: x.get('webcams', 0) > 0 if isinstance(x, dict) else False
265201
).sum()
266-
267-
# Update data
268202
media_data['Count'] = [speakers_count, micros_count, webcams_count]
269203
media_data['Percentage'] = [
270204
(speakers_count / total_visitors) * 100 if total_visitors > 0 else 0,
271205
(micros_count / total_visitors) * 100 if total_visitors > 0 else 0,
272206
(webcams_count / total_visitors) * 100 if total_visitors > 0 else 0
273207
]
274-
275-
# Create table
276208
fig, ax = plt.subplots(figsize=(10, 6))
277209
ax.axis('tight')
278210
ax.axis('off')
279-
280-
# Format percentage values
281211
formatted_percentages = [f"{p:.1f}%" for p in media_data['Percentage']]
282-
283212
table_data = [
284213
media_data['Device'],
285214
media_data['Count'],
286215
formatted_percentages
287216
]
288-
289217
table = ax.table(
290218
cellText=list(zip(*table_data)),
291219
colLabels=['Device', 'Count', 'Percentage'],
292220
loc='center',
293221
cellLoc='center'
294222
)
295-
296223
table.auto_set_font_size(False)
297224
table.set_fontsize(12)
298225
table.scale(1.2, 1.5)
299-
300226
plt.title('Media Devices Access')
301-
plt.savefig(output_pattern.format(8))
227+
plt.savefig(output_pattern.format(num))
302228
plt.close()
303-
304229
return True
305230
except Exception as e:
306231
print(f"Error creating media devices table: {str(e)}")
307-
return False
308-
309-
def generate_statistics_images(stats_data, output_pattern):
310-
"""Generate visualization images from statistics data"""
311-
try:
312-
# Basic period statistics visualizations
313-
periods = list(stats_data['periodStats'].keys())
314-
totals = [v['total'] for v in stats_data['periodStats'].values()]
315-
uniques = [v['unique'] for v in stats_data['periodStats'].values()]
316-
317-
plt.figure(figsize=(10, 6))
318-
plt.bar(periods, totals, label='Total Visits')
319-
plt.bar(periods, uniques, label='Unique Visitors')
320-
plt.title('Visitors Statistics')
321-
plt.legend()
322-
plt.savefig(output_pattern.format(1))
323-
plt.close()
324-
325-
# Pie chart for period distribution
326-
plt.figure(figsize=(8, 8))
327-
plt.pie(totals, labels=periods, autopct='%1.1f%%')
328-
plt.title('Visits Distribution')
329-
plt.savefig(output_pattern.format(2))
330-
plt.close()
331-
332-
# Get app from current context if available
333-
from flask import current_app
334-
app = current_app._get_current_object()
335-
336-
# Load data from MongoDB
337-
df = load_data_from_mongodb(app)
338-
339-
if not df.empty:
340-
# Create additional visualizations
341-
create_map_visualization(df, output_pattern)
342-
create_language_chart(df, output_pattern)
343-
create_screen_resolution_chart(df, output_pattern)
344-
create_os_visualization(df, output_pattern)
345-
create_browser_visualization(df, output_pattern)
346-
create_media_devices_table(df, output_pattern)
347-
348-
except Exception as e:
349-
print(f"Error generating images: {str(e)}")
232+
return False

0 commit comments

Comments
 (0)