euler314 commited on
Commit
7795d08
Β·
verified Β·
1 Parent(s): 7282961

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +636 -411
app.py CHANGED
@@ -4,14 +4,13 @@ import os
4
  import json
5
  import numpy as np
6
  import plotly.graph_objects as go
7
- from plotly.subplots import make_subplots
8
  from PIL import Image
9
  import time
10
  import io
11
 
12
  # Set page config with wider layout
13
  st.set_page_config(
14
- page_title="Eigenvalue Analysis Dashboard",
15
  page_icon="πŸ“Š",
16
  layout="wide",
17
  initial_sidebar_state="expanded"
@@ -43,28 +42,27 @@ st.markdown("""
43
  border-left: 4px solid #1E88E5;
44
  padding-left: 10px;
45
  }
46
- .stats-card {
47
- background-color: white;
48
- padding: 1rem;
49
- border-radius: 8px;
50
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
51
- text-align: center;
52
  }
53
- .stats-value {
54
- font-size: 1.8rem;
55
- font-weight: bold;
56
- color: #1E88E5;
 
 
 
 
57
  }
58
- .stats-label {
59
- font-size: 0.9rem;
60
- color: #616161;
61
- margin-top: 0.3rem;
62
  }
63
  </style>
64
  """, unsafe_allow_html=True)
65
 
66
  # Dashboard Header
67
- st.markdown('<h1 class="main-header">Eigenvalue Analysis Dashboard</h1>', unsafe_allow_html=True)
68
 
69
  # Create output directory in the current working directory
70
  current_dir = os.getcwd()
@@ -75,20 +73,14 @@ os.makedirs(output_dir, exist_ok=True)
75
  cpp_file = os.path.join(current_dir, "app.cpp")
76
  executable = os.path.join(current_dir, "eigen_analysis")
77
 
78
- # Two-column layout for the dashboard
79
- left_column, right_column = st.columns([1, 3])
 
 
80
 
81
- with left_column:
82
- st.markdown('<div class="dashboard-container">', unsafe_allow_html=True)
83
- st.markdown('<div class="panel-header">Control Panel</div>', unsafe_allow_html=True)
84
-
85
- # Check if cpp file exists and compile if necessary
86
- if not os.path.exists(cpp_file):
87
- st.error(f"C++ source file not found at: {cpp_file}")
88
- st.stop()
89
-
90
- # Compile the C++ code with the right OpenCV libraries
91
- if not os.path.exists(executable) or st.button("Recompile C++ Code"):
92
  with st.spinner("Compiling C++ code..."):
93
  compile_commands = [
94
  f"g++ -o {executable} {cpp_file} `pkg-config --cflags --libs opencv4` -std=c++11",
@@ -116,160 +108,307 @@ with left_column:
116
  # Make sure the executable is executable
117
  os.chmod(executable, 0o755)
118
  st.success("C++ code compiled successfully")
 
 
 
 
 
 
 
 
119
 
120
- # Parameter inputs with defaults and validation
121
- st.markdown("### Matrix Parameters")
122
- n = st.number_input("Sample size (n)", min_value=5, max_value=1000, value=100, step=5, help="Number of samples")
123
- p = st.number_input("Dimension (p)", min_value=5, max_value=1000, value=50, step=5, help="Dimensionality")
124
- a = st.number_input("Value for a", min_value=1.1, max_value=10.0, value=2.0, step=0.1, help="Parameter a > 1")
125
-
126
- # Automatically calculate y = p/n (as requested)
127
- y = p/n
128
- st.info(f"Value for y = p/n: {y:.4f}")
129
-
130
- st.markdown("### Calculation Controls")
131
- fineness = st.slider(
132
- "Beta points",
133
- min_value=20,
134
- max_value=500,
135
- value=100,
136
- step=10,
137
- help="Number of points to calculate along the Ξ² axis (0 to 1)"
138
- )
139
-
140
- with st.expander("Advanced Settings"):
141
- # Add controls for theoretical calculation precision
142
- theory_grid_points = st.slider(
143
- "Theoretical grid points",
144
- min_value=100,
145
- max_value=1000,
146
- value=200,
147
- step=50,
148
- help="Number of points in initial grid search for theoretical calculations"
149
- )
150
-
151
- theory_tolerance = st.number_input(
152
- "Theoretical tolerance",
153
- min_value=1e-12,
154
- max_value=1e-6,
155
- value=1e-10,
156
- format="%.1e",
157
- help="Convergence tolerance for golden section search"
158
- )
159
-
160
- # Generate button
161
- generate_button = st.button("Generate Analysis", type="primary", use_container_width=True)
162
- st.markdown('</div>', unsafe_allow_html=True)
163
-
164
- # About section
165
- with st.expander("About Eigenvalue Analysis"):
166
- st.markdown("""
167
- ## Theory
168
-
169
- This application visualizes the relationship between empirical and theoretical eigenvalues for matrices with specific properties.
170
-
171
- The analysis examines:
172
 
173
- - **Empirical Max/Min Eigenvalues**: The maximum and minimum eigenvalues calculated from the generated matrices
174
- - **Theoretical Max/Min Functions**: The theoretical bounds derived from mathematical analysis
 
 
 
 
 
 
175
 
176
- ### Key Parameters
 
 
177
 
178
- - **n**: Sample size
179
- - **p**: Dimension
180
- - **a**: Value > 1 that affects the distribution of eigenvalues
181
- - **y**: Value calculated as p/n that affects scaling
182
-
183
- ### Calculation Controls
 
 
 
 
184
 
185
- - **Beta points**: Number of points calculated along the Ξ² range (0 to 1)
186
- - **Theoretical grid points**: Number of points in initial grid search for finding theoretical max/min
187
- - **Theoretical tolerance**: Convergence tolerance for golden section search algorithm
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
- ### Mathematical Formulas
 
 
 
 
 
 
 
 
 
 
190
 
191
- Max Function:
192
- max{k ∈ (0,∞)} [yβ(a-1)k + (ak+1)((y-1)k-1)]/[(ak+1)(k²+k)]
193
 
194
- Min Function:
195
- min{t ∈ (-1/a,0)} [yβ(a-1)t + (at+1)((y-1)t-1)]/[(at+1)(t²+t)]
196
- """)
197
-
198
- with right_column:
199
- # Main visualization area
200
- st.markdown('<div class="dashboard-container">', unsafe_allow_html=True)
201
- st.markdown('<div class="panel-header">Eigenvalue Analysis Visualization</div>', unsafe_allow_html=True)
202
-
203
- # Container for the analysis results
204
- results_container = st.container()
205
-
206
- # Process when generate button is clicked
207
- if generate_button:
208
- with results_container:
209
- # Show progress
210
- progress_container = st.container()
211
- with progress_container:
212
- progress_bar = st.progress(0)
213
- status_text = st.empty()
214
-
215
- try:
216
- # Run the C++ executable with the parameters in JSON output mode
217
- data_file = os.path.join(output_dir, "eigenvalue_data.json")
218
-
219
- # Delete previous output if exists
220
- if os.path.exists(data_file):
221
- os.remove(data_file)
222
 
223
- # Execute the C++ program
224
- cmd = [
225
- executable,
226
- str(n),
227
- str(p),
228
- str(a),
229
- str(y),
230
- str(fineness),
231
- str(theory_grid_points),
232
- str(theory_tolerance),
233
- data_file
234
- ]
235
-
236
- process = subprocess.Popen(
237
- cmd,
238
- stdout=subprocess.PIPE,
239
- stderr=subprocess.PIPE,
240
- text=True
241
- )
242
-
243
- # Show output in a status area
244
- status_text.text("Starting calculations...")
245
-
246
- last_progress = 0
247
- while process.poll() is None:
248
- output = process.stdout.readline()
249
- if output:
250
- if output.startswith("PROGRESS:"):
251
- try:
252
- # Update progress bar
253
- progress_value = float(output.split(":")[1].strip())
254
- progress_bar.progress(progress_value)
255
- last_progress = progress_value
256
- status_text.text(f"Calculating... {int(progress_value * 100)}% complete")
257
- except:
258
- pass
259
- else:
260
- status_text.text(output.strip())
261
- time.sleep(0.1)
262
-
263
- return_code = process.poll()
264
-
265
- if return_code != 0:
266
- error = process.stderr.read()
267
- st.error(f"Error executing the analysis: {error}")
268
- else:
269
- progress_bar.progress(1.0)
270
- status_text.text("Calculations complete! Generating visualization...")
271
 
272
- # Load the results from the JSON file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  with open(data_file, 'r') as f:
274
  data = json.load(f)
275
 
@@ -347,7 +486,7 @@ with right_column:
347
  # Configure layout for better appearance
348
  fig.update_layout(
349
  title={
350
- 'text': f'Eigenvalue Analysis: n={n}, p={p}, a={a}, y={y:.4f}',
351
  'font': {'size': 24, 'color': '#1E88E5'},
352
  'y': 0.95,
353
  'x': 0.5,
@@ -378,256 +517,342 @@ with right_column:
378
  'borderwidth': 1
379
  },
380
  margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
381
- height=600,
382
- annotations=[
383
- {
384
- 'text': f"Max Function: max{{k ∈ (0,∞)}} [yβ(a-1)k + (ak+1)((y-1)k-1)]/[(ak+1)(k²+k)]",
385
- 'xref': 'paper', 'yref': 'paper',
386
- 'x': 0.02, 'y': 0.02,
387
- 'showarrow': False,
388
- 'font': {'size': 12, 'color': 'rgb(30, 180, 30)'},
389
- 'bgcolor': 'rgba(255, 255, 255, 0.9)',
390
- 'bordercolor': 'rgb(30, 180, 30)',
391
- 'borderwidth': 1,
392
- 'borderpad': 4
393
- },
394
- {
395
- 'text': f"Min Function: min{{t ∈ (-1/a,0)}} [yβ(a-1)t + (at+1)((y-1)t-1)]/[(at+1)(t²+t)]",
396
- 'xref': 'paper', 'yref': 'paper',
397
- 'x': 0.55, 'y': 0.02,
398
- 'showarrow': False,
399
- 'font': {'size': 12, 'color': 'rgb(180, 30, 180)'},
400
- 'bgcolor': 'rgba(255, 255, 255, 0.9)',
401
- 'bordercolor': 'rgb(180, 30, 180)',
402
- 'borderwidth': 1,
403
- 'borderpad': 4
404
- }
405
- ]
406
  )
407
 
408
- # Add custom modebar buttons
409
- fig.update_layout(
410
- modebar_add=[
411
- 'drawline', 'drawopenpath', 'drawclosedpath',
412
- 'drawcircle', 'drawrect', 'eraseshape'
413
- ],
414
- modebar_remove=['lasso2d', 'select2d'],
415
- dragmode='zoom'
416
- )
417
-
418
- # Clear progress container
419
- progress_container.empty()
420
-
421
  # Display the interactive plot in Streamlit
422
  st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
 
424
- # Generate static image for download
425
- output_file = os.path.join(output_dir, "eigenvalue_analysis.png")
426
- fig.write_image(output_file, scale=2)
427
 
428
- # Provide download button
429
- col1, col2, col3 = st.columns([1, 2, 1])
430
- with col2:
431
- with open(output_file, "rb") as file:
432
- btn = st.download_button(
433
- label="Download Plot",
434
- data=file,
435
- file_name=f"eigenvalue_analysis_n{n}_p{p}_a{a}_y{y:.4f}.png",
436
- mime="image/png",
437
- use_container_width=True
438
- )
439
 
440
- # Add statistics section with cards
441
- st.markdown("### Results Summary")
442
 
443
- # Calculate key statistics
444
- emp_max = max(max_eigenvalues)
445
- emp_min = min(min_eigenvalues)
446
- theo_max = max(theoretical_max)
447
- theo_min = min(theoretical_min)
448
- max_diff = abs(emp_max - theo_max)
449
- min_diff = abs(emp_min - theo_min)
450
 
451
- # Display statistics in a card layout
452
- col1, col2, col3, col4 = st.columns(4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
 
454
- with col1:
455
- st.markdown('<div class="stats-card">', unsafe_allow_html=True)
456
- st.markdown(f'<div class="stats-value">{emp_max:.4f}</div>', unsafe_allow_html=True)
457
- st.markdown('<div class="stats-label">Empirical Maximum</div>', unsafe_allow_html=True)
458
- st.markdown('</div>', unsafe_allow_html=True)
459
 
460
- with col2:
461
- st.markdown('<div class="stats-card">', unsafe_allow_html=True)
462
- st.markdown(f'<div class="stats-value">{emp_min:.4f}</div>', unsafe_allow_html=True)
463
- st.markdown('<div class="stats-label">Empirical Minimum</div>', unsafe_allow_html=True)
464
- st.markdown('</div>', unsafe_allow_html=True)
465
 
466
- with col3:
467
- st.markdown('<div class="stats-card">', unsafe_allow_html=True)
468
- st.markdown(f'<div class="stats-value">{theo_max:.4f}</div>', unsafe_allow_html=True)
469
- st.markdown('<div class="stats-label">Theoretical Maximum</div>', unsafe_allow_html=True)
470
- st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
471
 
472
- with col4:
473
- st.markdown('<div class="stats-card">', unsafe_allow_html=True)
474
- st.markdown(f'<div class="stats-value">{theo_min:.4f}</div>', unsafe_allow_html=True)
475
- st.markdown('<div class="stats-label">Theoretical Minimum</div>', unsafe_allow_html=True)
476
- st.markdown('</div>', unsafe_allow_html=True)
 
 
 
477
 
478
- st.markdown("<br>", unsafe_allow_html=True)
 
 
 
 
 
 
 
479
 
480
- col1, col2 = st.columns(2)
481
- with col1:
482
- st.markdown('<div class="stats-card">', unsafe_allow_html=True)
483
- st.markdown(f'<div class="stats-value">{max_diff:.4f}</div>', unsafe_allow_html=True)
484
- st.markdown('<div class="stats-label">Max Difference</div>', unsafe_allow_html=True)
485
- st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486
 
487
- with col2:
488
- st.markdown('<div class="stats-card">', unsafe_allow_html=True)
489
- st.markdown(f'<div class="stats-value">{min_diff:.4f}</div>', unsafe_allow_html=True)
490
- st.markdown('<div class="stats-label">Min Difference</div>', unsafe_allow_html=True)
491
- st.markdown('</div>', unsafe_allow_html=True)
492
 
493
- # Add calculation settings
494
- with st.expander("Calculation Details"):
495
- st.markdown(f"""
496
- - **Matrix Dimensions**: {n} Γ— {p}
497
- - **Parameter a**: {a}
498
- - **Parameter y (p/n)**: {y:.4f}
499
- - **Beta points**: {fineness}
500
- - **Theoretical grid points**: {theory_grid_points}
501
- - **Theoretical tolerance**: {theory_tolerance:.1e}
502
- """)
503
-
504
- except Exception as e:
505
- st.error(f"An error occurred: {str(e)}")
506
-
507
- else:
508
- # Try to load existing data if available
509
- data_file = os.path.join(output_dir, "eigenvalue_data.json")
510
- if os.path.exists(data_file):
511
- try:
512
- with open(data_file, 'r') as f:
513
- data = json.load(f)
514
-
515
- # Extract data
516
- beta_values = np.array(data['beta_values'])
517
- max_eigenvalues = np.array(data['max_eigenvalues'])
518
- min_eigenvalues = np.array(data['min_eigenvalues'])
519
- theoretical_max = np.array(data['theoretical_max'])
520
- theoretical_min = np.array(data['theoretical_min'])
521
-
522
- # Create an interactive plot using Plotly
523
- fig = go.Figure()
524
-
525
- # Add traces for each line
526
- fig.add_trace(go.Scatter(
527
- x=beta_values,
528
- y=max_eigenvalues,
529
- mode='lines+markers',
530
- name='Empirical Max Eigenvalue',
531
- line=dict(color='rgb(220, 60, 60)', width=3),
532
- marker=dict(
533
- symbol='circle',
534
- size=8,
535
- color='rgb(220, 60, 60)',
536
- line=dict(color='white', width=1)
537
- ),
538
- hovertemplate='Ξ²: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Max</extra>'
539
- ))
540
-
541
- fig.add_trace(go.Scatter(
542
- x=beta_values,
543
- y=min_eigenvalues,
544
- mode='lines+markers',
545
- name='Empirical Min Eigenvalue',
546
- line=dict(color='rgb(60, 60, 220)', width=3),
547
- marker=dict(
548
- symbol='circle',
549
- size=8,
550
- color='rgb(60, 60, 220)',
551
- line=dict(color='white', width=1)
552
- ),
553
- hovertemplate='Ξ²: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Min</extra>'
554
- ))
555
-
556
- fig.add_trace(go.Scatter(
557
- x=beta_values,
558
- y=theoretical_max,
559
- mode='lines+markers',
560
- name='Theoretical Max Function',
561
- line=dict(color='rgb(30, 180, 30)', width=3),
562
- marker=dict(
563
- symbol='diamond',
564
- size=8,
565
- color='rgb(30, 180, 30)',
566
- line=dict(color='white', width=1)
567
- ),
568
- hovertemplate='Ξ²: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Max</extra>'
569
- ))
570
-
571
- fig.add_trace(go.Scatter(
572
- x=beta_values,
573
- y=theoretical_min,
574
- mode='lines+markers',
575
- name='Theoretical Min Function',
576
- line=dict(color='rgb(180, 30, 180)', width=3),
577
- marker=dict(
578
- symbol='diamond',
579
- size=8,
580
- color='rgb(180, 30, 180)',
581
- line=dict(color='white', width=1)
582
- ),
583
- hovertemplate='Ξ²: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Min</extra>'
584
- ))
585
-
586
- # Configure layout for better appearance
587
- fig.update_layout(
588
- title={
589
- 'text': f'Eigenvalue Analysis (Previous Result)',
590
- 'font': {'size': 24, 'color': '#1E88E5'},
591
- 'y': 0.95,
592
- 'x': 0.5,
593
- 'xanchor': 'center',
594
- 'yanchor': 'top'
595
- },
596
- xaxis={
597
- 'title': 'Ξ² Parameter',
598
- 'titlefont': {'size': 18, 'color': '#424242'},
599
- 'tickfont': {'size': 14},
600
- 'gridcolor': 'rgba(220, 220, 220, 0.5)',
601
- 'showgrid': True
602
- },
603
- yaxis={
604
- 'title': 'Eigenvalues',
605
- 'titlefont': {'size': 18, 'color': '#424242'},
606
- 'tickfont': {'size': 14},
607
- 'gridcolor': 'rgba(220, 220, 220, 0.5)',
608
- 'showgrid': True
609
- },
610
- plot_bgcolor='rgba(240, 240, 240, 0.8)',
611
- paper_bgcolor='rgba(249, 249, 249, 0.8)',
612
- hovermode='closest',
613
- legend={
614
- 'font': {'size': 14},
615
- 'bgcolor': 'rgba(255, 255, 255, 0.9)',
616
- 'bordercolor': 'rgba(200, 200, 200, 0.5)',
617
- 'borderwidth': 1
618
- },
619
- margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
620
- height=600
621
- )
622
-
623
- # Display the interactive plot in Streamlit
624
- st.plotly_chart(fig, use_container_width=True)
625
- st.info("This is the previous analysis result. Adjust parameters and click 'Generate Analysis' to create a new visualization.")
626
-
627
- except Exception as e:
628
- st.info("πŸ‘ˆ Set parameters and click 'Generate Analysis' to create a visualization.")
629
- else:
630
- # Show placeholder
631
- st.info("πŸ‘ˆ Set parameters and click 'Generate Analysis' to create a visualization.")
632
-
633
- st.markdown('</div>', unsafe_allow_html=True)
 
4
  import json
5
  import numpy as np
6
  import plotly.graph_objects as go
 
7
  from PIL import Image
8
  import time
9
  import io
10
 
11
  # Set page config with wider layout
12
  st.set_page_config(
13
+ page_title="Matrix Analysis Dashboard",
14
  page_icon="πŸ“Š",
15
  layout="wide",
16
  initial_sidebar_state="expanded"
 
42
  border-left: 4px solid #1E88E5;
43
  padding-left: 10px;
44
  }
45
+ .stTabs [data-baseweb="tab-list"] {
46
+ gap: 12px;
 
 
 
 
47
  }
48
+ .stTabs [data-baseweb="tab"] {
49
+ height: 50px;
50
+ white-space: pre-wrap;
51
+ background-color: #f0f0f0;
52
+ border-radius: 6px 6px 0 0;
53
+ gap: 1;
54
+ padding-top: 10px;
55
+ padding-bottom: 10px;
56
  }
57
+ .stTabs [aria-selected="true"] {
58
+ background-color: #1E88E5 !important;
59
+ color: white !important;
 
60
  }
61
  </style>
62
  """, unsafe_allow_html=True)
63
 
64
  # Dashboard Header
65
+ st.markdown('<h1 class="main-header">Matrix Analysis Dashboard</h1>', unsafe_allow_html=True)
66
 
67
  # Create output directory in the current working directory
68
  current_dir = os.getcwd()
 
73
  cpp_file = os.path.join(current_dir, "app.cpp")
74
  executable = os.path.join(current_dir, "eigen_analysis")
75
 
76
+ # Check if cpp file exists and compile if necessary
77
+ if not os.path.exists(cpp_file):
78
+ st.error(f"C++ source file not found at: {cpp_file}")
79
+ st.stop()
80
 
81
+ # Compile the C++ code with the right OpenCV libraries
82
+ if not os.path.exists(executable) or st.sidebar.button("Recompile C++ Code"):
83
+ with st.sidebar:
 
 
 
 
 
 
 
 
84
  with st.spinner("Compiling C++ code..."):
85
  compile_commands = [
86
  f"g++ -o {executable} {cpp_file} `pkg-config --cflags --libs opencv4` -std=c++11",
 
108
  # Make sure the executable is executable
109
  os.chmod(executable, 0o755)
110
  st.success("C++ code compiled successfully")
111
+
112
+ # Create tabs for different analyses
113
+ tab1, tab2 = st.tabs(["Eigenvalue Analysis", "Im(s) vs z Analysis"])
114
+
115
+ # Tab 1: Eigenvalue Analysis
116
+ with tab1:
117
+ # Two-column layout for the dashboard
118
+ left_column, right_column = st.columns([1, 3])
119
 
120
+ with left_column:
121
+ st.markdown('<div class="dashboard-container">', unsafe_allow_html=True)
122
+ st.markdown('<div class="panel-header">Eigenvalue Analysis Controls</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
+ # Parameter inputs with defaults and validation
125
+ st.markdown("### Matrix Parameters")
126
+ n = st.number_input("Sample size (n)", min_value=5, max_value=1000, value=100, step=5,
127
+ help="Number of samples", key="eig_n")
128
+ p = st.number_input("Dimension (p)", min_value=5, max_value=1000, value=50, step=5,
129
+ help="Dimensionality", key="eig_p")
130
+ a = st.number_input("Value for a", min_value=1.1, max_value=10.0, value=2.0, step=0.1,
131
+ help="Parameter a > 1", key="eig_a")
132
 
133
+ # Automatically calculate y = p/n (as requested)
134
+ y = p/n
135
+ st.info(f"Value for y = p/n: {y:.4f}")
136
 
137
+ st.markdown("### Calculation Controls")
138
+ fineness = st.slider(
139
+ "Beta points",
140
+ min_value=20,
141
+ max_value=500,
142
+ value=100,
143
+ step=10,
144
+ help="Number of points to calculate along the Ξ² axis (0 to 1)",
145
+ key="eig_fineness"
146
+ )
147
 
148
+ with st.expander("Advanced Settings"):
149
+ # Add controls for theoretical calculation precision
150
+ theory_grid_points = st.slider(
151
+ "Theoretical grid points",
152
+ min_value=100,
153
+ max_value=1000,
154
+ value=200,
155
+ step=50,
156
+ help="Number of points in initial grid search for theoretical calculations",
157
+ key="eig_grid_points"
158
+ )
159
+
160
+ theory_tolerance = st.number_input(
161
+ "Theoretical tolerance",
162
+ min_value=1e-12,
163
+ max_value=1e-6,
164
+ value=1e-10,
165
+ format="%.1e",
166
+ help="Convergence tolerance for golden section search",
167
+ key="eig_tolerance"
168
+ )
169
 
170
+ # Generate button
171
+ eig_generate_button = st.button("Generate Eigenvalue Analysis",
172
+ type="primary",
173
+ use_container_width=True,
174
+ key="eig_generate")
175
+ st.markdown('</div>', unsafe_allow_html=True)
176
+
177
+ with right_column:
178
+ # Main visualization area
179
+ st.markdown('<div class="dashboard-container">', unsafe_allow_html=True)
180
+ st.markdown('<div class="panel-header">Eigenvalue Analysis Results</div>', unsafe_allow_html=True)
181
 
182
+ # Container for the analysis results
183
+ eig_results_container = st.container()
184
 
185
+ # Process when generate button is clicked
186
+ if eig_generate_button:
187
+ with eig_results_container:
188
+ # Show progress
189
+ progress_container = st.container()
190
+ with progress_container:
191
+ progress_bar = st.progress(0)
192
+ status_text = st.empty()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
+ try:
195
+ # Run the C++ executable with the parameters in JSON output mode
196
+ data_file = os.path.join(output_dir, "eigenvalue_data.json")
197
+
198
+ # Delete previous output if exists
199
+ if os.path.exists(data_file):
200
+ os.remove(data_file)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
+ # Execute the C++ program
203
+ cmd = [
204
+ executable,
205
+ "eigenvalues",
206
+ str(n),
207
+ str(p),
208
+ str(a),
209
+ str(y),
210
+ str(fineness),
211
+ str(theory_grid_points),
212
+ str(theory_tolerance),
213
+ data_file
214
+ ]
215
+
216
+ process = subprocess.Popen(
217
+ cmd,
218
+ stdout=subprocess.PIPE,
219
+ stderr=subprocess.PIPE,
220
+ text=True
221
+ )
222
+
223
+ # Show output in a status area
224
+ status_text.text("Starting calculations...")
225
+
226
+ last_progress = 0
227
+ while process.poll() is None:
228
+ output = process.stdout.readline()
229
+ if output:
230
+ if output.startswith("PROGRESS:"):
231
+ try:
232
+ # Update progress bar
233
+ progress_value = float(output.split(":")[1].strip())
234
+ progress_bar.progress(progress_value)
235
+ last_progress = progress_value
236
+ status_text.text(f"Calculating... {int(progress_value * 100)}% complete")
237
+ except:
238
+ pass
239
+ else:
240
+ status_text.text(output.strip())
241
+ time.sleep(0.1)
242
+
243
+ return_code = process.poll()
244
+
245
+ if return_code != 0:
246
+ error = process.stderr.read()
247
+ st.error(f"Error executing the analysis: {error}")
248
+ else:
249
+ progress_bar.progress(1.0)
250
+ status_text.text("Calculations complete! Generating visualization...")
251
+
252
+ # Load the results from the JSON file
253
+ with open(data_file, 'r') as f:
254
+ data = json.load(f)
255
+
256
+ # Extract data
257
+ beta_values = np.array(data['beta_values'])
258
+ max_eigenvalues = np.array(data['max_eigenvalues'])
259
+ min_eigenvalues = np.array(data['min_eigenvalues'])
260
+ theoretical_max = np.array(data['theoretical_max'])
261
+ theoretical_min = np.array(data['theoretical_min'])
262
+
263
+ # Create an interactive plot using Plotly
264
+ fig = go.Figure()
265
+
266
+ # Add traces for each line
267
+ fig.add_trace(go.Scatter(
268
+ x=beta_values,
269
+ y=max_eigenvalues,
270
+ mode='lines+markers',
271
+ name='Empirical Max Eigenvalue',
272
+ line=dict(color='rgb(220, 60, 60)', width=3),
273
+ marker=dict(
274
+ symbol='circle',
275
+ size=8,
276
+ color='rgb(220, 60, 60)',
277
+ line=dict(color='white', width=1)
278
+ ),
279
+ hovertemplate='Ξ²: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Max</extra>'
280
+ ))
281
+
282
+ fig.add_trace(go.Scatter(
283
+ x=beta_values,
284
+ y=min_eigenvalues,
285
+ mode='lines+markers',
286
+ name='Empirical Min Eigenvalue',
287
+ line=dict(color='rgb(60, 60, 220)', width=3),
288
+ marker=dict(
289
+ symbol='circle',
290
+ size=8,
291
+ color='rgb(60, 60, 220)',
292
+ line=dict(color='white', width=1)
293
+ ),
294
+ hovertemplate='Ξ²: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Min</extra>'
295
+ ))
296
+
297
+ fig.add_trace(go.Scatter(
298
+ x=beta_values,
299
+ y=theoretical_max,
300
+ mode='lines+markers',
301
+ name='Theoretical Max Function',
302
+ line=dict(color='rgb(30, 180, 30)', width=3),
303
+ marker=dict(
304
+ symbol='diamond',
305
+ size=8,
306
+ color='rgb(30, 180, 30)',
307
+ line=dict(color='white', width=1)
308
+ ),
309
+ hovertemplate='Ξ²: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Max</extra>'
310
+ ))
311
+
312
+ fig.add_trace(go.Scatter(
313
+ x=beta_values,
314
+ y=theoretical_min,
315
+ mode='lines+markers',
316
+ name='Theoretical Min Function',
317
+ line=dict(color='rgb(180, 30, 180)', width=3),
318
+ marker=dict(
319
+ symbol='diamond',
320
+ size=8,
321
+ color='rgb(180, 30, 180)',
322
+ line=dict(color='white', width=1)
323
+ ),
324
+ hovertemplate='Ξ²: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Min</extra>'
325
+ ))
326
+
327
+ # Configure layout for better appearance
328
+ fig.update_layout(
329
+ title={
330
+ 'text': f'Eigenvalue Analysis: n={n}, p={p}, a={a}, y={y:.4f}',
331
+ 'font': {'size': 24, 'color': '#1E88E5'},
332
+ 'y': 0.95,
333
+ 'x': 0.5,
334
+ 'xanchor': 'center',
335
+ 'yanchor': 'top'
336
+ },
337
+ xaxis={
338
+ 'title': 'Ξ² Parameter',
339
+ 'titlefont': {'size': 18, 'color': '#424242'},
340
+ 'tickfont': {'size': 14},
341
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
342
+ 'showgrid': True
343
+ },
344
+ yaxis={
345
+ 'title': 'Eigenvalues',
346
+ 'titlefont': {'size': 18, 'color': '#424242'},
347
+ 'tickfont': {'size': 14},
348
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
349
+ 'showgrid': True
350
+ },
351
+ plot_bgcolor='rgba(240, 240, 240, 0.8)',
352
+ paper_bgcolor='rgba(249, 249, 249, 0.8)',
353
+ hovermode='closest',
354
+ legend={
355
+ 'font': {'size': 14},
356
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
357
+ 'bordercolor': 'rgba(200, 200, 200, 0.5)',
358
+ 'borderwidth': 1
359
+ },
360
+ margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
361
+ height=600,
362
+ annotations=[
363
+ {
364
+ 'text': f"Max Function: max{{k ∈ (0,∞)}} [yβ(a-1)k + (ak+1)((y-1)k-1)]/[(ak+1)(k²+k)]",
365
+ 'xref': 'paper', 'yref': 'paper',
366
+ 'x': 0.02, 'y': 0.02,
367
+ 'showarrow': False,
368
+ 'font': {'size': 12, 'color': 'rgb(30, 180, 30)'},
369
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
370
+ 'bordercolor': 'rgb(30, 180, 30)',
371
+ 'borderwidth': 1,
372
+ 'borderpad': 4
373
+ },
374
+ {
375
+ 'text': f"Min Function: min{{t ∈ (-1/a,0)}} [yβ(a-1)t + (at+1)((y-1)t-1)]/[(at+1)(t²+t)]",
376
+ 'xref': 'paper', 'yref': 'paper',
377
+ 'x': 0.55, 'y': 0.02,
378
+ 'showarrow': False,
379
+ 'font': {'size': 12, 'color': 'rgb(180, 30, 180)'},
380
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
381
+ 'bordercolor': 'rgb(180, 30, 180)',
382
+ 'borderwidth': 1,
383
+ 'borderpad': 4
384
+ }
385
+ ]
386
+ )
387
+
388
+ # Add custom modebar buttons
389
+ fig.update_layout(
390
+ modebar_add=[
391
+ 'drawline', 'drawopenpath', 'drawclosedpath',
392
+ 'drawcircle', 'drawrect', 'eraseshape'
393
+ ],
394
+ modebar_remove=['lasso2d', 'select2d'],
395
+ dragmode='zoom'
396
+ )
397
+
398
+ # Clear progress container
399
+ progress_container.empty()
400
+
401
+ # Display the interactive plot in Streamlit
402
+ st.plotly_chart(fig, use_container_width=True)
403
+
404
+ except Exception as e:
405
+ st.error(f"An error occurred: {str(e)}")
406
+
407
+ else:
408
+ # Try to load existing data if available
409
+ data_file = os.path.join(output_dir, "eigenvalue_data.json")
410
+ if os.path.exists(data_file):
411
+ try:
412
  with open(data_file, 'r') as f:
413
  data = json.load(f)
414
 
 
486
  # Configure layout for better appearance
487
  fig.update_layout(
488
  title={
489
+ 'text': f'Eigenvalue Analysis (Previous Result)',
490
  'font': {'size': 24, 'color': '#1E88E5'},
491
  'y': 0.95,
492
  'x': 0.5,
 
517
  'borderwidth': 1
518
  },
519
  margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
520
+ height=600
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
521
  )
522
 
 
 
 
 
 
 
 
 
 
 
 
 
 
523
  # Display the interactive plot in Streamlit
524
  st.plotly_chart(fig, use_container_width=True)
525
+ st.info("This is the previous analysis result. Adjust parameters and click 'Generate Analysis' to create a new visualization.")
526
+
527
+ except Exception as e:
528
+ st.info("πŸ‘ˆ Set parameters and click 'Generate Analysis' to create a visualization.")
529
+ else:
530
+ # Show placeholder
531
+ st.info("πŸ‘ˆ Set parameters and click 'Generate Eigenvalue Analysis' to create a visualization.")
532
+
533
+ st.markdown('</div>', unsafe_allow_html=True)
534
+
535
+ # Tab 2: Im(s) vs z Analysis
536
+ with tab2:
537
+ # Two-column layout for the dashboard
538
+ left_column, right_column = st.columns([1, 3])
539
+
540
+ with left_column:
541
+ st.markdown('<div class="dashboard-container">', unsafe_allow_html=True)
542
+ st.markdown('<div class="panel-header">Im(s) vs z Analysis Controls</div>', unsafe_allow_html=True)
543
+
544
+ # Parameter inputs with defaults and validation
545
+ st.markdown("### Cubic Equation Parameters")
546
+ cubic_a = st.number_input("Value for a", min_value=1.1, max_value=10.0, value=2.0, step=0.1,
547
+ help="Parameter a > 1", key="cubic_a")
548
+ cubic_y = st.number_input("Value for y", min_value=0.1, max_value=10.0, value=1.0, step=0.1,
549
+ help="Parameter y > 0", key="cubic_y")
550
+ cubic_beta = st.number_input("Value for Ξ²", min_value=0.0, max_value=1.0, value=0.5, step=0.05,
551
+ help="Value between 0 and 1", key="cubic_beta")
552
+
553
+ st.markdown("### Calculation Controls")
554
+ cubic_points = st.slider(
555
+ "Number of z points",
556
+ min_value=50,
557
+ max_value=1000,
558
+ value=300,
559
+ step=50,
560
+ help="Number of points to calculate along the z axis",
561
+ key="cubic_points"
562
+ )
563
+
564
+ cubic_range = st.slider(
565
+ "z range",
566
+ min_value=0.1,
567
+ max_value=20.0,
568
+ value=(0.01, 10.0),
569
+ step=0.1,
570
+ help="Range of z values to calculate",
571
+ key="cubic_range"
572
+ )
573
+
574
+ # Show cubic equation
575
+ st.markdown("### Cubic Equation")
576
+ st.latex(r"zas^3 + [z(a+1)+a(1-y)]\,s^2 + [z+(a+1)-y-y\beta (a-1)]\,s + 1 = 0")
577
+
578
+ # Generate button
579
+ cubic_generate_button = st.button("Generate Im(s) vs z Analysis",
580
+ type="primary",
581
+ use_container_width=True,
582
+ key="cubic_generate")
583
+ st.markdown('</div>', unsafe_allow_html=True)
584
+
585
+ with right_column:
586
+ # Main visualization area
587
+ st.markdown('<div class="dashboard-container">', unsafe_allow_html=True)
588
+ st.markdown('<div class="panel-header">Im(s) vs z Analysis Results</div>', unsafe_allow_html=True)
589
+
590
+ # Container for the analysis results
591
+ cubic_results_container = st.container()
592
+
593
+ # Process when generate button is clicked
594
+ if cubic_generate_button:
595
+ with cubic_results_container:
596
+ # Show progress
597
+ progress_container = st.container()
598
+ with progress_container:
599
+ status_text = st.empty()
600
+ status_text.text("Starting cubic equation calculations...")
601
+
602
+ try:
603
+ # Run the C++ executable with the parameters in JSON output mode
604
+ data_file = os.path.join(output_dir, "cubic_data.json")
605
 
606
+ # Delete previous output if exists
607
+ if os.path.exists(data_file):
608
+ os.remove(data_file)
609
 
610
+ # Execute the C++ program
611
+ cmd = [
612
+ executable,
613
+ "cubic",
614
+ str(cubic_a),
615
+ str(cubic_y),
616
+ str(cubic_beta),
617
+ str(cubic_points),
618
+ data_file
619
+ ]
 
620
 
621
+ status_text.text("Calculating Im(s) vs z values...")
 
622
 
623
+ process = subprocess.run(
624
+ cmd,
625
+ capture_output=True,
626
+ text=True
627
+ )
 
 
628
 
629
+ if process.returncode != 0:
630
+ st.error(f"Error executing the analysis: {process.stderr}")
631
+ else:
632
+ status_text.text("Calculations complete! Generating visualization...")
633
+
634
+ # Load the results from the JSON file
635
+ with open(data_file, 'r') as f:
636
+ data = json.load(f)
637
+
638
+ # Extract data
639
+ z_values = np.array(data['z_values'])
640
+ ims_values1 = np.array(data['ims_values1'])
641
+ ims_values2 = np.array(data['ims_values2'])
642
+ ims_values3 = np.array(data['ims_values3'])
643
+
644
+ # Create an interactive plot using Plotly
645
+ fig = go.Figure()
646
+
647
+ # Add traces for each root's imaginary part
648
+ fig.add_trace(go.Scatter(
649
+ x=z_values,
650
+ y=ims_values1,
651
+ mode='lines',
652
+ name='Im(s₁)',
653
+ line=dict(color='rgb(220, 60, 60)', width=3),
654
+ hovertemplate='z: %{x:.3f}<br>Im(s₁): %{y:.6f}<extra>Root 1</extra>'
655
+ ))
656
+
657
+ fig.add_trace(go.Scatter(
658
+ x=z_values,
659
+ y=ims_values2,
660
+ mode='lines',
661
+ name='Im(sβ‚‚)',
662
+ line=dict(color='rgb(60, 60, 220)', width=3),
663
+ hovertemplate='z: %{x:.3f}<br>Im(sβ‚‚): %{y:.6f}<extra>Root 2</extra>'
664
+ ))
665
+
666
+ fig.add_trace(go.Scatter(
667
+ x=z_values,
668
+ y=ims_values3,
669
+ mode='lines',
670
+ name='Im(s₃)',
671
+ line=dict(color='rgb(30, 180, 30)', width=3),
672
+ hovertemplate='z: %{x:.3f}<br>Im(s₃): %{y:.6f}<extra>Root 3</extra>'
673
+ ))
674
+
675
+ # Configure layout for better appearance
676
+ fig.update_layout(
677
+ title={
678
+ 'text': f'Im(s) vs z Analysis: a={cubic_a}, y={cubic_y}, Ξ²={cubic_beta}',
679
+ 'font': {'size': 24, 'color': '#1E88E5'},
680
+ 'y': 0.95,
681
+ 'x': 0.5,
682
+ 'xanchor': 'center',
683
+ 'yanchor': 'top'
684
+ },
685
+ xaxis={
686
+ 'title': 'z',
687
+ 'titlefont': {'size': 18, 'color': '#424242'},
688
+ 'tickfont': {'size': 14},
689
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
690
+ 'showgrid': True,
691
+ 'type': 'log', # Use logarithmic scale for better visualization
692
+ 'title': 'z (logarithmic scale)'
693
+ },
694
+ yaxis={
695
+ 'title': 'Im(s)',
696
+ 'titlefont': {'size': 18, 'color': '#424242'},
697
+ 'tickfont': {'size': 14},
698
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
699
+ 'showgrid': True
700
+ },
701
+ plot_bgcolor='rgba(240, 240, 240, 0.8)',
702
+ paper_bgcolor='rgba(249, 249, 249, 0.8)',
703
+ hovermode='closest',
704
+ legend={
705
+ 'font': {'size': 14},
706
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
707
+ 'bordercolor': 'rgba(200, 200, 200, 0.5)',
708
+ 'borderwidth': 1
709
+ },
710
+ margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
711
+ height=600,
712
+ annotations=[
713
+ {
714
+ 'text': f"Cubic Equation: {cubic_a}zsΒ³ + [{cubic_a+1}z+{cubic_a}(1-{cubic_y})]sΒ² + [z+{cubic_a+1}-{cubic_y}-{cubic_y*cubic_beta}({cubic_a-1})]s + 1 = 0",
715
+ 'xref': 'paper', 'yref': 'paper',
716
+ 'x': 0.5, 'y': 0.02,
717
+ 'showarrow': False,
718
+ 'font': {'size': 12, 'color': 'black'},
719
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
720
+ 'bordercolor': 'rgba(0, 0, 0, 0.5)',
721
+ 'borderwidth': 1,
722
+ 'borderpad': 4,
723
+ 'align': 'center'
724
+ }
725
+ ]
726
+ )
727
+
728
+ # Add custom modebar buttons
729
+ fig.update_layout(
730
+ modebar_add=[
731
+ 'drawline', 'drawopenpath', 'drawclosedpath',
732
+ 'drawcircle', 'drawrect', 'eraseshape'
733
+ ],
734
+ modebar_remove=['lasso2d', 'select2d'],
735
+ dragmode='zoom'
736
+ )
737
+
738
+ # Clear progress container
739
+ progress_container.empty()
740
+
741
+ # Display the interactive plot in Streamlit
742
+ st.plotly_chart(fig, use_container_width=True)
743
+
744
+ # Add explanation text
745
+ st.markdown("""
746
+ ### Explanation of the Analysis
747
+
748
+ This plot shows the imaginary parts of the three roots (s₁, sβ‚‚, s₃) of the cubic equation as a function of z.
749
+ The cubic equation being solved is:
750
+
751
+ ```
752
+ zasΒ³ + [z(a+1)+a(1-y)]sΒ² + [z+(a+1)-y-yΞ²(a-1)]s + 1 = 0
753
+ ```
754
+
755
+ Where a, y, and Ξ² are parameters you can adjust in the control panel. The imaginary parts of the roots represent
756
+ oscillatory behavior in the system.
757
+
758
+ - When Im(s) = 0, the root is purely real
759
+ - When Im(s) β‰  0, the root has an oscillatory component
760
+ """)
761
+
762
+ except Exception as e:
763
+ st.error(f"An error occurred: {str(e)}")
764
+
765
+ else:
766
+ # Try to load existing data if available
767
+ data_file = os.path.join(output_dir, "cubic_data.json")
768
+ if os.path.exists(data_file):
769
+ try:
770
+ with open(data_file, 'r') as f:
771
+ data = json.load(f)
772
 
773
+ # Extract data
774
+ z_values = np.array(data['z_values'])
775
+ ims_values1 = np.array(data['ims_values1'])
776
+ ims_values2 = np.array(data['ims_values2'])
777
+ ims_values3 = np.array(data['ims_values3'])
778
 
779
+ # Create an interactive plot using Plotly
780
+ fig = go.Figure()
 
 
 
781
 
782
+ # Add traces for each root's imaginary part
783
+ fig.add_trace(go.Scatter(
784
+ x=z_values,
785
+ y=ims_values1,
786
+ mode='lines',
787
+ name='Im(s₁)',
788
+ line=dict(color='rgb(220, 60, 60)', width=3),
789
+ hovertemplate='z: %{x:.3f}<br>Im(s₁): %{y:.6f}<extra>Root 1</extra>'
790
+ ))
791
 
792
+ fig.add_trace(go.Scatter(
793
+ x=z_values,
794
+ y=ims_values2,
795
+ mode='lines',
796
+ name='Im(sβ‚‚)',
797
+ line=dict(color='rgb(60, 60, 220)', width=3),
798
+ hovertemplate='z: %{x:.3f}<br>Im(sβ‚‚): %{y:.6f}<extra>Root 2</extra>'
799
+ ))
800
 
801
+ fig.add_trace(go.Scatter(
802
+ x=z_values,
803
+ y=ims_values3,
804
+ mode='lines',
805
+ name='Im(s₃)',
806
+ line=dict(color='rgb(30, 180, 30)', width=3),
807
+ hovertemplate='z: %{x:.3f}<br>Im(s₃): %{y:.6f}<extra>Root 3</extra>'
808
+ ))
809
 
810
+ # Configure layout for better appearance
811
+ fig.update_layout(
812
+ title={
813
+ 'text': f'Im(s) vs z Analysis (Previous Result)',
814
+ 'font': {'size': 24, 'color': '#1E88E5'},
815
+ 'y': 0.95,
816
+ 'x': 0.5,
817
+ 'xanchor': 'center',
818
+ 'yanchor': 'top'
819
+ },
820
+ xaxis={
821
+ 'title': 'z (logarithmic scale)',
822
+ 'titlefont': {'size': 18, 'color': '#424242'},
823
+ 'tickfont': {'size': 14},
824
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
825
+ 'showgrid': True,
826
+ 'type': 'log' # Use logarithmic scale for better visualization
827
+ },
828
+ yaxis={
829
+ 'title': 'Im(s)',
830
+ 'titlefont': {'size': 18, 'color': '#424242'},
831
+ 'tickfont': {'size': 14},
832
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
833
+ 'showgrid': True
834
+ },
835
+ plot_bgcolor='rgba(240, 240, 240, 0.8)',
836
+ paper_bgcolor='rgba(249, 249, 249, 0.8)',
837
+ hovermode='closest',
838
+ legend={
839
+ 'font': {'size': 14},
840
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
841
+ 'bordercolor': 'rgba(200, 200, 200, 0.5)',
842
+ 'borderwidth': 1
843
+ },
844
+ margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
845
+ height=600
846
+ )
847
 
848
+ # Display the interactive plot in Streamlit
849
+ st.plotly_chart(fig, use_container_width=True)
850
+ st.info("This is the previous analysis result. Adjust parameters and click 'Generate Analysis' to create a new visualization.")
 
 
851
 
852
+ except Exception as e:
853
+ st.info("πŸ‘ˆ Set parameters and click 'Generate Im(s) vs z Analysis' to create a visualization.")
854
+ else:
855
+ # Show placeholder
856
+ st.info("πŸ‘ˆ Set parameters and click 'Generate Im(s) vs z Analysis' to create a visualization.")
857
+
858
+ st.markdown('</div>', unsafe_allow_html=True)