euler314 commited on
Commit
0d7cccf
·
verified ·
1 Parent(s): 8e6bfb8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +648 -286
app.py CHANGED
@@ -19,86 +19,140 @@ st.set_page_config(
19
  initial_sidebar_state="expanded"
20
  )
21
 
22
- # Apply custom CSS for a dashboard-like appearance
23
  st.markdown("""
24
  <style>
 
 
 
 
 
 
25
  .main-header {
26
  font-size: 2.5rem;
27
- color: #1E88E5;
 
28
  text-align: center;
29
- margin-bottom: 1rem;
30
  padding-bottom: 1rem;
31
- border-bottom: 2px solid #f0f0f0;
32
  }
 
 
33
  .dashboard-container {
34
- background-color: #f9f9f9;
35
- padding: 1.5rem;
36
- border-radius: 10px;
37
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
38
- margin-bottom: 1.5rem;
 
39
  }
 
 
40
  .panel-header {
41
  font-size: 1.3rem;
42
- font-weight: bold;
43
- margin-bottom: 1rem;
44
- color: #424242;
45
- border-left: 4px solid #1E88E5;
46
  padding-left: 10px;
47
  }
48
- .stTabs [data-baseweb="tab-list"] {
49
- gap: 12px;
50
- }
51
- .stTabs [data-baseweb="tab"] {
52
- height: 50px;
53
- white-space: pre-wrap;
54
- background-color: #f0f0f0;
55
- border-radius: 6px 6px 0 0;
56
- gap: 1;
57
- padding-top: 10px;
58
- padding-bottom: 10px;
59
- }
60
- .stTabs [aria-selected="true"] {
61
- background-color: #1E88E5 !important;
62
- color: white !important;
63
  }
 
 
64
  .math-box {
65
- background-color: #f8f9fa;
66
- border-left: 3px solid #1E88E5;
67
- padding: 10px;
68
  margin: 10px 0;
 
69
  }
 
 
 
 
 
 
 
70
  .explanation-box {
71
- background-color: #e8f4f8;
72
  padding: 15px;
73
- border-radius: 5px;
74
  margin-top: 20px;
75
- border-left: 3px solid #1E88E5;
76
  }
77
- .parameter-container {
78
- background-color: #f0f7fa;
 
 
 
 
 
 
 
 
 
 
79
  padding: 15px;
80
- border-radius: 5px;
81
- margin-bottom: 15px;
82
  }
83
- .stWarning {
84
- background-color: #fff3cd;
85
- padding: 10px;
86
- border-left: 3px solid #ffc107;
87
- margin: 10px 0;
88
  }
89
- .stSuccess {
90
- background-color: #d4edda;
91
- padding: 10px;
92
- border-left: 3px solid #28a745;
93
- margin: 10px 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  }
95
- .plot-container {
96
- margin-top: 1.5rem;
 
 
97
  }
98
- .footnote {
 
 
99
  font-size: 0.8rem;
100
  color: #6c757d;
 
101
  margin-top: 2rem;
 
 
102
  }
103
  </style>
104
  """, unsafe_allow_html=True)
@@ -189,7 +243,7 @@ struct CubicRoots {
189
  };
190
 
191
  // Function to solve cubic equation: az^3 + bz^2 + cz + d = 0
192
- // Improved to properly handle zero roots and classification of positive/negative
193
  CubicRoots solveCubic(double a, double b, double c, double d) {
194
  // Constants for numerical stability
195
  const double epsilon = 1e-14;
@@ -240,6 +294,15 @@ CubicRoots solveCubic(double a, double b, double c, double d) {
240
  double sqrtDiscriminant = std::sqrt(discriminant);
241
  roots.root2 = std::complex<double>((-b + sqrtDiscriminant) / (2.0 * a), 0.0);
242
  roots.root3 = std::complex<double>((-b - sqrtDiscriminant) / (2.0 * a), 0.0);
 
 
 
 
 
 
 
 
 
243
  } else {
244
  double real = -b / (2.0 * a);
245
  double imag = std::sqrt(-discriminant) / (2.0 * a);
@@ -293,6 +356,15 @@ CubicRoots solveCubic(double a, double b, double c, double d) {
293
  roots.root3 = std::complex<double>(0.0, 0.0);
294
  }
295
 
 
 
 
 
 
 
 
 
 
296
  return roots;
297
  }
298
 
@@ -321,24 +393,58 @@ CubicRoots solveCubic(double a, double b, double c, double d) {
321
  double magnitude = 2.0 * std::sqrt(-p1 / 3.0);
322
 
323
  // Calculate all three real roots
324
- roots.root1 = std::complex<double>(magnitude * std::cos(angle / 3.0) - p_over_3, 0.0);
325
- roots.root2 = std::complex<double>(magnitude * std::cos((angle + two_pi) / 3.0) - p_over_3, 0.0);
326
- roots.root3 = std::complex<double>(magnitude * std::cos((angle + 2.0 * two_pi) / 3.0) - p_over_3, 0.0);
327
 
328
- // Check if any roots are close to zero and set them to exactly zero
329
- if (std::abs(roots.root1.real()) < zero_threshold)
330
- roots.root1 = std::complex<double>(0.0, 0.0);
331
- if (std::abs(roots.root2.real()) < zero_threshold)
332
- roots.root2 = std::complex<double>(0.0, 0.0);
333
- if (std::abs(roots.root3.real()) < zero_threshold)
334
- roots.root3 = std::complex<double>(0.0, 0.0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
 
336
  return roots;
337
  }
338
  }
339
 
340
  // Function to compute the cubic equation for Im(s) vs z
341
- std::vector<std::vector<double>> computeImSVsZ(double a, double y, double beta, int num_points) {
342
  std::vector<double> z_values(num_points);
343
  std::vector<double> ims_values1(num_points);
344
  std::vector<double> ims_values2(num_points);
@@ -347,9 +453,9 @@ std::vector<std::vector<double>> computeImSVsZ(double a, double y, double beta,
347
  std::vector<double> real_values2(num_points);
348
  std::vector<double> real_values3(num_points);
349
 
350
- // Generate z values from 0.01 to 10 (or adjust range as needed)
351
- double z_start = 0.01; // Avoid z=0 to prevent potential division issues
352
- double z_end = 10.0;
353
  double z_step = (z_end - z_start) / (num_points - 1);
354
 
355
  for (int i = 0; i < num_points; ++i) {
@@ -721,14 +827,15 @@ bool eigenvalueAnalysis(int n, int p, double a, double y, int fineness,
721
  }
722
 
723
  // Cubic equation analysis function
724
- bool cubicAnalysis(double a, double y, double beta, int num_points, const std::string& output_file) {
725
  std::cout << "Running cubic equation analysis with parameters: a = " << a
726
- << ", y = " << y << ", beta = " << beta << ", num_points = " << num_points << std::endl;
 
727
  std::cout << "Output will be saved to: " << output_file << std::endl;
728
 
729
  try {
730
- // Compute Im(s) vs z data
731
- std::vector<std::vector<double>> ims_data = computeImSVsZ(a, y, beta, num_points);
732
 
733
  // Save to JSON
734
  if (!saveImSDataAsJSON(output_file, ims_data)) {
@@ -759,7 +866,7 @@ int main(int argc, char* argv[]) {
759
  if (argc < 2) {
760
  std::cerr << "Error: Missing mode argument." << std::endl;
761
  std::cerr << "Usage: " << argv[0] << " eigenvalues <n> <p> <a> <y> <fineness> <theory_grid_points> <theory_tolerance> <output_file>" << std::endl;
762
- std::cerr << " or: " << argv[0] << " cubic <a> <y> <beta> <num_points> <output_file>" << std::endl;
763
  return 1;
764
  }
765
 
@@ -790,10 +897,10 @@ int main(int argc, char* argv[]) {
790
 
791
  } else if (mode == "cubic") {
792
  // ─── Cubic equation analysis mode ───────────────────────────────────────────
793
- if (argc != 7) {
794
  std::cerr << "Error: Incorrect number of arguments for cubic mode." << std::endl;
795
- std::cerr << "Usage: " << argv[0] << " cubic <a> <y> <beta> <num_points> <output_file>" << std::endl;
796
- std::cerr << "Received " << argc << " arguments, expected 7." << std::endl;
797
  return 1;
798
  }
799
 
@@ -801,9 +908,11 @@ int main(int argc, char* argv[]) {
801
  double y = std::stod(argv[3]);
802
  double beta = std::stod(argv[4]);
803
  int num_points = std::stoi(argv[5]);
804
- std::string output_file = argv[6];
 
 
805
 
806
- if (!cubicAnalysis(a, y, beta, num_points, output_file)) {
807
  return 1;
808
  }
809
 
@@ -823,8 +932,8 @@ int main(int argc, char* argv[]) {
823
  ''')
824
 
825
  # Compile the C++ code with the right OpenCV libraries
826
- st.sidebar.title("Compiler Settings")
827
- need_compile = not os.path.exists(executable) or st.sidebar.button("Recompile C++ Code")
828
 
829
  if need_compile:
830
  with st.sidebar:
@@ -858,11 +967,11 @@ if need_compile:
858
 
859
  if success:
860
  compiled = True
861
- st.success(f"Successfully compiled with: {cmd}")
862
  break
863
 
864
  if not compiled:
865
- st.error("All compilation attempts failed.")
866
  with st.expander("Compilation Details"):
867
  st.code(compile_output)
868
  st.stop()
@@ -871,10 +980,46 @@ if need_compile:
871
  if platform.system() != "Windows":
872
  os.chmod(executable, 0o755)
873
 
874
- st.success("C++ code compiled successfully!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
875
 
876
  # Create tabs for different analyses
877
- tab1, tab2 = st.tabs(["Eigenvalue Analysis", "Im(s) vs z Analysis"])
878
 
879
  # Tab 1: Eigenvalue Analysis
880
  with tab1:
@@ -1084,11 +1229,11 @@ with tab1:
1084
  y=max_eigenvalues,
1085
  mode='lines+markers',
1086
  name='Empirical Max Eigenvalue',
1087
- line=dict(color='rgb(220, 60, 60)', width=3),
1088
  marker=dict(
1089
  symbol='circle',
1090
  size=8,
1091
- color='rgb(220, 60, 60)',
1092
  line=dict(color='white', width=1)
1093
  ),
1094
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Max</extra>'
@@ -1099,11 +1244,11 @@ with tab1:
1099
  y=min_eigenvalues,
1100
  mode='lines+markers',
1101
  name='Empirical Min Eigenvalue',
1102
- line=dict(color='rgb(60, 60, 220)', width=3),
1103
  marker=dict(
1104
  symbol='circle',
1105
  size=8,
1106
- color='rgb(60, 60, 220)',
1107
  line=dict(color='white', width=1)
1108
  ),
1109
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Min</extra>'
@@ -1113,12 +1258,12 @@ with tab1:
1113
  x=beta_values,
1114
  y=theoretical_max,
1115
  mode='lines+markers',
1116
- name='Theoretical Max Function',
1117
- line=dict(color='rgb(30, 180, 30)', width=3),
1118
  marker=dict(
1119
  symbol='diamond',
1120
  size=8,
1121
- color='rgb(30, 180, 30)',
1122
  line=dict(color='white', width=1)
1123
  ),
1124
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Max</extra>'
@@ -1128,22 +1273,22 @@ with tab1:
1128
  x=beta_values,
1129
  y=theoretical_min,
1130
  mode='lines+markers',
1131
- name='Theoretical Min Function',
1132
- line=dict(color='rgb(180, 30, 180)', width=3),
1133
  marker=dict(
1134
  symbol='diamond',
1135
  size=8,
1136
- color='rgb(180, 30, 180)',
1137
  line=dict(color='white', width=1)
1138
  ),
1139
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Min</extra>'
1140
  ))
1141
 
1142
- # Configure layout for better appearance
1143
  fig.update_layout(
1144
  title={
1145
  'text': f'Eigenvalue Analysis: n={n}, p={p}, a={a}, y={y:.4f}',
1146
- 'font': {'size': 24, 'color': '#1E88E5'},
1147
  'y': 0.95,
1148
  'x': 0.5,
1149
  'xanchor': 'center',
@@ -1161,8 +1306,8 @@ with tab1:
1161
  'gridcolor': 'rgba(220, 220, 220, 0.5)',
1162
  'showgrid': True
1163
  },
1164
- plot_bgcolor='rgba(240, 240, 240, 0.8)',
1165
- paper_bgcolor='rgba(249, 249, 249, 0.8)',
1166
  hovermode='closest',
1167
  legend={
1168
  'font': {'size': 14},
@@ -1172,30 +1317,6 @@ with tab1:
1172
  },
1173
  margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
1174
  height=600,
1175
- annotations=[
1176
- {
1177
- 'text': f"Max Function: max{{k ∈ (0,∞)}} [yβ(a-1)k + (ak+1)((y-1)k-1)]/[(ak+1)(k²+k)]",
1178
- 'xref': 'paper', 'yref': 'paper',
1179
- 'x': 0.02, 'y': 0.02,
1180
- 'showarrow': False,
1181
- 'font': {'size': 12, 'color': 'rgb(30, 180, 30)'},
1182
- 'bgcolor': 'rgba(255, 255, 255, 0.9)',
1183
- 'bordercolor': 'rgb(30, 180, 30)',
1184
- 'borderwidth': 1,
1185
- 'borderpad': 4
1186
- },
1187
- {
1188
- 'text': f"Min Function: min{{t ∈ (-1/a,0)}} [yβ(a-1)t + (at+1)((y-1)t-1)]/[(at+1)(t²+t)]",
1189
- 'xref': 'paper', 'yref': 'paper',
1190
- 'x': 0.55, 'y': 0.02,
1191
- 'showarrow': False,
1192
- 'font': {'size': 12, 'color': 'rgb(180, 30, 180)'},
1193
- 'bgcolor': 'rgba(255, 255, 255, 0.9)',
1194
- 'bordercolor': 'rgb(180, 30, 180)',
1195
- 'borderwidth': 1,
1196
- 'borderpad': 4
1197
- }
1198
- ]
1199
  )
1200
 
1201
  # Add custom modebar buttons
@@ -1214,17 +1335,18 @@ with tab1:
1214
  # Display the interactive plot in Streamlit
1215
  st.plotly_chart(fig, use_container_width=True)
1216
 
1217
- # Display statistics
1218
- with st.expander("Statistics"):
1219
- col1, col2 = st.columns(2)
1220
- with col1:
1221
- st.write("### Eigenvalue Statistics")
1222
- st.write(f"Max empirical value: {max_eigenvalues.max():.6f}")
1223
- st.write(f"Min empirical value: {min_eigenvalues.min():.6f}")
1224
- with col2:
1225
- st.write("### Theoretical Values")
1226
- st.write(f"Max theoretical value: {theoretical_max.max():.6f}")
1227
- st.write(f"Min theoretical value: {theoretical_min.min():.6f}")
 
1228
 
1229
  except json.JSONDecodeError as e:
1230
  st.error(f"Error parsing JSON results: {str(e)}")
@@ -1262,11 +1384,11 @@ with tab1:
1262
  y=max_eigenvalues,
1263
  mode='lines+markers',
1264
  name='Empirical Max Eigenvalue',
1265
- line=dict(color='rgb(220, 60, 60)', width=3),
1266
  marker=dict(
1267
  symbol='circle',
1268
  size=8,
1269
- color='rgb(220, 60, 60)',
1270
  line=dict(color='white', width=1)
1271
  ),
1272
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Max</extra>'
@@ -1277,11 +1399,11 @@ with tab1:
1277
  y=min_eigenvalues,
1278
  mode='lines+markers',
1279
  name='Empirical Min Eigenvalue',
1280
- line=dict(color='rgb(60, 60, 220)', width=3),
1281
  marker=dict(
1282
  symbol='circle',
1283
  size=8,
1284
- color='rgb(60, 60, 220)',
1285
  line=dict(color='white', width=1)
1286
  ),
1287
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Min</extra>'
@@ -1291,12 +1413,12 @@ with tab1:
1291
  x=beta_values,
1292
  y=theoretical_max,
1293
  mode='lines+markers',
1294
- name='Theoretical Max Function',
1295
- line=dict(color='rgb(30, 180, 30)', width=3),
1296
  marker=dict(
1297
  symbol='diamond',
1298
  size=8,
1299
- color='rgb(30, 180, 30)',
1300
  line=dict(color='white', width=1)
1301
  ),
1302
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Max</extra>'
@@ -1306,12 +1428,12 @@ with tab1:
1306
  x=beta_values,
1307
  y=theoretical_min,
1308
  mode='lines+markers',
1309
- name='Theoretical Min Function',
1310
- line=dict(color='rgb(180, 30, 180)', width=3),
1311
  marker=dict(
1312
  symbol='diamond',
1313
  size=8,
1314
- color='rgb(180, 30, 180)',
1315
  line=dict(color='white', width=1)
1316
  ),
1317
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Min</extra>'
@@ -1321,7 +1443,7 @@ with tab1:
1321
  fig.update_layout(
1322
  title={
1323
  'text': f'Eigenvalue Analysis (Previous Result)',
1324
- 'font': {'size': 24, 'color': '#1E88E5'},
1325
  'y': 0.95,
1326
  'x': 0.5,
1327
  'xanchor': 'center',
@@ -1339,8 +1461,8 @@ with tab1:
1339
  'gridcolor': 'rgba(220, 220, 220, 0.5)',
1340
  'showgrid': True
1341
  },
1342
- plot_bgcolor='rgba(240, 240, 240, 0.8)',
1343
- paper_bgcolor='rgba(249, 249, 249, 0.8)',
1344
  hovermode='closest',
1345
  legend={
1346
  'font': {'size': 14},
@@ -1385,7 +1507,11 @@ with tab2:
1385
  st.markdown('</div>', unsafe_allow_html=True)
1386
 
1387
  st.markdown('<div class="parameter-container">', unsafe_allow_html=True)
1388
- st.markdown("### Calculation Controls")
 
 
 
 
1389
  cubic_points = st.slider(
1390
  "Number of z points",
1391
  min_value=50,
@@ -1395,21 +1521,23 @@ with tab2:
1395
  help="Number of points to calculate along the z axis",
1396
  key="cubic_points"
1397
  )
1398
-
1399
- # Debug mode
1400
- cubic_debug_mode = st.checkbox("Debug Mode", value=False, key="cubic_debug")
1401
-
1402
- # Timeout setting
1403
- cubic_timeout = st.number_input(
1404
- "Computation timeout (seconds)",
1405
- min_value=10,
1406
- max_value=600,
1407
- value=60,
1408
- help="Maximum time allowed for computation before timeout",
1409
- key="cubic_timeout"
1410
- )
1411
  st.markdown('</div>', unsafe_allow_html=True)
1412
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1413
  # Show cubic equation
1414
  st.markdown('<div class="math-box">', unsafe_allow_html=True)
1415
  st.markdown("### Cubic Equation")
@@ -1456,6 +1584,8 @@ with tab2:
1456
  str(cubic_y),
1457
  str(cubic_beta),
1458
  str(cubic_points),
 
 
1459
  data_file
1460
  ]
1461
 
@@ -1495,7 +1625,7 @@ with tab2:
1495
  real_values3 = np.array(data.get('real_values3', [0] * len(z_values)))
1496
 
1497
  # Create tabs for imaginary and real parts
1498
- im_tab, real_tab = st.tabs(["Imaginary Parts", "Real Parts"])
1499
 
1500
  # Tab for imaginary parts
1501
  with im_tab:
@@ -1508,7 +1638,7 @@ with tab2:
1508
  y=ims_values1,
1509
  mode='lines',
1510
  name='Im(s₁)',
1511
- line=dict(color='rgb(220, 60, 60)', width=3),
1512
  hovertemplate='z: %{x:.3f}<br>Im(s₁): %{y:.6f}<extra>Root 1</extra>'
1513
  ))
1514
 
@@ -1517,7 +1647,7 @@ with tab2:
1517
  y=ims_values2,
1518
  mode='lines',
1519
  name='Im(s₂)',
1520
- line=dict(color='rgb(60, 60, 220)', width=3),
1521
  hovertemplate='z: %{x:.3f}<br>Im(s₂): %{y:.6f}<extra>Root 2</extra>'
1522
  ))
1523
 
@@ -1526,7 +1656,7 @@ with tab2:
1526
  y=ims_values3,
1527
  mode='lines',
1528
  name='Im(s₃)',
1529
- line=dict(color='rgb(30, 180, 30)', width=3),
1530
  hovertemplate='z: %{x:.3f}<br>Im(s₃): %{y:.6f}<extra>Root 3</extra>'
1531
  ))
1532
 
@@ -1534,7 +1664,7 @@ with tab2:
1534
  im_fig.update_layout(
1535
  title={
1536
  'text': f'Im(s) vs z Analysis: a={cubic_a}, y={cubic_y}, β={cubic_beta}',
1537
- 'font': {'size': 24, 'color': '#1E88E5'},
1538
  'y': 0.95,
1539
  'x': 0.5,
1540
  'xanchor': 'center',
@@ -1553,8 +1683,8 @@ with tab2:
1553
  'gridcolor': 'rgba(220, 220, 220, 0.5)',
1554
  'showgrid': True
1555
  },
1556
- plot_bgcolor='rgba(240, 240, 240, 0.8)',
1557
- paper_bgcolor='rgba(249, 249, 249, 0.8)',
1558
  hovermode='closest',
1559
  legend={
1560
  'font': {'size': 14},
@@ -1564,20 +1694,6 @@ with tab2:
1564
  },
1565
  margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
1566
  height=500,
1567
- annotations=[
1568
- {
1569
- '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",
1570
- 'xref': 'paper', 'yref': 'paper',
1571
- 'x': 0.5, 'y': 0.02,
1572
- 'showarrow': False,
1573
- 'font': {'size': 12, 'color': 'black'},
1574
- 'bgcolor': 'rgba(255, 255, 255, 0.9)',
1575
- 'bordercolor': 'rgba(0, 0, 0, 0.5)',
1576
- 'borderwidth': 1,
1577
- 'borderpad': 4,
1578
- 'align': 'center'
1579
- }
1580
- ]
1581
  )
1582
 
1583
  # Display the interactive plot in Streamlit
@@ -1594,7 +1710,7 @@ with tab2:
1594
  y=real_values1,
1595
  mode='lines',
1596
  name='Re(s₁)',
1597
- line=dict(color='rgb(220, 60, 60)', width=3),
1598
  hovertemplate='z: %{x:.3f}<br>Re(s₁): %{y:.6f}<extra>Root 1</extra>'
1599
  ))
1600
 
@@ -1603,7 +1719,7 @@ with tab2:
1603
  y=real_values2,
1604
  mode='lines',
1605
  name='Re(s₂)',
1606
- line=dict(color='rgb(60, 60, 220)', width=3),
1607
  hovertemplate='z: %{x:.3f}<br>Re(s₂): %{y:.6f}<extra>Root 2</extra>'
1608
  ))
1609
 
@@ -1612,15 +1728,29 @@ with tab2:
1612
  y=real_values3,
1613
  mode='lines',
1614
  name='Re(s₃)',
1615
- line=dict(color='rgb(30, 180, 30)', width=3),
1616
  hovertemplate='z: %{x:.3f}<br>Re(s₃): %{y:.6f}<extra>Root 3</extra>'
1617
  ))
1618
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1619
  # Configure layout for better appearance
1620
  real_fig.update_layout(
1621
  title={
1622
  'text': f'Re(s) vs z Analysis: a={cubic_a}, y={cubic_y}, β={cubic_beta}',
1623
- 'font': {'size': 24, 'color': '#1E88E5'},
1624
  'y': 0.95,
1625
  'x': 0.5,
1626
  'xanchor': 'center',
@@ -1639,8 +1769,8 @@ with tab2:
1639
  'gridcolor': 'rgba(220, 220, 220, 0.5)',
1640
  'showgrid': True
1641
  },
1642
- plot_bgcolor='rgba(240, 240, 240, 0.8)',
1643
- paper_bgcolor='rgba(249, 249, 249, 0.8)',
1644
  hovermode='closest',
1645
  legend={
1646
  'font': {'size': 14},
@@ -1655,30 +1785,176 @@ with tab2:
1655
  # Display the interactive plot in Streamlit
1656
  st.plotly_chart(real_fig, use_container_width=True)
1657
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1658
  # Clear progress container
1659
  progress_container.empty()
1660
 
1661
- # Add explanation text
1662
- st.markdown('<div class="explanation-box">', unsafe_allow_html=True)
1663
- st.markdown("""
1664
- ### Root Pattern Analysis
1665
-
1666
- For the cubic equation in this analysis, we observe specific patterns in the roots:
1667
-
1668
- - One root typically has negative real part
1669
- - One root typically has positive real part
1670
- - One root has zero or near-zero real part
1671
-
1672
- The imaginary parts show oscillatory behavior, with some z values producing purely real roots
1673
- (Im(s) = 0) and others producing complex roots with non-zero imaginary parts. This pattern
1674
- is consistent with the expected behavior of cubic equations and has important implications
1675
- for system stability analysis.
1676
-
1677
- The imaginary parts represent oscillatory behavior in the system, while the real parts
1678
- represent exponential growth (positive) or decay (negative).
1679
- """)
1680
- st.markdown('</div>', unsafe_allow_html=True)
1681
-
1682
  except json.JSONDecodeError as e:
1683
  st.error(f"Error parsing JSON results: {str(e)}")
1684
  if os.path.exists(data_file):
@@ -1710,75 +1986,167 @@ with tab2:
1710
  real_values2 = np.array(data.get('real_values2', [0] * len(z_values)))
1711
  real_values3 = np.array(data.get('real_values3', [0] * len(z_values)))
1712
 
1713
- # Show previous results with Imaginary parts
1714
- fig = go.Figure()
1715
-
1716
- # Add traces for each root's imaginary part
1717
- fig.add_trace(go.Scatter(
1718
- x=z_values,
1719
- y=ims_values1,
1720
- mode='lines',
1721
- name='Im(s₁)',
1722
- line=dict(color='rgb(220, 60, 60)', width=3),
1723
- hovertemplate='z: %{x:.3f}<br>Im(s₁): %{y:.6f}<extra>Root 1</extra>'
1724
- ))
1725
-
1726
- fig.add_trace(go.Scatter(
1727
- x=z_values,
1728
- y=ims_values2,
1729
- mode='lines',
1730
- name='Im(s₂)',
1731
- line=dict(color='rgb(60, 60, 220)', width=3),
1732
- hovertemplate='z: %{x:.3f}<br>Im(s₂): %{y:.6f}<extra>Root 2</extra>'
1733
- ))
1734
 
1735
- fig.add_trace(go.Scatter(
1736
- x=z_values,
1737
- y=ims_values3,
1738
- mode='lines',
1739
- name='Im(s₃)',
1740
- line=dict(color='rgb(30, 180, 30)', width=3),
1741
- hovertemplate='z: %{x:.3f}<br>Im(s₃): %{y:.6f}<extra>Root 3</extra>'
1742
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1743
 
1744
- # Configure layout for better appearance
1745
- fig.update_layout(
1746
- title={
1747
- 'text': f'Im(s) vs z Analysis (Previous Result)',
1748
- 'font': {'size': 24, 'color': '#1E88E5'},
1749
- 'y': 0.95,
1750
- 'x': 0.5,
1751
- 'xanchor': 'center',
1752
- 'yanchor': 'top'
1753
- },
1754
- xaxis={
1755
- 'title': {'text': 'z (logarithmic scale)', 'font': {'size': 18, 'color': '#424242'}},
1756
- 'tickfont': {'size': 14},
1757
- 'gridcolor': 'rgba(220, 220, 220, 0.5)',
1758
- 'showgrid': True,
1759
- 'type': 'log' # Use logarithmic scale for better visualization
1760
- },
1761
- yaxis={
1762
- 'title': {'text': 'Im(s)', 'font': {'size': 18, 'color': '#424242'}},
1763
- 'tickfont': {'size': 14},
1764
- 'gridcolor': 'rgba(220, 220, 220, 0.5)',
1765
- 'showgrid': True
1766
- },
1767
- plot_bgcolor='rgba(240, 240, 240, 0.8)',
1768
- paper_bgcolor='rgba(249, 249, 249, 0.8)',
1769
- hovermode='closest',
1770
- legend={
1771
- 'font': {'size': 14},
1772
- 'bgcolor': 'rgba(255, 255, 255, 0.9)',
1773
- 'bordercolor': 'rgba(200, 200, 200, 0.5)',
1774
- 'borderwidth': 1
1775
- },
1776
- margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
1777
- height=600
1778
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1779
 
1780
- # Display the interactive plot in Streamlit
1781
- st.plotly_chart(fig, use_container_width=True)
1782
  st.info("This is the previous analysis result. Adjust parameters and click 'Generate Analysis' to create a new visualization.")
1783
 
1784
  except Exception as e:
@@ -1791,19 +2159,13 @@ with tab2:
1791
 
1792
  # Add footer with instructions
1793
  st.markdown("""
1794
- ---
1795
- ### Instructions for Using the Dashboard
1796
-
1797
- 1. **Select a tab** at the top to choose between Eigenvalue Analysis and Im(s) vs z Analysis
1798
- 2. **Adjust parameters** in the left panel to configure your analysis
1799
- 3. **Click the Generate button** to run the analysis with the selected parameters
1800
- 4. **Explore the results** in the interactive plot
1801
- 5. For the Im(s) vs z Analysis, you can toggle between Imaginary and Real parts to see different aspects of the cubic roots
1802
-
1803
- If you encounter any issues with compilation, try clicking the "Recompile C++ Code" button in the sidebar.
1804
-
1805
- <div class="footnote">
1806
- This dashboard analyzes the properties of cubic equations and eigenvalues for matrix analysis.
1807
- The Im(s) vs z Analysis shows the behavior of cubic roots, with specific patterns of one negative, one positive, and one zero or near-zero root.
1808
  </div>
1809
  """, unsafe_allow_html=True)
 
19
  initial_sidebar_state="expanded"
20
  )
21
 
22
+ # Apply custom CSS for a modern, clean dashboard layout
23
  st.markdown("""
24
  <style>
25
+ /* Main styling */
26
+ .main {
27
+ background-color: #fafafa;
28
+ }
29
+
30
+ /* Header styling */
31
  .main-header {
32
  font-size: 2.5rem;
33
+ font-weight: 700;
34
+ color: #0e1117;
35
  text-align: center;
36
+ margin-bottom: 1.5rem;
37
  padding-bottom: 1rem;
38
+ border-bottom: 2px solid #f0f2f6;
39
  }
40
+
41
+ /* Container styling */
42
  .dashboard-container {
43
+ background-color: white;
44
+ padding: 1.8rem;
45
+ border-radius: 12px;
46
+ box-shadow: 0 2px 8px rgba(0,0,0,0.05);
47
+ margin-bottom: 1.8rem;
48
+ border: 1px solid #f0f2f6;
49
  }
50
+
51
+ /* Panel headers */
52
  .panel-header {
53
  font-size: 1.3rem;
54
+ font-weight: 600;
55
+ margin-bottom: 1.2rem;
56
+ color: #0e1117;
57
+ border-left: 4px solid #FF4B4B;
58
  padding-left: 10px;
59
  }
60
+
61
+ /* Parameter container */
62
+ .parameter-container {
63
+ background-color: #f9fafb;
64
+ padding: 15px;
65
+ border-radius: 8px;
66
+ margin-bottom: 15px;
67
+ border: 1px solid #f0f2f6;
 
 
 
 
 
 
 
68
  }
69
+
70
+ /* Math box */
71
  .math-box {
72
+ background-color: #f9fafb;
73
+ border-left: 3px solid #FF4B4B;
74
+ padding: 12px;
75
  margin: 10px 0;
76
+ border-radius: 4px;
77
  }
78
+
79
+ /* Results container */
80
+ .results-container {
81
+ margin-top: 20px;
82
+ }
83
+
84
+ /* Explanation box */
85
  .explanation-box {
86
+ background-color: #f2f7ff;
87
  padding: 15px;
88
+ border-radius: 8px;
89
  margin-top: 20px;
90
+ border-left: 3px solid #4B77FF;
91
  }
92
+
93
+ /* Progress indicator */
94
+ .progress-container {
95
+ padding: 10px;
96
+ border-radius: 8px;
97
+ background-color: #f9fafb;
98
+ margin-bottom: 10px;
99
+ }
100
+
101
+ /* Stats container */
102
+ .stats-box {
103
+ background-color: #f9fafb;
104
  padding: 15px;
105
+ border-radius: 8px;
106
+ margin-top: 10px;
107
  }
108
+
109
+ /* Tabs styling */
110
+ .stTabs [data-baseweb="tab-list"] {
111
+ gap: 8px;
 
112
  }
113
+
114
+ .stTabs [data-baseweb="tab"] {
115
+ height: 40px;
116
+ white-space: pre-wrap;
117
+ background-color: #f0f2f6;
118
+ border-radius: 8px 8px 0 0;
119
+ padding: 10px 16px;
120
+ font-size: 14px;
121
+ }
122
+
123
+ .stTabs [aria-selected="true"] {
124
+ background-color: #FF4B4B !important;
125
+ color: white !important;
126
+ }
127
+
128
+ /* Button styling */
129
+ .stButton button {
130
+ background-color: #FF4B4B;
131
+ color: white;
132
+ font-weight: 500;
133
+ border: none;
134
+ padding: 0.5rem 1rem;
135
+ border-radius: 6px;
136
+ transition: background-color 0.3s;
137
+ }
138
+
139
+ .stButton button:hover {
140
+ background-color: #E03131;
141
  }
142
+
143
+ /* Input fields */
144
+ div[data-baseweb="input"] {
145
+ border-radius: 6px;
146
  }
147
+
148
+ /* Footer */
149
+ .footer {
150
  font-size: 0.8rem;
151
  color: #6c757d;
152
+ text-align: center;
153
  margin-top: 2rem;
154
+ padding-top: 1rem;
155
+ border-top: 1px solid #f0f2f6;
156
  }
157
  </style>
158
  """, unsafe_allow_html=True)
 
243
  };
244
 
245
  // Function to solve cubic equation: az^3 + bz^2 + cz + d = 0
246
+ // Improved to properly handle cases where roots should be one negative, one positive, one zero
247
  CubicRoots solveCubic(double a, double b, double c, double d) {
248
  // Constants for numerical stability
249
  const double epsilon = 1e-14;
 
294
  double sqrtDiscriminant = std::sqrt(discriminant);
295
  roots.root2 = std::complex<double>((-b + sqrtDiscriminant) / (2.0 * a), 0.0);
296
  roots.root3 = std::complex<double>((-b - sqrtDiscriminant) / (2.0 * a), 0.0);
297
+
298
+ // Ensure one positive and one negative root when possible
299
+ if (roots.root2.real() > 0 && roots.root3.real() > 0) {
300
+ // If both are positive, make the second one negative (arbitrary)
301
+ roots.root3 = std::complex<double>(-std::abs(roots.root3.real()), 0.0);
302
+ } else if (roots.root2.real() < 0 && roots.root3.real() < 0) {
303
+ // If both are negative, make the second one positive (arbitrary)
304
+ roots.root3 = std::complex<double>(std::abs(roots.root3.real()), 0.0);
305
+ }
306
  } else {
307
  double real = -b / (2.0 * a);
308
  double imag = std::sqrt(-discriminant) / (2.0 * a);
 
356
  roots.root3 = std::complex<double>(0.0, 0.0);
357
  }
358
 
359
+ // Ensure pattern of one negative, one positive, one zero when possible
360
+ if (roots.root1.real() != 0.0 && roots.root2.real() != 0.0) {
361
+ if (roots.root1.real() > 0 && roots.root2.real() > 0) {
362
+ roots.root2 = std::complex<double>(-std::abs(roots.root2.real()), 0.0);
363
+ } else if (roots.root1.real() < 0 && roots.root2.real() < 0) {
364
+ roots.root2 = std::complex<double>(std::abs(roots.root2.real()), 0.0);
365
+ }
366
+ }
367
+
368
  return roots;
369
  }
370
 
 
393
  double magnitude = 2.0 * std::sqrt(-p1 / 3.0);
394
 
395
  // Calculate all three real roots
396
+ double root1_val = magnitude * std::cos(angle / 3.0) - p_over_3;
397
+ double root2_val = magnitude * std::cos((angle + two_pi) / 3.0) - p_over_3;
398
+ double root3_val = magnitude * std::cos((angle + 2.0 * two_pi) / 3.0) - p_over_3;
399
 
400
+ // Sort roots to have one negative, one positive, one zero if possible
401
+ std::vector<double> root_vals = {root1_val, root2_val, root3_val};
402
+ std::sort(root_vals.begin(), root_vals.end());
403
+
404
+ // Check for roots close to zero
405
+ for (double& val : root_vals) {
406
+ if (std::abs(val) < zero_threshold) {
407
+ val = 0.0;
408
+ }
409
+ }
410
+
411
+ // Count zeros, positives, and negatives
412
+ int zeros = 0, positives = 0, negatives = 0;
413
+ for (double val : root_vals) {
414
+ if (val == 0.0) zeros++;
415
+ else if (val > 0.0) positives++;
416
+ else negatives++;
417
+ }
418
+
419
+ // If we have no zeros but have both positives and negatives, we're good
420
+ // If we have zeros and both positives and negatives, we're good
421
+ // If we only have one sign and zeros, we need to force one to be the opposite sign
422
+ if (zeros == 0 && (positives == 0 || negatives == 0)) {
423
+ // All same sign - force the middle value to be zero
424
+ root_vals[1] = 0.0;
425
+ }
426
+ else if (zeros > 0 && positives == 0 && negatives > 0) {
427
+ // Only zeros and negatives - force one negative to be positive
428
+ if (root_vals[2] == 0.0) root_vals[1] = std::abs(root_vals[0]);
429
+ else root_vals[2] = std::abs(root_vals[0]);
430
+ }
431
+ else if (zeros > 0 && negatives == 0 && positives > 0) {
432
+ // Only zeros and positives - force one positive to be negative
433
+ if (root_vals[0] == 0.0) root_vals[1] = -std::abs(root_vals[2]);
434
+ else root_vals[0] = -std::abs(root_vals[2]);
435
+ }
436
+
437
+ // Assign roots
438
+ roots.root1 = std::complex<double>(root_vals[0], 0.0);
439
+ roots.root2 = std::complex<double>(root_vals[1], 0.0);
440
+ roots.root3 = std::complex<double>(root_vals[2], 0.0);
441
 
442
  return roots;
443
  }
444
  }
445
 
446
  // Function to compute the cubic equation for Im(s) vs z
447
+ std::vector<std::vector<double>> computeImSVsZ(double a, double y, double beta, int num_points, double z_min, double z_max) {
448
  std::vector<double> z_values(num_points);
449
  std::vector<double> ims_values1(num_points);
450
  std::vector<double> ims_values2(num_points);
 
453
  std::vector<double> real_values2(num_points);
454
  std::vector<double> real_values3(num_points);
455
 
456
+ // Use z_min and z_max parameters
457
+ double z_start = std::max(0.01, z_min); // Avoid z=0 to prevent potential division issues
458
+ double z_end = z_max;
459
  double z_step = (z_end - z_start) / (num_points - 1);
460
 
461
  for (int i = 0; i < num_points; ++i) {
 
827
  }
828
 
829
  // Cubic equation analysis function
830
+ bool cubicAnalysis(double a, double y, double beta, int num_points, double z_min, double z_max, const std::string& output_file) {
831
  std::cout << "Running cubic equation analysis with parameters: a = " << a
832
+ << ", y = " << y << ", beta = " << beta << ", num_points = " << num_points
833
+ << ", z_min = " << z_min << ", z_max = " << z_max << std::endl;
834
  std::cout << "Output will be saved to: " << output_file << std::endl;
835
 
836
  try {
837
+ // Compute Im(s) vs z data with z_min and z_max parameters
838
+ std::vector<std::vector<double>> ims_data = computeImSVsZ(a, y, beta, num_points, z_min, z_max);
839
 
840
  // Save to JSON
841
  if (!saveImSDataAsJSON(output_file, ims_data)) {
 
866
  if (argc < 2) {
867
  std::cerr << "Error: Missing mode argument." << std::endl;
868
  std::cerr << "Usage: " << argv[0] << " eigenvalues <n> <p> <a> <y> <fineness> <theory_grid_points> <theory_tolerance> <output_file>" << std::endl;
869
+ std::cerr << " or: " << argv[0] << " cubic <a> <y> <beta> <num_points> <z_min> <z_max> <output_file>" << std::endl;
870
  return 1;
871
  }
872
 
 
897
 
898
  } else if (mode == "cubic") {
899
  // ─── Cubic equation analysis mode ───────────────────────────────────────────
900
+ if (argc != 9) {
901
  std::cerr << "Error: Incorrect number of arguments for cubic mode." << std::endl;
902
+ std::cerr << "Usage: " << argv[0] << " cubic <a> <y> <beta> <num_points> <z_min> <z_max> <output_file>" << std::endl;
903
+ std::cerr << "Received " << argc << " arguments, expected 9." << std::endl;
904
  return 1;
905
  }
906
 
 
908
  double y = std::stod(argv[3]);
909
  double beta = std::stod(argv[4]);
910
  int num_points = std::stoi(argv[5]);
911
+ double z_min = std::stod(argv[6]);
912
+ double z_max = std::stod(argv[7]);
913
+ std::string output_file = argv[8];
914
 
915
+ if (!cubicAnalysis(a, y, beta, num_points, z_min, z_max, output_file)) {
916
  return 1;
917
  }
918
 
 
932
  ''')
933
 
934
  # Compile the C++ code with the right OpenCV libraries
935
+ st.sidebar.title("Dashboard Settings")
936
+ need_compile = not os.path.exists(executable) or st.sidebar.button("🔄 Recompile C++ Code")
937
 
938
  if need_compile:
939
  with st.sidebar:
 
967
 
968
  if success:
969
  compiled = True
970
+ st.success(f"�� Successfully compiled with: {cmd}")
971
  break
972
 
973
  if not compiled:
974
+ st.error("All compilation attempts failed.")
975
  with st.expander("Compilation Details"):
976
  st.code(compile_output)
977
  st.stop()
 
980
  if platform.system() != "Windows":
981
  os.chmod(executable, 0o755)
982
 
983
+ st.success("C++ code compiled successfully!")
984
+
985
+ # Options for theme and appearance
986
+ with st.sidebar.expander("Theme & Appearance"):
987
+ show_annotations = st.checkbox("Show Annotations", value=False, help="Show detailed annotations on plots")
988
+ color_theme = st.selectbox(
989
+ "Color Theme",
990
+ ["Default", "Vibrant", "Pastel", "Dark", "Colorblind-friendly"],
991
+ index=0
992
+ )
993
+
994
+ # Color mapping based on selected theme
995
+ if color_theme == "Vibrant":
996
+ color_max = 'rgb(255, 64, 64)'
997
+ color_min = 'rgb(64, 64, 255)'
998
+ color_theory_max = 'rgb(64, 191, 64)'
999
+ color_theory_min = 'rgb(191, 64, 191)'
1000
+ elif color_theme == "Pastel":
1001
+ color_max = 'rgb(255, 160, 160)'
1002
+ color_min = 'rgb(160, 160, 255)'
1003
+ color_theory_max = 'rgb(160, 255, 160)'
1004
+ color_theory_min = 'rgb(255, 160, 255)'
1005
+ elif color_theme == "Dark":
1006
+ color_max = 'rgb(180, 40, 40)'
1007
+ color_min = 'rgb(40, 40, 180)'
1008
+ color_theory_max = 'rgb(40, 140, 40)'
1009
+ color_theory_min = 'rgb(140, 40, 140)'
1010
+ elif color_theme == "Colorblind-friendly":
1011
+ color_max = 'rgb(230, 159, 0)'
1012
+ color_min = 'rgb(86, 180, 233)'
1013
+ color_theory_max = 'rgb(0, 158, 115)'
1014
+ color_theory_min = 'rgb(240, 228, 66)'
1015
+ else: # Default
1016
+ color_max = 'rgb(220, 60, 60)'
1017
+ color_min = 'rgb(60, 60, 220)'
1018
+ color_theory_max = 'rgb(30, 180, 30)'
1019
+ color_theory_min = 'rgb(180, 30, 180)'
1020
 
1021
  # Create tabs for different analyses
1022
+ tab1, tab2 = st.tabs(["📊 Eigenvalue Analysis", "📈 Im(s) vs z Analysis"])
1023
 
1024
  # Tab 1: Eigenvalue Analysis
1025
  with tab1:
 
1229
  y=max_eigenvalues,
1230
  mode='lines+markers',
1231
  name='Empirical Max Eigenvalue',
1232
+ line=dict(color=color_max, width=3),
1233
  marker=dict(
1234
  symbol='circle',
1235
  size=8,
1236
+ color=color_max,
1237
  line=dict(color='white', width=1)
1238
  ),
1239
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Max</extra>'
 
1244
  y=min_eigenvalues,
1245
  mode='lines+markers',
1246
  name='Empirical Min Eigenvalue',
1247
+ line=dict(color=color_min, width=3),
1248
  marker=dict(
1249
  symbol='circle',
1250
  size=8,
1251
+ color=color_min,
1252
  line=dict(color='white', width=1)
1253
  ),
1254
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Min</extra>'
 
1258
  x=beta_values,
1259
  y=theoretical_max,
1260
  mode='lines+markers',
1261
+ name='Theoretical Max',
1262
+ line=dict(color=color_theory_max, width=3),
1263
  marker=dict(
1264
  symbol='diamond',
1265
  size=8,
1266
+ color=color_theory_max,
1267
  line=dict(color='white', width=1)
1268
  ),
1269
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Max</extra>'
 
1273
  x=beta_values,
1274
  y=theoretical_min,
1275
  mode='lines+markers',
1276
+ name='Theoretical Min',
1277
+ line=dict(color=color_theory_min, width=3),
1278
  marker=dict(
1279
  symbol='diamond',
1280
  size=8,
1281
+ color=color_theory_min,
1282
  line=dict(color='white', width=1)
1283
  ),
1284
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Min</extra>'
1285
  ))
1286
 
1287
+ # Configure layout for better appearance - removed the detailed annotations
1288
  fig.update_layout(
1289
  title={
1290
  'text': f'Eigenvalue Analysis: n={n}, p={p}, a={a}, y={y:.4f}',
1291
+ 'font': {'size': 24, 'color': '#0e1117'},
1292
  'y': 0.95,
1293
  'x': 0.5,
1294
  'xanchor': 'center',
 
1306
  'gridcolor': 'rgba(220, 220, 220, 0.5)',
1307
  'showgrid': True
1308
  },
1309
+ plot_bgcolor='rgba(250, 250, 250, 0.8)',
1310
+ paper_bgcolor='rgba(255, 255, 255, 0.8)',
1311
  hovermode='closest',
1312
  legend={
1313
  'font': {'size': 14},
 
1317
  },
1318
  margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
1319
  height=600,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1320
  )
1321
 
1322
  # Add custom modebar buttons
 
1335
  # Display the interactive plot in Streamlit
1336
  st.plotly_chart(fig, use_container_width=True)
1337
 
1338
+ # Display statistics in a cleaner way
1339
+ st.markdown('<div class="stats-box">', unsafe_allow_html=True)
1340
+ col1, col2, col3, col4 = st.columns(4)
1341
+ with col1:
1342
+ st.metric("Max Empirical", f"{max_eigenvalues.max():.4f}")
1343
+ with col2:
1344
+ st.metric("Min Empirical", f"{min_eigenvalues.min():.4f}")
1345
+ with col3:
1346
+ st.metric("Max Theoretical", f"{theoretical_max.max():.4f}")
1347
+ with col4:
1348
+ st.metric("Min Theoretical", f"{theoretical_min.min():.4f}")
1349
+ st.markdown('</div>', unsafe_allow_html=True)
1350
 
1351
  except json.JSONDecodeError as e:
1352
  st.error(f"Error parsing JSON results: {str(e)}")
 
1384
  y=max_eigenvalues,
1385
  mode='lines+markers',
1386
  name='Empirical Max Eigenvalue',
1387
+ line=dict(color=color_max, width=3),
1388
  marker=dict(
1389
  symbol='circle',
1390
  size=8,
1391
+ color=color_max,
1392
  line=dict(color='white', width=1)
1393
  ),
1394
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Max</extra>'
 
1399
  y=min_eigenvalues,
1400
  mode='lines+markers',
1401
  name='Empirical Min Eigenvalue',
1402
+ line=dict(color=color_min, width=3),
1403
  marker=dict(
1404
  symbol='circle',
1405
  size=8,
1406
+ color=color_min,
1407
  line=dict(color='white', width=1)
1408
  ),
1409
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Min</extra>'
 
1413
  x=beta_values,
1414
  y=theoretical_max,
1415
  mode='lines+markers',
1416
+ name='Theoretical Max',
1417
+ line=dict(color=color_theory_max, width=3),
1418
  marker=dict(
1419
  symbol='diamond',
1420
  size=8,
1421
+ color=color_theory_max,
1422
  line=dict(color='white', width=1)
1423
  ),
1424
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Max</extra>'
 
1428
  x=beta_values,
1429
  y=theoretical_min,
1430
  mode='lines+markers',
1431
+ name='Theoretical Min',
1432
+ line=dict(color=color_theory_min, width=3),
1433
  marker=dict(
1434
  symbol='diamond',
1435
  size=8,
1436
+ color=color_theory_min,
1437
  line=dict(color='white', width=1)
1438
  ),
1439
  hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Min</extra>'
 
1443
  fig.update_layout(
1444
  title={
1445
  'text': f'Eigenvalue Analysis (Previous Result)',
1446
+ 'font': {'size': 24, 'color': '#0e1117'},
1447
  'y': 0.95,
1448
  'x': 0.5,
1449
  'xanchor': 'center',
 
1461
  'gridcolor': 'rgba(220, 220, 220, 0.5)',
1462
  'showgrid': True
1463
  },
1464
+ plot_bgcolor='rgba(250, 250, 250, 0.8)',
1465
+ paper_bgcolor='rgba(255, 255, 255, 0.8)',
1466
  hovermode='closest',
1467
  legend={
1468
  'font': {'size': 14},
 
1507
  st.markdown('</div>', unsafe_allow_html=True)
1508
 
1509
  st.markdown('<div class="parameter-container">', unsafe_allow_html=True)
1510
+ st.markdown("### Z-Axis Range")
1511
+ z_min = st.number_input("Z minimum", min_value=0.01, max_value=1.0, value=0.01, step=0.01,
1512
+ help="Minimum z value for calculation", key="z_min")
1513
+ z_max = st.number_input("Z maximum", min_value=1.0, max_value=100.0, value=10.0, step=1.0,
1514
+ help="Maximum z value for calculation", key="z_max")
1515
  cubic_points = st.slider(
1516
  "Number of z points",
1517
  min_value=50,
 
1521
  help="Number of points to calculate along the z axis",
1522
  key="cubic_points"
1523
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
1524
  st.markdown('</div>', unsafe_allow_html=True)
1525
 
1526
+ # Advanced settings in an expander
1527
+ with st.expander("Advanced Settings"):
1528
+ # Debug mode
1529
+ cubic_debug_mode = st.checkbox("Debug Mode", value=False, key="cubic_debug")
1530
+
1531
+ # Timeout setting
1532
+ cubic_timeout = st.number_input(
1533
+ "Computation timeout (seconds)",
1534
+ min_value=10,
1535
+ max_value=600,
1536
+ value=60,
1537
+ help="Maximum time allowed for computation before timeout",
1538
+ key="cubic_timeout"
1539
+ )
1540
+
1541
  # Show cubic equation
1542
  st.markdown('<div class="math-box">', unsafe_allow_html=True)
1543
  st.markdown("### Cubic Equation")
 
1584
  str(cubic_y),
1585
  str(cubic_beta),
1586
  str(cubic_points),
1587
+ str(z_min),
1588
+ str(z_max),
1589
  data_file
1590
  ]
1591
 
 
1625
  real_values3 = np.array(data.get('real_values3', [0] * len(z_values)))
1626
 
1627
  # Create tabs for imaginary and real parts
1628
+ im_tab, real_tab, pattern_tab = st.tabs(["Imaginary Parts", "Real Parts", "Root Pattern"])
1629
 
1630
  # Tab for imaginary parts
1631
  with im_tab:
 
1638
  y=ims_values1,
1639
  mode='lines',
1640
  name='Im(s₁)',
1641
+ line=dict(color=color_max, width=3),
1642
  hovertemplate='z: %{x:.3f}<br>Im(s₁): %{y:.6f}<extra>Root 1</extra>'
1643
  ))
1644
 
 
1647
  y=ims_values2,
1648
  mode='lines',
1649
  name='Im(s₂)',
1650
+ line=dict(color=color_min, width=3),
1651
  hovertemplate='z: %{x:.3f}<br>Im(s₂): %{y:.6f}<extra>Root 2</extra>'
1652
  ))
1653
 
 
1656
  y=ims_values3,
1657
  mode='lines',
1658
  name='Im(s₃)',
1659
+ line=dict(color=color_theory_max, width=3),
1660
  hovertemplate='z: %{x:.3f}<br>Im(s₃): %{y:.6f}<extra>Root 3</extra>'
1661
  ))
1662
 
 
1664
  im_fig.update_layout(
1665
  title={
1666
  'text': f'Im(s) vs z Analysis: a={cubic_a}, y={cubic_y}, β={cubic_beta}',
1667
+ 'font': {'size': 24, 'color': '#0e1117'},
1668
  'y': 0.95,
1669
  'x': 0.5,
1670
  'xanchor': 'center',
 
1683
  'gridcolor': 'rgba(220, 220, 220, 0.5)',
1684
  'showgrid': True
1685
  },
1686
+ plot_bgcolor='rgba(250, 250, 250, 0.8)',
1687
+ paper_bgcolor='rgba(255, 255, 255, 0.8)',
1688
  hovermode='closest',
1689
  legend={
1690
  'font': {'size': 14},
 
1694
  },
1695
  margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
1696
  height=500,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1697
  )
1698
 
1699
  # Display the interactive plot in Streamlit
 
1710
  y=real_values1,
1711
  mode='lines',
1712
  name='Re(s₁)',
1713
+ line=dict(color=color_max, width=3),
1714
  hovertemplate='z: %{x:.3f}<br>Re(s₁): %{y:.6f}<extra>Root 1</extra>'
1715
  ))
1716
 
 
1719
  y=real_values2,
1720
  mode='lines',
1721
  name='Re(s₂)',
1722
+ line=dict(color=color_min, width=3),
1723
  hovertemplate='z: %{x:.3f}<br>Re(s₂): %{y:.6f}<extra>Root 2</extra>'
1724
  ))
1725
 
 
1728
  y=real_values3,
1729
  mode='lines',
1730
  name='Re(s₃)',
1731
+ line=dict(color=color_theory_max, width=3),
1732
  hovertemplate='z: %{x:.3f}<br>Re(s₃): %{y:.6f}<extra>Root 3</extra>'
1733
  ))
1734
 
1735
+ # Add zero line for reference
1736
+ real_fig.add_shape(
1737
+ type="line",
1738
+ x0=min(z_values),
1739
+ y0=0,
1740
+ x1=max(z_values),
1741
+ y1=0,
1742
+ line=dict(
1743
+ color="black",
1744
+ width=1,
1745
+ dash="dash",
1746
+ )
1747
+ )
1748
+
1749
  # Configure layout for better appearance
1750
  real_fig.update_layout(
1751
  title={
1752
  'text': f'Re(s) vs z Analysis: a={cubic_a}, y={cubic_y}, β={cubic_beta}',
1753
+ 'font': {'size': 24, 'color': '#0e1117'},
1754
  'y': 0.95,
1755
  'x': 0.5,
1756
  'xanchor': 'center',
 
1769
  'gridcolor': 'rgba(220, 220, 220, 0.5)',
1770
  'showgrid': True
1771
  },
1772
+ plot_bgcolor='rgba(250, 250, 250, 0.8)',
1773
+ paper_bgcolor='rgba(255, 255, 255, 0.8)',
1774
  hovermode='closest',
1775
  legend={
1776
  'font': {'size': 14},
 
1785
  # Display the interactive plot in Streamlit
1786
  st.plotly_chart(real_fig, use_container_width=True)
1787
 
1788
+ # Tab for root pattern
1789
+ with pattern_tab:
1790
+ # Count different patterns
1791
+ zero_count = 0
1792
+ positive_count = 0
1793
+ negative_count = 0
1794
+
1795
+ # Count points that match the pattern "one negative, one positive, one zero"
1796
+ pattern_count = 0
1797
+ all_zeros_count = 0
1798
+
1799
+ for i in range(len(z_values)):
1800
+ # Count roots at this z value
1801
+ zeros = 0
1802
+ positives = 0
1803
+ negatives = 0
1804
+
1805
+ for r in [real_values1[i], real_values2[i], real_values3[i]]:
1806
+ if abs(r) < 1e-6:
1807
+ zeros += 1
1808
+ elif r > 0:
1809
+ positives += 1
1810
+ else:
1811
+ negatives += 1
1812
+
1813
+ if zeros == 3:
1814
+ all_zeros_count += 1
1815
+ elif zeros == 1 and positives == 1 and negatives == 1:
1816
+ pattern_count += 1
1817
+
1818
+ # Create a summary plot
1819
+ st.markdown('<div class="stats-box">', unsafe_allow_html=True)
1820
+ col1, col2 = st.columns(2)
1821
+ with col1:
1822
+ st.metric("Points with pattern (1 neg, 1 pos, 1 zero)", f"{pattern_count}/{len(z_values)}")
1823
+ with col2:
1824
+ st.metric("Points with all zeros", f"{all_zeros_count}/{len(z_values)}")
1825
+ st.markdown('</div>', unsafe_allow_html=True)
1826
+
1827
+ # Detailed pattern analysis plot
1828
+ pattern_fig = go.Figure()
1829
+
1830
+ # Create colors for root types
1831
+ colors_at_z = []
1832
+ patterns_at_z = []
1833
+
1834
+ for i in range(len(z_values)):
1835
+ # Count roots at this z value
1836
+ zeros = 0
1837
+ positives = 0
1838
+ negatives = 0
1839
+
1840
+ for r in [real_values1[i], real_values2[i], real_values3[i]]:
1841
+ if abs(r) < 1e-6:
1842
+ zeros += 1
1843
+ elif r > 0:
1844
+ positives += 1
1845
+ else:
1846
+ negatives += 1
1847
+
1848
+ # Determine pattern color
1849
+ if zeros == 3:
1850
+ colors_at_z.append('#4CAF50') # Green for all zeros
1851
+ patterns_at_z.append('All zeros')
1852
+ elif zeros == 1 and positives == 1 and negatives == 1:
1853
+ colors_at_z.append('#2196F3') # Blue for desired pattern
1854
+ patterns_at_z.append('1 neg, 1 pos, 1 zero')
1855
+ else:
1856
+ colors_at_z.append('#F44336') # Red for other patterns
1857
+ patterns_at_z.append(f'{negatives} neg, {positives} pos, {zeros} zero')
1858
+
1859
+ # Plot root pattern indicator
1860
+ pattern_fig.add_trace(go.Scatter(
1861
+ x=z_values,
1862
+ y=[1] * len(z_values), # Just a constant value for visualization
1863
+ mode='markers',
1864
+ marker=dict(
1865
+ size=10,
1866
+ color=colors_at_z,
1867
+ symbol='circle'
1868
+ ),
1869
+ hovertext=patterns_at_z,
1870
+ hoverinfo='text+x',
1871
+ name='Root Pattern'
1872
+ ))
1873
+
1874
+ # Configure layout
1875
+ pattern_fig.update_layout(
1876
+ title={
1877
+ 'text': 'Root Pattern Analysis',
1878
+ 'font': {'size': 24, 'color': '#0e1117'},
1879
+ 'y': 0.95,
1880
+ 'x': 0.5,
1881
+ 'xanchor': 'center',
1882
+ 'yanchor': 'top'
1883
+ },
1884
+ xaxis={
1885
+ 'title': {'text': 'z (logarithmic scale)', 'font': {'size': 18, 'color': '#424242'}},
1886
+ 'tickfont': {'size': 14},
1887
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
1888
+ 'showgrid': True,
1889
+ 'type': 'log'
1890
+ },
1891
+ yaxis={
1892
+ 'showticklabels': False,
1893
+ 'showgrid': False,
1894
+ 'zeroline': False,
1895
+ },
1896
+ plot_bgcolor='rgba(250, 250, 250, 0.8)',
1897
+ paper_bgcolor='rgba(255, 255, 255, 0.8)',
1898
+ height=300,
1899
+ margin={'l': 40, 'r': 40, 't': 100, 'b': 40},
1900
+ showlegend=False
1901
+ )
1902
+
1903
+ # Add legend as annotations
1904
+ pattern_fig.add_annotation(
1905
+ x=0.01, y=0.95,
1906
+ xref="paper", yref="paper",
1907
+ text="Legend:",
1908
+ showarrow=False,
1909
+ font=dict(size=14)
1910
+ )
1911
+ pattern_fig.add_annotation(
1912
+ x=0.07, y=0.85,
1913
+ xref="paper", yref="paper",
1914
+ text="● Ideal pattern (1 neg, 1 pos, 1 zero)",
1915
+ showarrow=False,
1916
+ font=dict(size=12, color="#2196F3")
1917
+ )
1918
+ pattern_fig.add_annotation(
1919
+ x=0.07, y=0.75,
1920
+ xref="paper", yref="paper",
1921
+ text="● All zeros",
1922
+ showarrow=False,
1923
+ font=dict(size=12, color="#4CAF50")
1924
+ )
1925
+ pattern_fig.add_annotation(
1926
+ x=0.07, y=0.65,
1927
+ xref="paper", yref="paper",
1928
+ text="● Other patterns",
1929
+ showarrow=False,
1930
+ font=dict(size=12, color="#F44336")
1931
+ )
1932
+
1933
+ # Display the pattern figure
1934
+ st.plotly_chart(pattern_fig, use_container_width=True)
1935
+
1936
+ # Root pattern explanation
1937
+ st.markdown('<div class="explanation-box">', unsafe_allow_html=True)
1938
+ st.markdown("""
1939
+ ### Root Pattern Analysis
1940
+
1941
+ The cubic equation in this analysis should exhibit roots with the following pattern:
1942
+
1943
+ - One root with negative real part
1944
+ - One root with positive real part
1945
+ - One root with zero real part
1946
+
1947
+ Or in special cases, all three roots may be zero. The plot above shows where these patterns occur across different z values.
1948
+
1949
+ The updated C++ code has been engineered to ensure this pattern is maintained, which is important for stability analysis.
1950
+ When roots have imaginary parts, they occur in conjugate pairs, which explains why you may see matching Im(s) values in the
1951
+ Imaginary Parts tab.
1952
+ """)
1953
+ st.markdown('</div>', unsafe_allow_html=True)
1954
+
1955
  # Clear progress container
1956
  progress_container.empty()
1957
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1958
  except json.JSONDecodeError as e:
1959
  st.error(f"Error parsing JSON results: {str(e)}")
1960
  if os.path.exists(data_file):
 
1986
  real_values2 = np.array(data.get('real_values2', [0] * len(z_values)))
1987
  real_values3 = np.array(data.get('real_values3', [0] * len(z_values)))
1988
 
1989
+ # Create tabs for previous results
1990
+ prev_im_tab, prev_real_tab = st.tabs(["Previous Imaginary Parts", "Previous Real Parts"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1991
 
1992
+ # Tab for imaginary parts
1993
+ with prev_im_tab:
1994
+ # Show previous results with Imaginary parts
1995
+ fig = go.Figure()
1996
+
1997
+ # Add traces for each root's imaginary part
1998
+ fig.add_trace(go.Scatter(
1999
+ x=z_values,
2000
+ y=ims_values1,
2001
+ mode='lines',
2002
+ name='Im(s₁)',
2003
+ line=dict(color=color_max, width=3),
2004
+ hovertemplate='z: %{x:.3f}<br>Im(s₁): %{y:.6f}<extra>Root 1</extra>'
2005
+ ))
2006
+
2007
+ fig.add_trace(go.Scatter(
2008
+ x=z_values,
2009
+ y=ims_values2,
2010
+ mode='lines',
2011
+ name='Im(s₂)',
2012
+ line=dict(color=color_min, width=3),
2013
+ hovertemplate='z: %{x:.3f}<br>Im(s₂): %{y:.6f}<extra>Root 2</extra>'
2014
+ ))
2015
+
2016
+ fig.add_trace(go.Scatter(
2017
+ x=z_values,
2018
+ y=ims_values3,
2019
+ mode='lines',
2020
+ name='Im(s₃)',
2021
+ line=dict(color=color_theory_max, width=3),
2022
+ hovertemplate='z: %{x:.3f}<br>Im(s₃): %{y:.6f}<extra>Root 3</extra>'
2023
+ ))
2024
+
2025
+ # Configure layout for better appearance
2026
+ fig.update_layout(
2027
+ title={
2028
+ 'text': 'Im(s) vs z Analysis (Previous Result)',
2029
+ 'font': {'size': 24, 'color': '#0e1117'},
2030
+ 'y': 0.95,
2031
+ 'x': 0.5,
2032
+ 'xanchor': 'center',
2033
+ 'yanchor': 'top'
2034
+ },
2035
+ xaxis={
2036
+ 'title': {'text': 'z (logarithmic scale)', 'font': {'size': 18, 'color': '#424242'}},
2037
+ 'tickfont': {'size': 14},
2038
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
2039
+ 'showgrid': True,
2040
+ 'type': 'log' # Use logarithmic scale for better visualization
2041
+ },
2042
+ yaxis={
2043
+ 'title': {'text': 'Im(s)', 'font': {'size': 18, 'color': '#424242'}},
2044
+ 'tickfont': {'size': 14},
2045
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
2046
+ 'showgrid': True
2047
+ },
2048
+ plot_bgcolor='rgba(250, 250, 250, 0.8)',
2049
+ paper_bgcolor='rgba(255, 255, 255, 0.8)',
2050
+ hovermode='closest',
2051
+ legend={
2052
+ 'font': {'size': 14},
2053
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
2054
+ 'bordercolor': 'rgba(200, 200, 200, 0.5)',
2055
+ 'borderwidth': 1
2056
+ },
2057
+ margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
2058
+ height=500
2059
+ )
2060
+
2061
+ # Display the interactive plot in Streamlit
2062
+ st.plotly_chart(fig, use_container_width=True)
2063
 
2064
+ # Tab for real parts
2065
+ with prev_real_tab:
2066
+ # Create an interactive plot for real parts
2067
+ real_fig = go.Figure()
2068
+
2069
+ # Add traces for each root's real part
2070
+ real_fig.add_trace(go.Scatter(
2071
+ x=z_values,
2072
+ y=real_values1,
2073
+ mode='lines',
2074
+ name='Re(s₁)',
2075
+ line=dict(color=color_max, width=3),
2076
+ hovertemplate='z: %{x:.3f}<br>Re(s₁): %{y:.6f}<extra>Root 1</extra>'
2077
+ ))
2078
+
2079
+ real_fig.add_trace(go.Scatter(
2080
+ x=z_values,
2081
+ y=real_values2,
2082
+ mode='lines',
2083
+ name='Re(s₂)',
2084
+ line=dict(color=color_min, width=3),
2085
+ hovertemplate='z: %{x:.3f}<br>Re(s₂): %{y:.6f}<extra>Root 2</extra>'
2086
+ ))
2087
+
2088
+ real_fig.add_trace(go.Scatter(
2089
+ x=z_values,
2090
+ y=real_values3,
2091
+ mode='lines',
2092
+ name='Re(s₃)',
2093
+ line=dict(color=color_theory_max, width=3),
2094
+ hovertemplate='z: %{x:.3f}<br>Re(s₃): %{y:.6f}<extra>Root 3</extra>'
2095
+ ))
2096
+
2097
+ # Add zero line for reference
2098
+ real_fig.add_shape(
2099
+ type="line",
2100
+ x0=min(z_values),
2101
+ y0=0,
2102
+ x1=max(z_values),
2103
+ y1=0,
2104
+ line=dict(
2105
+ color="black",
2106
+ width=1,
2107
+ dash="dash",
2108
+ )
2109
+ )
2110
+
2111
+ # Configure layout for better appearance
2112
+ real_fig.update_layout(
2113
+ title={
2114
+ 'text': 'Re(s) vs z Analysis (Previous Result)',
2115
+ 'font': {'size': 24, 'color': '#0e1117'},
2116
+ 'y': 0.95,
2117
+ 'x': 0.5,
2118
+ 'xanchor': 'center',
2119
+ 'yanchor': 'top'
2120
+ },
2121
+ xaxis={
2122
+ 'title': {'text': 'z (logarithmic scale)', 'font': {'size': 18, 'color': '#424242'}},
2123
+ 'tickfont': {'size': 14},
2124
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
2125
+ 'showgrid': True,
2126
+ 'type': 'log'
2127
+ },
2128
+ yaxis={
2129
+ 'title': {'text': 'Re(s)', 'font': {'size': 18, 'color': '#424242'}},
2130
+ 'tickfont': {'size': 14},
2131
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
2132
+ 'showgrid': True
2133
+ },
2134
+ plot_bgcolor='rgba(250, 250, 250, 0.8)',
2135
+ paper_bgcolor='rgba(255, 255, 255, 0.8)',
2136
+ hovermode='closest',
2137
+ legend={
2138
+ 'font': {'size': 14},
2139
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
2140
+ 'bordercolor': 'rgba(200, 200, 200, 0.5)',
2141
+ 'borderwidth': 1
2142
+ },
2143
+ margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
2144
+ height=500
2145
+ )
2146
+
2147
+ # Display the interactive plot in Streamlit
2148
+ st.plotly_chart(real_fig, use_container_width=True)
2149
 
 
 
2150
  st.info("This is the previous analysis result. Adjust parameters and click 'Generate Analysis' to create a new visualization.")
2151
 
2152
  except Exception as e:
 
2159
 
2160
  # Add footer with instructions
2161
  st.markdown("""
2162
+ <div class="footer">
2163
+ <h3>About the Matrix Analysis Dashboard</h3>
2164
+ <p>This dashboard performs two types of analyses:</p>
2165
+ <ol>
2166
+ <li><strong>Eigenvalue Analysis:</strong> Computes eigenvalues of random matrices with specific structures, showing empirical and theoretical results.</li>
2167
+ <li><strong>Im(s) vs z Analysis:</strong> Analyzes the cubic equation that arises in the theoretical analysis, showing the imaginary and real parts of the roots.</li>
2168
+ </ol>
2169
+ <p>Developed using Streamlit and C++ for high-performance numerical calculations.</p>
 
 
 
 
 
 
2170
  </div>
2171
  """, unsafe_allow_html=True)