Update pages/dashboard.py
Browse files- pages/dashboard.py +280 -271
pages/dashboard.py
CHANGED
@@ -1,317 +1,326 @@
|
|
|
|
|
|
|
|
1 |
import streamlit as st
|
2 |
import pandas as pd
|
3 |
-
import numpy as np
|
4 |
import plotly.express as px
|
5 |
import plotly.graph_objects as go
|
6 |
from datetime import datetime, timedelta
|
7 |
-
|
8 |
from utils.storage import load_data, save_data, load_dataframe, save_dataframe
|
9 |
-
from utils.
|
10 |
-
from utils.error_handling import handle_ui_exceptions
|
11 |
-
from utils.logging import get_logger
|
12 |
|
13 |
-
logger = get_logger(__name__)
|
14 |
|
15 |
-
@
|
16 |
def create_dashboard_page():
|
17 |
-
"""
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
with
|
29 |
-
|
30 |
-
|
31 |
-
with tab3:
|
32 |
-
create_data_upload_section()
|
33 |
-
|
34 |
-
with tab4:
|
35 |
-
create_realtime_section()
|
36 |
-
|
37 |
-
@handle_ui_exceptions
|
38 |
-
def create_overview_section():
|
39 |
-
"""Create the overview section of the dashboard"""
|
40 |
-
st.header("π Overview")
|
41 |
-
|
42 |
-
# Create sample metrics
|
43 |
-
col1, col2, col3, col4 = st.columns(4)
|
44 |
-
|
45 |
-
with col1:
|
46 |
-
st.metric("Total Records", "1,234", "12%")
|
47 |
-
|
48 |
-
with col2:
|
49 |
-
st.metric("Active Users", "567", "8%")
|
50 |
-
|
51 |
-
with col3:
|
52 |
-
st.metric("Processing Time", "2.3s", "-0.5s")
|
53 |
-
|
54 |
-
with col4:
|
55 |
-
st.metric("Success Rate", "98.5%", "1.2%")
|
56 |
-
|
57 |
-
# Create sample charts
|
58 |
-
col1, col2 = st.columns(2)
|
59 |
-
|
60 |
-
with col1:
|
61 |
-
st.subheader("π Trend Analysis")
|
62 |
-
# Generate sample data
|
63 |
-
dates = pd.date_range(start='2024-01-01', end='2024-12-31', freq='D')
|
64 |
-
values = np.random.randn(len(dates)).cumsum() + 100
|
65 |
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
|
71 |
-
|
72 |
-
st.
|
73 |
-
|
74 |
-
|
75 |
-
st.subheader("π¦ Category Distribution")
|
76 |
-
categories = ['A', 'B', 'C', 'D', 'E']
|
77 |
-
values = np.random.randint(10, 100, size=len(categories))
|
78 |
|
79 |
-
|
80 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
|
82 |
-
|
83 |
-
def
|
84 |
-
"""
|
85 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
|
87 |
-
|
88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
|
90 |
with col1:
|
91 |
-
|
92 |
-
"
|
93 |
-
value=
|
94 |
-
|
95 |
)
|
96 |
|
97 |
with col2:
|
98 |
-
|
99 |
-
"
|
100 |
-
|
|
|
101 |
)
|
102 |
|
103 |
with col3:
|
104 |
-
|
105 |
-
"
|
106 |
-
|
|
|
107 |
)
|
108 |
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
dates = pd.date_range(start=start_date, end=end_date, freq='D')
|
116 |
-
values = np.random.randn(len(dates)).cumsum() + np.random.randint(50, 200)
|
117 |
-
|
118 |
-
df = pd.DataFrame({
|
119 |
-
'Date': dates,
|
120 |
-
metric: values
|
121 |
-
})
|
122 |
-
|
123 |
-
# Create chart based on selection
|
124 |
-
if chart_type == "Line":
|
125 |
-
fig = px.line(df, x='Date', y=metric, title=f'{metric} Over Time')
|
126 |
-
elif chart_type == "Bar":
|
127 |
-
fig = px.bar(df, x='Date', y=metric, title=f'{metric} by Day')
|
128 |
-
elif chart_type == "Scatter":
|
129 |
-
df['Random'] = np.random.randn(len(df))
|
130 |
-
fig = px.scatter(df, x='Random', y=metric, title=f'{metric} Scatter Plot')
|
131 |
-
elif chart_type == "Area":
|
132 |
-
fig = px.area(df, x='Date', y=metric, title=f'{metric} Area Chart')
|
133 |
-
elif chart_type == "Histogram":
|
134 |
-
fig = px.histogram(df, x=metric, title=f'{metric} Distribution')
|
135 |
-
|
136 |
-
st.plotly_chart(fig, use_container_width=True)
|
137 |
-
|
138 |
-
# Show data table
|
139 |
-
with st.expander("View Raw Data"):
|
140 |
-
st.dataframe(df)
|
141 |
|
142 |
-
@handle_ui_exceptions
|
143 |
-
def create_data_upload_section():
|
144 |
-
"""Create the data upload section"""
|
145 |
-
st.header("π€ Data Upload")
|
146 |
-
|
147 |
-
# File upload
|
148 |
-
uploaded_file = st.file_uploader(
|
149 |
-
"Upload your data file",
|
150 |
-
type=['csv', 'xlsx', 'json'],
|
151 |
-
help="Supported formats: CSV, Excel, JSON"
|
152 |
-
)
|
153 |
-
|
154 |
-
if uploaded_file is not None:
|
155 |
-
try:
|
156 |
-
# Read the uploaded file
|
157 |
-
if uploaded_file.name.endswith('.csv'):
|
158 |
-
df = pd.read_csv(uploaded_file)
|
159 |
-
elif uploaded_file.name.endswith('.xlsx'):
|
160 |
-
df = pd.read_excel(uploaded_file)
|
161 |
-
elif uploaded_file.name.endswith('.json'):
|
162 |
-
df = pd.read_json(uploaded_file)
|
163 |
-
|
164 |
-
st.success(f"File uploaded successfully! Shape: {df.shape}")
|
165 |
-
|
166 |
-
# Display data preview
|
167 |
-
st.subheader("Data Preview")
|
168 |
-
st.dataframe(df.head())
|
169 |
-
|
170 |
-
# Data summary
|
171 |
-
col1, col2 = st.columns(2)
|
172 |
-
|
173 |
-
with col1:
|
174 |
-
st.subheader("Data Info")
|
175 |
-
st.write(f"**Rows:** {len(df)}")
|
176 |
-
st.write(f"**Columns:** {len(df.columns)}")
|
177 |
-
st.write(f"**File Size:** {uploaded_file.size} bytes")
|
178 |
-
|
179 |
-
with col2:
|
180 |
-
st.subheader("Column Types")
|
181 |
-
for col, dtype in df.dtypes.items():
|
182 |
-
st.write(f"**{col}:** {dtype}")
|
183 |
-
|
184 |
-
# Save data option
|
185 |
-
if st.button("Save Data"):
|
186 |
-
save_dataframe(df, f"uploaded_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}")
|
187 |
-
st.success("Data saved successfully!")
|
188 |
-
|
189 |
-
# Basic analytics on uploaded data
|
190 |
-
if len(df.select_dtypes(include=[np.number]).columns) > 0:
|
191 |
-
st.subheader("Quick Analytics")
|
192 |
-
numeric_cols = df.select_dtypes(include=[np.number]).columns
|
193 |
-
|
194 |
-
selected_col = st.selectbox("Select column for analysis", numeric_cols)
|
195 |
-
|
196 |
-
if selected_col:
|
197 |
-
col1, col2 = st.columns(2)
|
198 |
-
|
199 |
-
with col1:
|
200 |
-
fig = px.histogram(df, x=selected_col, title=f'Distribution of {selected_col}')
|
201 |
-
st.plotly_chart(fig, use_container_width=True)
|
202 |
-
|
203 |
-
with col2:
|
204 |
-
fig = px.box(df, y=selected_col, title=f'Box Plot of {selected_col}')
|
205 |
-
st.plotly_chart(fig, use_container_width=True)
|
206 |
-
|
207 |
-
except Exception as e:
|
208 |
-
st.error(f"Error processing file: {str(e)}")
|
209 |
-
logger.error(f"File processing error: {str(e)}")
|
210 |
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
# Auto-refresh toggle
|
217 |
-
auto_refresh = st.checkbox("Enable Auto-refresh", value=False)
|
218 |
|
219 |
-
|
220 |
-
refresh_interval = st.slider("Refresh Interval (seconds)", 1, 60, 5)
|
221 |
-
st.info(f"Data will refresh every {refresh_interval} seconds")
|
222 |
|
223 |
-
#
|
224 |
-
col1, col2
|
225 |
-
|
226 |
-
# Generate real-time data
|
227 |
-
current_time = datetime.now()
|
228 |
|
229 |
with col1:
|
230 |
-
|
231 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
232 |
|
233 |
with col2:
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
))
|
266 |
-
|
267 |
-
fig.update_layout(
|
268 |
-
title='System Performance Over Time',
|
269 |
-
xaxis_title='Time',
|
270 |
-
yaxis_title='Usage (%)',
|
271 |
-
hovermode='x unified'
|
272 |
)
|
273 |
|
274 |
-
st.plotly_chart(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
|
276 |
-
|
277 |
-
st.subheader("π¨ System Status")
|
278 |
|
279 |
-
|
|
|
280 |
|
281 |
with col1:
|
282 |
-
|
283 |
-
st.write(f"**Database:** {status}")
|
284 |
|
285 |
with col2:
|
286 |
-
|
287 |
-
st.write(f"**API:** {status}")
|
288 |
|
289 |
with col3:
|
290 |
-
|
291 |
-
st.write(f"**Services:** {status}")
|
292 |
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
st.subheader("π Recent Events")
|
299 |
-
|
300 |
-
events = [
|
301 |
-
{"time": current_time - timedelta(minutes=2), "event": "System backup completed", "type": "info"},
|
302 |
-
{"time": current_time - timedelta(minutes=5), "event": "High CPU usage detected", "type": "warning"},
|
303 |
-
{"time": current_time - timedelta(minutes=8), "event": "New user registration", "type": "info"},
|
304 |
-
{"time": current_time - timedelta(minutes=12), "event": "Database connection restored", "type": "success"},
|
305 |
-
{"time": current_time - timedelta(minutes=15), "event": "Scheduled maintenance started", "type": "info"},
|
306 |
]
|
307 |
|
308 |
-
|
309 |
-
|
310 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
311 |
|
312 |
-
#
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Dashboard page for the application
|
3 |
+
"""
|
4 |
import streamlit as st
|
5 |
import pandas as pd
|
|
|
6 |
import plotly.express as px
|
7 |
import plotly.graph_objects as go
|
8 |
from datetime import datetime, timedelta
|
|
|
9 |
from utils.storage import load_data, save_data, load_dataframe, save_dataframe
|
10 |
+
from utils.error_handling import handle_data_exceptions, log_error, display_error
|
|
|
|
|
11 |
|
|
|
12 |
|
13 |
+
@handle_data_exceptions
|
14 |
def create_dashboard_page():
|
15 |
+
"""
|
16 |
+
Create the main dashboard page
|
17 |
+
"""
|
18 |
+
st.title("π Dashboard")
|
19 |
+
st.markdown("---")
|
20 |
+
|
21 |
+
# Initialize session state
|
22 |
+
if 'dashboard_data' not in st.session_state:
|
23 |
+
st.session_state.dashboard_data = generate_sample_data()
|
24 |
+
|
25 |
+
# Sidebar controls
|
26 |
+
with st.sidebar:
|
27 |
+
st.header("Dashboard Controls")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
+
# Data refresh button
|
30 |
+
if st.button("π Refresh Data"):
|
31 |
+
st.session_state.dashboard_data = generate_sample_data()
|
32 |
+
st.success("Data refreshed!")
|
33 |
|
34 |
+
# Date range selector
|
35 |
+
st.subheader("Date Range")
|
36 |
+
start_date = st.date_input("Start Date", value=datetime.now() - timedelta(days=30))
|
37 |
+
end_date = st.date_input("End Date", value=datetime.now())
|
|
|
|
|
|
|
38 |
|
39 |
+
# Chart type selector
|
40 |
+
chart_type = st.selectbox(
|
41 |
+
"Chart Type",
|
42 |
+
["Line Chart", "Bar Chart", "Area Chart", "Scatter Plot"]
|
43 |
+
)
|
44 |
+
|
45 |
+
# Main dashboard content
|
46 |
+
create_metrics_section()
|
47 |
+
create_charts_section(chart_type)
|
48 |
+
create_data_table_section()
|
49 |
|
50 |
+
|
51 |
+
def generate_sample_data():
|
52 |
+
"""
|
53 |
+
Generate sample data for the dashboard
|
54 |
+
"""
|
55 |
+
import random
|
56 |
+
import numpy as np
|
57 |
+
|
58 |
+
# Generate date range
|
59 |
+
dates = pd.date_range(start='2024-01-01', end='2024-12-31', freq='D')
|
60 |
+
|
61 |
+
# Generate sample metrics
|
62 |
+
data = {
|
63 |
+
'date': dates,
|
64 |
+
'sales': [random.randint(1000, 5000) + random.randint(-500, 500) for _ in dates],
|
65 |
+
'users': [random.randint(100, 1000) + random.randint(-100, 100) for _ in dates],
|
66 |
+
'revenue': [random.randint(5000, 25000) + random.randint(-2000, 2000) for _ in dates],
|
67 |
+
'conversion_rate': [round(random.uniform(0.02, 0.08), 4) for _ in dates]
|
68 |
+
}
|
69 |
|
70 |
+
return pd.DataFrame(data)
|
71 |
+
|
72 |
+
|
73 |
+
def create_metrics_section():
|
74 |
+
"""
|
75 |
+
Create metrics cards section
|
76 |
+
"""
|
77 |
+
st.subheader("π Key Metrics")
|
78 |
+
|
79 |
+
data = st.session_state.dashboard_data
|
80 |
+
|
81 |
+
# Calculate metrics
|
82 |
+
total_sales = data['sales'].sum()
|
83 |
+
total_users = data['users'].sum()
|
84 |
+
total_revenue = data['revenue'].sum()
|
85 |
+
avg_conversion = data['conversion_rate'].mean()
|
86 |
+
|
87 |
+
# Previous period comparison (last 30 days vs previous 30 days)
|
88 |
+
recent_data = data.tail(30)
|
89 |
+
previous_data = data.iloc[-60:-30] if len(data) >= 60 else data.head(30)
|
90 |
+
|
91 |
+
sales_change = ((recent_data['sales'].sum() - previous_data['sales'].sum()) / previous_data['sales'].sum()) * 100
|
92 |
+
users_change = ((recent_data['users'].sum() - previous_data['users'].sum()) / previous_data['users'].sum()) * 100
|
93 |
+
revenue_change = ((recent_data['revenue'].sum() - previous_data['revenue'].sum()) / previous_data['revenue'].sum()) * 100
|
94 |
+
conversion_change = ((recent_data['conversion_rate'].mean() - previous_data['conversion_rate'].mean()) / previous_data['conversion_rate'].mean()) * 100
|
95 |
+
|
96 |
+
# Display metrics in columns
|
97 |
+
col1, col2, col3, col4 = st.columns(4)
|
98 |
|
99 |
with col1:
|
100 |
+
st.metric(
|
101 |
+
label="Total Sales",
|
102 |
+
value=f"{total_sales:,}",
|
103 |
+
delta=f"{sales_change:.1f}%"
|
104 |
)
|
105 |
|
106 |
with col2:
|
107 |
+
st.metric(
|
108 |
+
label="Total Users",
|
109 |
+
value=f"{total_users:,}",
|
110 |
+
delta=f"{users_change:.1f}%"
|
111 |
)
|
112 |
|
113 |
with col3:
|
114 |
+
st.metric(
|
115 |
+
label="Total Revenue",
|
116 |
+
value=f"${total_revenue:,}",
|
117 |
+
delta=f"{revenue_change:.1f}%"
|
118 |
)
|
119 |
|
120 |
+
with col4:
|
121 |
+
st.metric(
|
122 |
+
label="Avg Conversion Rate",
|
123 |
+
value=f"{avg_conversion:.2%}",
|
124 |
+
delta=f"{conversion_change:.1f}%"
|
125 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
|
128 |
+
def create_charts_section(chart_type):
|
129 |
+
"""
|
130 |
+
Create charts section
|
131 |
+
"""
|
132 |
+
st.subheader("π Analytics Charts")
|
|
|
|
|
133 |
|
134 |
+
data = st.session_state.dashboard_data
|
|
|
|
|
135 |
|
136 |
+
# Create two columns for charts
|
137 |
+
col1, col2 = st.columns(2)
|
|
|
|
|
|
|
138 |
|
139 |
with col1:
|
140 |
+
st.write("**Sales Over Time**")
|
141 |
+
if chart_type == "Line Chart":
|
142 |
+
fig = px.line(data, x='date', y='sales', title='Daily Sales')
|
143 |
+
elif chart_type == "Bar Chart":
|
144 |
+
# Group by month for bar chart
|
145 |
+
monthly_data = data.groupby(data['date'].dt.to_period('M'))['sales'].sum().reset_index()
|
146 |
+
monthly_data['date'] = monthly_data['date'].astype(str)
|
147 |
+
fig = px.bar(monthly_data, x='date', y='sales', title='Monthly Sales')
|
148 |
+
elif chart_type == "Area Chart":
|
149 |
+
fig = px.area(data, x='date', y='sales', title='Sales Area Chart')
|
150 |
+
else: # Scatter Plot
|
151 |
+
fig = px.scatter(data, x='date', y='sales', title='Sales Scatter Plot')
|
152 |
+
|
153 |
+
fig.update_layout(height=400)
|
154 |
+
st.plotly_chart(fig, use_container_width=True)
|
155 |
|
156 |
with col2:
|
157 |
+
st.write("**Revenue vs Users**")
|
158 |
+
fig2 = px.scatter(
|
159 |
+
data,
|
160 |
+
x='users',
|
161 |
+
y='revenue',
|
162 |
+
size='sales',
|
163 |
+
color='conversion_rate',
|
164 |
+
title='Revenue vs Users (sized by Sales)',
|
165 |
+
color_continuous_scale='Viridis'
|
166 |
+
)
|
167 |
+
fig2.update_layout(height=400)
|
168 |
+
st.plotly_chart(fig2, use_container_width=True)
|
169 |
+
|
170 |
+
# Full width chart
|
171 |
+
st.write("**Multi-Metric Trend Analysis**")
|
172 |
+
|
173 |
+
# Normalize data for comparison
|
174 |
+
normalized_data = data.copy()
|
175 |
+
for col in ['sales', 'users', 'revenue']:
|
176 |
+
normalized_data[f'{col}_normalized'] = (normalized_data[col] - normalized_data[col].min()) / (normalized_data[col].max() - normalized_data[col].min())
|
177 |
+
|
178 |
+
fig3 = go.Figure()
|
179 |
+
fig3.add_trace(go.Scatter(x=normalized_data['date'], y=normalized_data['sales_normalized'], name='Sales (Normalized)'))
|
180 |
+
fig3.add_trace(go.Scatter(x=normalized_data['date'], y=normalized_data['users_normalized'], name='Users (Normalized)'))
|
181 |
+
fig3.add_trace(go.Scatter(x=normalized_data['date'], y=normalized_data['revenue_normalized'], name='Revenue (Normalized)'))
|
182 |
+
|
183 |
+
fig3.update_layout(
|
184 |
+
title='Normalized Trends Comparison',
|
185 |
+
xaxis_title='Date',
|
186 |
+
yaxis_title='Normalized Value (0-1)',
|
187 |
+
height=400
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
188 |
)
|
189 |
|
190 |
+
st.plotly_chart(fig3, use_container_width=True)
|
191 |
+
|
192 |
+
|
193 |
+
def create_data_table_section():
|
194 |
+
"""
|
195 |
+
Create data table section
|
196 |
+
"""
|
197 |
+
st.subheader("π Data Table")
|
198 |
|
199 |
+
data = st.session_state.dashboard_data
|
|
|
200 |
|
201 |
+
# Add filters
|
202 |
+
col1, col2, col3 = st.columns(3)
|
203 |
|
204 |
with col1:
|
205 |
+
min_sales = st.number_input("Min Sales", value=0, max_value=int(data['sales'].max()))
|
|
|
206 |
|
207 |
with col2:
|
208 |
+
min_users = st.number_input("Min Users", value=0, max_value=int(data['users'].max()))
|
|
|
209 |
|
210 |
with col3:
|
211 |
+
min_revenue = st.number_input("Min Revenue", value=0, max_value=int(data['revenue'].max()))
|
|
|
212 |
|
213 |
+
# Filter data
|
214 |
+
filtered_data = data[
|
215 |
+
(data['sales'] >= min_sales) &
|
216 |
+
(data['users'] >= min_users) &
|
217 |
+
(data['revenue'] >= min_revenue)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
]
|
219 |
|
220 |
+
# Display filtered data
|
221 |
+
st.write(f"Showing {len(filtered_data)} of {len(data)} records")
|
222 |
+
|
223 |
+
# Format data for display
|
224 |
+
display_data = filtered_data.copy()
|
225 |
+
display_data['date'] = display_data['date'].dt.strftime('%Y-%m-%d')
|
226 |
+
display_data['revenue'] = display_data['revenue'].apply(lambda x: f"${x:,}")
|
227 |
+
display_data['conversion_rate'] = display_data['conversion_rate'].apply(lambda x: f"{x:.2%}")
|
228 |
+
|
229 |
+
st.dataframe(
|
230 |
+
display_data,
|
231 |
+
use_container_width=True,
|
232 |
+
hide_index=True,
|
233 |
+
column_config={
|
234 |
+
"date": "Date",
|
235 |
+
"sales": st.column_config.NumberColumn("Sales", format="%d"),
|
236 |
+
"users": st.column_config.NumberColumn("Users", format="%d"),
|
237 |
+
"revenue": "Revenue",
|
238 |
+
"conversion_rate": "Conversion Rate"
|
239 |
+
}
|
240 |
+
)
|
241 |
|
242 |
+
# Download button
|
243 |
+
csv = data.to_csv(index=False)
|
244 |
+
st.download_button(
|
245 |
+
label="π₯ Download Data as CSV",
|
246 |
+
data=csv,
|
247 |
+
file_name=f"dashboard_data_{datetime.now().strftime('%Y%m%d')}.csv",
|
248 |
+
mime="text/csv"
|
249 |
+
)
|
250 |
+
|
251 |
+
|
252 |
+
def create_summary_statistics():
|
253 |
+
"""
|
254 |
+
Create summary statistics section
|
255 |
+
"""
|
256 |
+
data = st.session_state.dashboard_data
|
257 |
+
|
258 |
+
st.subheader("π Summary Statistics")
|
259 |
+
|
260 |
+
# Calculate statistics
|
261 |
+
stats = data[['sales', 'users', 'revenue', 'conversion_rate']].describe()
|
262 |
+
|
263 |
+
# Display statistics table
|
264 |
+
st.dataframe(
|
265 |
+
stats,
|
266 |
+
use_container_width=True,
|
267 |
+
column_config={
|
268 |
+
"sales": st.column_config.NumberColumn("Sales", format="%.0f"),
|
269 |
+
"users": st.column_config.NumberColumn("Users", format="%.0f"),
|
270 |
+
"revenue": st.column_config.NumberColumn("Revenue", format="%.0f"),
|
271 |
+
"conversion_rate": st.column_config.NumberColumn("Conversion Rate", format="%.4f")
|
272 |
+
}
|
273 |
+
)
|
274 |
+
|
275 |
+
|
276 |
+
# Additional utility functions
|
277 |
+
@handle_data_exceptions
|
278 |
+
def export_dashboard_data(format_type='csv'):
|
279 |
+
"""
|
280 |
+
Export dashboard data in specified format
|
281 |
+
"""
|
282 |
+
data = st.session_state.dashboard_data
|
283 |
+
|
284 |
+
if format_type == 'csv':
|
285 |
+
return data.to_csv(index=False)
|
286 |
+
elif format_type == 'json':
|
287 |
+
return data.to_json(orient='records', date_format='iso')
|
288 |
+
elif format_type == 'excel':
|
289 |
+
# This would require openpyxl
|
290 |
+
return data.to_excel(index=False)
|
291 |
+
else:
|
292 |
+
raise ValueError(f"Unsupported format: {format_type}")
|
293 |
+
|
294 |
+
|
295 |
+
@handle_data_exceptions
|
296 |
+
def load_dashboard_config():
|
297 |
+
"""
|
298 |
+
Load dashboard configuration
|
299 |
+
"""
|
300 |
+
try:
|
301 |
+
config = load_data('dashboard_config.json')
|
302 |
+
return config if config else get_default_config()
|
303 |
+
except:
|
304 |
+
return get_default_config()
|
305 |
+
|
306 |
+
|
307 |
+
def get_default_config():
|
308 |
+
"""
|
309 |
+
Get default dashboard configuration
|
310 |
+
"""
|
311 |
+
return {
|
312 |
+
'theme': 'light',
|
313 |
+
'default_chart_type': 'Line Chart',
|
314 |
+
'refresh_interval': 300, # 5 minutes
|
315 |
+
'show_metrics': True,
|
316 |
+
'show_charts': True,
|
317 |
+
'show_table': True
|
318 |
+
}
|
319 |
+
|
320 |
+
|
321 |
+
@handle_data_exceptions
|
322 |
+
def save_dashboard_config(config):
|
323 |
+
"""
|
324 |
+
Save dashboard configuration
|
325 |
+
"""
|
326 |
+
return save_data(config, 'dashboard_config.json')
|