mcli-framework 7.3.1__py3-none-any.whl → 7.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mcli-framework might be problematic. Click here for more details.

@@ -0,0 +1,565 @@
1
+ """
2
+ Gravity Anomaly Visualization Dashboard
3
+ Correlates gravitational measurements with politician locations and trading activity
4
+ """
5
+
6
+ import streamlit as st
7
+ import pandas as pd
8
+ import plotly.graph_objects as go
9
+ import plotly.express as px
10
+ from datetime import datetime, timedelta
11
+ from typing import List, Dict, Optional, Tuple
12
+ import numpy as np
13
+
14
+ # Configure page
15
+ st.set_page_config(
16
+ page_title="Gravity Anomaly Monitor",
17
+ page_icon="🌍",
18
+ layout="wide",
19
+ initial_sidebar_state="expanded"
20
+ )
21
+
22
+ # Custom CSS for better styling
23
+ st.markdown("""
24
+ <style>
25
+ .main-header {
26
+ font-size: 2.5rem;
27
+ font-weight: 700;
28
+ color: #1f77b4;
29
+ margin-bottom: 1rem;
30
+ }
31
+ .metric-card {
32
+ background-color: #f0f2f6;
33
+ padding: 1rem;
34
+ border-radius: 0.5rem;
35
+ margin: 0.5rem 0;
36
+ }
37
+ .alert-high {
38
+ color: #d32f2f;
39
+ font-weight: 600;
40
+ }
41
+ .alert-medium {
42
+ color: #f57c00;
43
+ font-weight: 600;
44
+ }
45
+ .alert-low {
46
+ color: #388e3c;
47
+ font-weight: 600;
48
+ }
49
+ </style>
50
+ """, unsafe_allow_html=True)
51
+
52
+
53
+ class GravityData:
54
+ """Simulates gravity measurement data (in production, would fetch from real sensors/APIs)"""
55
+
56
+ @staticmethod
57
+ def generate_gravity_anomalies(lat: float, lon: float, radius_km: float = 50) -> pd.DataFrame:
58
+ """
59
+ Generate simulated gravity measurements near a location
60
+ In production: fetch from GRACE satellite data, ground sensors, or geological surveys
61
+ """
62
+ num_points = np.random.randint(20, 50)
63
+
64
+ # Generate points within radius
65
+ angles = np.random.uniform(0, 2 * np.pi, num_points)
66
+ distances = np.random.uniform(0, radius_km, num_points)
67
+
68
+ # Convert to lat/lon offsets (approximate)
69
+ lat_offsets = (distances / 111) * np.cos(angles) # 111 km per degree latitude
70
+ lon_offsets = (distances / (111 * np.cos(np.radians(lat)))) * np.sin(angles)
71
+
72
+ # Generate gravity anomalies (mGal - milligals)
73
+ # Normal Earth gravity ~9.8 m/s^2, anomalies typically +/- 100 mGal
74
+ base_gravity = 980000 # mGal
75
+ anomalies = np.random.normal(0, 30, num_points) # +/- 30 mGal typical range
76
+
77
+ # Add some interesting features
78
+ if np.random.random() > 0.7: # 30% chance of significant anomaly
79
+ spike_idx = np.random.randint(0, num_points)
80
+ anomalies[spike_idx] += np.random.uniform(50, 100)
81
+
82
+ timestamps = [
83
+ datetime.now() - timedelta(hours=np.random.randint(0, 168)) # Last week
84
+ for _ in range(num_points)
85
+ ]
86
+
87
+ return pd.DataFrame({
88
+ 'latitude': lat + lat_offsets,
89
+ 'longitude': lon + lon_offsets,
90
+ 'gravity_anomaly_mgal': anomalies,
91
+ 'absolute_gravity_mgal': base_gravity + anomalies,
92
+ 'measurement_time': timestamps,
93
+ 'distance_km': distances,
94
+ 'quality': np.random.choice(['high', 'medium', 'low'], num_points, p=[0.6, 0.3, 0.1])
95
+ })
96
+
97
+
98
+ class PoliticianLocations:
99
+ """Manages politician location and trading data"""
100
+
101
+ @staticmethod
102
+ def get_sample_politicians() -> pd.DataFrame:
103
+ """
104
+ Sample politician data with locations
105
+ In production: integrate with mcli's politician_trading database
106
+ """
107
+ politicians = [
108
+ {
109
+ 'name': 'Nancy Pelosi',
110
+ 'role': 'US House Representative',
111
+ 'state': 'California',
112
+ 'district': 'CA-11',
113
+ 'party': 'Democrat',
114
+ 'lat': 37.7749, # San Francisco
115
+ 'lon': -122.4194,
116
+ 'recent_trades': 15,
117
+ 'total_trade_volume': 5_000_000,
118
+ 'last_trade_date': datetime(2025, 10, 5),
119
+ },
120
+ {
121
+ 'name': 'Tommy Tuberville',
122
+ 'role': 'US Senator',
123
+ 'state': 'Alabama',
124
+ 'district': None,
125
+ 'party': 'Republican',
126
+ 'lat': 32.3668, # Montgomery
127
+ 'lon': -86.3000,
128
+ 'recent_trades': 23,
129
+ 'total_trade_volume': 3_200_000,
130
+ 'last_trade_date': datetime(2025, 10, 3),
131
+ },
132
+ {
133
+ 'name': 'Josh Gottheimer',
134
+ 'role': 'US House Representative',
135
+ 'state': 'New Jersey',
136
+ 'district': 'NJ-05',
137
+ 'party': 'Democrat',
138
+ 'lat': 40.9168, # Ridgewood
139
+ 'lon': -74.1168,
140
+ 'recent_trades': 12,
141
+ 'total_trade_volume': 2_800_000,
142
+ 'last_trade_date': datetime(2025, 10, 7),
143
+ },
144
+ {
145
+ 'name': 'Dan Crenshaw',
146
+ 'role': 'US House Representative',
147
+ 'state': 'Texas',
148
+ 'district': 'TX-02',
149
+ 'party': 'Republican',
150
+ 'lat': 29.7604, # Houston
151
+ 'lon': -95.3698,
152
+ 'recent_trades': 18,
153
+ 'total_trade_volume': 4_100_000,
154
+ 'last_trade_date': datetime(2025, 10, 6),
155
+ },
156
+ {
157
+ 'name': 'Ro Khanna',
158
+ 'role': 'US House Representative',
159
+ 'state': 'California',
160
+ 'district': 'CA-17',
161
+ 'party': 'Democrat',
162
+ 'lat': 37.3861, # San Jose
163
+ 'lon': -121.8947,
164
+ 'recent_trades': 8,
165
+ 'total_trade_volume': 1_500_000,
166
+ 'last_trade_date': datetime(2025, 10, 4),
167
+ },
168
+ ]
169
+
170
+ return pd.DataFrame(politicians)
171
+
172
+
173
+ def create_gravity_map(politicians_df: pd.DataFrame, selected_politician: Optional[str] = None) -> go.Figure:
174
+ """Create interactive map showing politician locations and gravity anomalies"""
175
+
176
+ fig = go.Figure()
177
+
178
+ # Add politician markers
179
+ for _, pol in politicians_df.iterrows():
180
+ is_selected = pol['name'] == selected_politician
181
+
182
+ fig.add_trace(go.Scattergeo(
183
+ lon=[pol['lon']],
184
+ lat=[pol['lat']],
185
+ mode='markers+text',
186
+ marker=dict(
187
+ size=20 if is_selected else 12,
188
+ color='red' if is_selected else 'blue',
189
+ symbol='star',
190
+ line=dict(width=2, color='white')
191
+ ),
192
+ text=pol['name'],
193
+ textposition='top center',
194
+ name=pol['name'],
195
+ hovertemplate=(
196
+ f"<b>{pol['name']}</b><br>"
197
+ f"Role: {pol['role']}<br>"
198
+ f"State: {pol['state']}<br>"
199
+ f"Recent Trades: {pol['recent_trades']}<br>"
200
+ f"Trade Volume: ${pol['total_trade_volume']:,.0f}<br>"
201
+ "<extra></extra>"
202
+ ),
203
+ ))
204
+
205
+ # Add gravity measurement points if politician is selected
206
+ if is_selected:
207
+ gravity_data = GravityData.generate_gravity_anomalies(pol['lat'], pol['lon'])
208
+
209
+ # Color by anomaly strength
210
+ colors = gravity_data['gravity_anomaly_mgal']
211
+
212
+ fig.add_trace(go.Scattergeo(
213
+ lon=gravity_data['longitude'],
214
+ lat=gravity_data['latitude'],
215
+ mode='markers',
216
+ marker=dict(
217
+ size=8,
218
+ color=colors,
219
+ colorscale='RdYlGn_r',
220
+ cmin=-50,
221
+ cmax=50,
222
+ colorbar=dict(
223
+ title="Gravity<br>Anomaly<br>(mGal)",
224
+ x=1.1
225
+ ),
226
+ showscale=True,
227
+ ),
228
+ name='Gravity Measurements',
229
+ hovertemplate=(
230
+ "Anomaly: %{marker.color:.2f} mGal<br>"
231
+ "Distance: %{customdata[0]:.1f} km<br>"
232
+ "Time: %{customdata[1]}<br>"
233
+ "<extra></extra>"
234
+ ),
235
+ customdata=gravity_data[['distance_km', 'measurement_time']].values
236
+ ))
237
+
238
+ # Update layout
239
+ fig.update_geos(
240
+ projection_type='natural earth',
241
+ showcountries=True,
242
+ countrycolor='lightgray',
243
+ showland=True,
244
+ landcolor='white',
245
+ showocean=True,
246
+ oceancolor='lightblue',
247
+ coastlinewidth=1,
248
+ )
249
+
250
+ fig.update_layout(
251
+ title='Politician Locations & Gravity Anomalies',
252
+ height=600,
253
+ showlegend=False,
254
+ margin=dict(l=0, r=0, t=40, b=0)
255
+ )
256
+
257
+ return fig
258
+
259
+
260
+ def create_gravity_heatmap(gravity_df: pd.DataFrame) -> go.Figure:
261
+ """Create heatmap of gravity measurements over time"""
262
+
263
+ fig = go.Figure(data=go.Densitymapbox(
264
+ lat=gravity_df['latitude'],
265
+ lon=gravity_df['longitude'],
266
+ z=gravity_df['gravity_anomaly_mgal'],
267
+ radius=20,
268
+ colorscale='RdYlGn_r',
269
+ zmin=-50,
270
+ zmax=50,
271
+ hovertemplate='Anomaly: %{z:.2f} mGal<extra></extra>',
272
+ ))
273
+
274
+ # Calculate center point
275
+ center_lat = gravity_df['latitude'].mean()
276
+ center_lon = gravity_df['longitude'].mean()
277
+
278
+ fig.update_layout(
279
+ mapbox_style="open-street-map",
280
+ mapbox=dict(
281
+ center=dict(lat=center_lat, lon=center_lon),
282
+ zoom=8
283
+ ),
284
+ margin=dict(l=0, r=0, t=0, b=0),
285
+ height=400
286
+ )
287
+
288
+ return fig
289
+
290
+
291
+ def create_correlation_chart(politician_df: pd.DataFrame, gravity_df: pd.DataFrame) -> go.Figure:
292
+ """Create scatter plot correlating gravity anomalies with trading activity"""
293
+
294
+ # Aggregate gravity data by time period
295
+ gravity_stats = {
296
+ 'max_anomaly': gravity_df['gravity_anomaly_mgal'].max(),
297
+ 'mean_anomaly': gravity_df['gravity_anomaly_mgal'].mean(),
298
+ 'std_anomaly': gravity_df['gravity_anomaly_mgal'].std(),
299
+ 'num_measurements': len(gravity_df),
300
+ }
301
+
302
+ fig = go.Figure()
303
+
304
+ fig.add_trace(go.Bar(
305
+ x=['Max Anomaly', 'Mean Anomaly', 'Std Dev', 'Measurements'],
306
+ y=[
307
+ gravity_stats['max_anomaly'],
308
+ gravity_stats['mean_anomaly'],
309
+ gravity_stats['std_anomaly'],
310
+ gravity_stats['num_measurements'] / 10 # Scale for visibility
311
+ ],
312
+ marker_color=['red', 'orange', 'yellow', 'green'],
313
+ text=[f"{v:.2f}" for v in [
314
+ gravity_stats['max_anomaly'],
315
+ gravity_stats['mean_anomaly'],
316
+ gravity_stats['std_anomaly'],
317
+ gravity_stats['num_measurements'] / 10
318
+ ]],
319
+ textposition='auto',
320
+ ))
321
+
322
+ fig.update_layout(
323
+ title='Gravity Anomaly Statistics',
324
+ xaxis_title='Metric',
325
+ yaxis_title='Value',
326
+ height=300,
327
+ showlegend=False
328
+ )
329
+
330
+ return fig
331
+
332
+
333
+ def create_timeline_chart(gravity_df: pd.DataFrame, politician_name: str) -> go.Figure:
334
+ """Create timeline showing gravity measurements over time"""
335
+
336
+ # Sort by time
337
+ gravity_df = gravity_df.sort_values('measurement_time')
338
+
339
+ fig = go.Figure()
340
+
341
+ fig.add_trace(go.Scatter(
342
+ x=gravity_df['measurement_time'],
343
+ y=gravity_df['gravity_anomaly_mgal'],
344
+ mode='markers+lines',
345
+ marker=dict(
346
+ size=8,
347
+ color=gravity_df['gravity_anomaly_mgal'],
348
+ colorscale='RdYlGn_r',
349
+ showscale=False,
350
+ line=dict(width=1, color='white')
351
+ ),
352
+ line=dict(width=1, color='gray', dash='dot'),
353
+ name='Gravity Anomaly',
354
+ hovertemplate=(
355
+ 'Time: %{x}<br>'
356
+ 'Anomaly: %{y:.2f} mGal<br>'
357
+ '<extra></extra>'
358
+ )
359
+ ))
360
+
361
+ # Add zero line
362
+ fig.add_hline(y=0, line_dash="dash", line_color="gray", opacity=0.5)
363
+
364
+ fig.update_layout(
365
+ title=f'Gravity Measurements Over Time - {politician_name}',
366
+ xaxis_title='Time',
367
+ yaxis_title='Gravity Anomaly (mGal)',
368
+ height=350,
369
+ showlegend=False,
370
+ hovermode='closest'
371
+ )
372
+
373
+ return fig
374
+
375
+
376
+ def main():
377
+ """Main application"""
378
+
379
+ # Header
380
+ st.markdown('<h1 class="main-header">🌍 Gravity Anomaly Monitor</h1>', unsafe_allow_html=True)
381
+ st.markdown("""
382
+ Monitor gravitational anomalies near politician locations and correlate with trading activity.
383
+ Data sources: GRACE satellites, ground-based gravimeters, and geological surveys.
384
+ """)
385
+
386
+ # Sidebar
387
+ st.sidebar.header("⚙️ Configuration")
388
+
389
+ # Load politician data
390
+ politicians_df = PoliticianLocations.get_sample_politicians()
391
+
392
+ # Politician selection
393
+ selected_politician = st.sidebar.selectbox(
394
+ "Select Politician",
395
+ options=['All'] + politicians_df['name'].tolist(),
396
+ index=0
397
+ )
398
+
399
+ # Filters
400
+ st.sidebar.subheader("📊 Filters")
401
+
402
+ date_range = st.sidebar.slider(
403
+ "Data Range (days)",
404
+ min_value=1,
405
+ max_value=30,
406
+ value=7,
407
+ help="Number of days of historical data to display"
408
+ )
409
+
410
+ min_trade_volume = st.sidebar.number_input(
411
+ "Minimum Trade Volume ($)",
412
+ min_value=0,
413
+ max_value=10_000_000,
414
+ value=1_000_000,
415
+ step=500_000,
416
+ format="%d"
417
+ )
418
+
419
+ # Filter politicians by trade volume
420
+ filtered_politicians = politicians_df[
421
+ politicians_df['total_trade_volume'] >= min_trade_volume
422
+ ]
423
+
424
+ # Main content
425
+ if selected_politician != 'All':
426
+ # Single politician view
427
+ pol = politicians_df[politicians_df['name'] == selected_politician].iloc[0]
428
+
429
+ # Metrics row
430
+ col1, col2, col3, col4 = st.columns(4)
431
+
432
+ with col1:
433
+ st.metric(
434
+ label="Recent Trades",
435
+ value=pol['recent_trades'],
436
+ delta=f"Last: {(datetime.now() - pol['last_trade_date']).days}d ago"
437
+ )
438
+
439
+ with col2:
440
+ st.metric(
441
+ label="Trade Volume",
442
+ value=f"${pol['total_trade_volume']:,.0f}",
443
+ delta=None
444
+ )
445
+
446
+ with col3:
447
+ gravity_data = GravityData.generate_gravity_anomalies(pol['lat'], pol['lon'])
448
+ max_anomaly = gravity_data['gravity_anomaly_mgal'].max()
449
+ alert_class = 'alert-high' if max_anomaly > 40 else 'alert-medium' if max_anomaly > 20 else 'alert-low'
450
+ st.metric(
451
+ label="Max Gravity Anomaly",
452
+ value=f"{max_anomaly:.2f} mGal",
453
+ help="Unusually high anomalies may indicate geological features or data quality issues"
454
+ )
455
+
456
+ with col4:
457
+ st.metric(
458
+ label="Measurements",
459
+ value=len(gravity_data),
460
+ delta=f"{len(gravity_data[gravity_data['quality'] == 'high'])} high quality"
461
+ )
462
+
463
+ # Tabs for different visualizations
464
+ tab1, tab2, tab3, tab4 = st.tabs(["🗺️ Map", "🔥 Heatmap", "📈 Timeline", "📊 Statistics"])
465
+
466
+ with tab1:
467
+ st.plotly_chart(
468
+ create_gravity_map(filtered_politicians, selected_politician),
469
+ config={"displayModeBar": True},
470
+ use_container_width=True
471
+ )
472
+
473
+ with tab2:
474
+ st.plotly_chart(
475
+ create_gravity_heatmap(gravity_data),
476
+ config={"displayModeBar": True},
477
+ use_container_width=True
478
+ )
479
+
480
+ # Data table
481
+ st.subheader("Measurement Data")
482
+ st.dataframe(
483
+ gravity_data[[
484
+ 'latitude', 'longitude', 'gravity_anomaly_mgal',
485
+ 'distance_km', 'quality', 'measurement_time'
486
+ ]].sort_values('gravity_anomaly_mgal', ascending=False).head(10),
487
+ use_container_width=True
488
+ )
489
+
490
+ with tab3:
491
+ st.plotly_chart(
492
+ create_timeline_chart(gravity_data, selected_politician),
493
+ config={"displayModeBar": True},
494
+ use_container_width=True
495
+ )
496
+
497
+ with tab4:
498
+ st.plotly_chart(
499
+ create_correlation_chart(filtered_politicians, gravity_data),
500
+ config={"displayModeBar": True},
501
+ use_container_width=True
502
+ )
503
+
504
+ # Additional stats
505
+ col1, col2 = st.columns(2)
506
+
507
+ with col1:
508
+ st.subheader("Gravity Statistics")
509
+ st.write(f"**Mean Anomaly:** {gravity_data['gravity_anomaly_mgal'].mean():.2f} mGal")
510
+ st.write(f"**Std Dev:** {gravity_data['gravity_anomaly_mgal'].std():.2f} mGal")
511
+ st.write(f"**Min:** {gravity_data['gravity_anomaly_mgal'].min():.2f} mGal")
512
+ st.write(f"**Max:** {gravity_data['gravity_anomaly_mgal'].max():.2f} mGal")
513
+
514
+ with col2:
515
+ st.subheader("Data Quality")
516
+ quality_counts = gravity_data['quality'].value_counts()
517
+ st.bar_chart(quality_counts)
518
+
519
+ else:
520
+ # Overview of all politicians
521
+ st.subheader("📍 All Politicians Overview")
522
+
523
+ st.plotly_chart(
524
+ create_gravity_map(filtered_politicians),
525
+ config={"displayModeBar": True},
526
+ use_container_width=True
527
+ )
528
+
529
+ # Summary table
530
+ st.subheader("Trading Activity Summary")
531
+ summary_df = filtered_politicians[[
532
+ 'name', 'role', 'state', 'party',
533
+ 'recent_trades', 'total_trade_volume', 'last_trade_date'
534
+ ]].sort_values('total_trade_volume', ascending=False)
535
+
536
+ st.dataframe(summary_df, use_container_width=True)
537
+
538
+ # Trading volume chart
539
+ st.subheader("Trade Volume Comparison")
540
+ fig = px.bar(
541
+ filtered_politicians.sort_values('total_trade_volume', ascending=True),
542
+ x='total_trade_volume',
543
+ y='name',
544
+ orientation='h',
545
+ color='party',
546
+ color_discrete_map={'Democrat': 'blue', 'Republican': 'red'},
547
+ labels={'total_trade_volume': 'Total Trade Volume ($)', 'name': 'Politician'},
548
+ title='Trade Volume by Politician'
549
+ )
550
+ st.plotly_chart(fig, config={"displayModeBar": True}, use_container_width=True)
551
+
552
+ # Footer
553
+ st.markdown("---")
554
+ st.markdown("""
555
+ **Data Sources:**
556
+ - Gravity: GRACE satellites, ground gravimeters, geological surveys
557
+ - Trading: mcli politician trading database
558
+ - Locations: Official government records
559
+
560
+ **Note:** This is a demonstration. In production, integrate with real-time data sources.
561
+ """)
562
+
563
+
564
+ if __name__ == "__main__":
565
+ main()